-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Clang] Treat constexpr-unknown value as invalid in EvaluateAsInitializer
#128409
Conversation
@@ -3628,8 +3628,6 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, | |||
if (AllowConstexprUnknown) { | |||
if (!Result) | |||
Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base); | |||
else | |||
Result->setConstexprUnknown(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deleting this makes a lot of sense; I was really confused trying to parse what this line in the original patch was supposed to do.
const auto *NewVD = Base.dyn_cast<const ValueDecl *>(); | ||
if (!NewVD) | ||
NewVD = VD; | ||
Info.FFDiag(getExprLoc(), diag::note_constexpr_var_init_non_constant, 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally, we should emit a note here:
llvm-project/clang/lib/AST/ExprConstant.cpp
Lines 3581 to 3584 in a955426
if (AllowConstexprUnknown) { | |
Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base); | |
return true; | |
} |
But I don't know how to add a "lazy" note (i.e., these notes will be shown if an error occurs).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what you mean by a "lazy" note; the whole point of constexpr-unknown is that it's not an error at the point it's constructed.
If you need more information to generate a good diagnostic, you could pass that information to createConstexprUnknownAPValues, and store it in the APValue itself, I guess. Computing the whole diagnostic in advance seems like it would be too expensive, though.
I don't think it's a big deal if we generate slightly different diagnostics depending on whether we're in C++23 mode, as long as we generate some explanation for what's happening.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you need more information to generate a good diagnostic, you could pass that information to createConstexprUnknownAPValues, and store it in the APValue itself, I guess. Computing the whole diagnostic in advance seems like it would be too expensive, though.
That is what the current implementation does.
evaluateValue
EvaluateAsInitializer
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clang Author: Yingwei Zheng (dtcxzyw) ChangesIt is an alternative to #127525. Full diff: https://github.com/llvm/llvm-project/pull/128409.diff 3 Files Affected:
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 6ccb6e23f8d2f..42801dc4e18fa 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -3628,8 +3628,6 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
if (AllowConstexprUnknown) {
if (!Result)
Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base);
- else
- Result->setConstexprUnknown();
}
return true;
}
@@ -17000,6 +16998,18 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
if (!Info.discardCleanups())
llvm_unreachable("Unhandled cleanup; missing full expression marker?");
+
+ if (Value.allowConstexprUnknown()) {
+ assert(Value.isLValue() && "Expected an lvalue");
+ auto Base = Value.getLValueBase();
+ const auto *NewVD = Base.dyn_cast<const ValueDecl *>();
+ if (!NewVD)
+ NewVD = VD;
+ Info.FFDiag(getExprLoc(), diag::note_constexpr_var_init_non_constant, 1)
+ << NewVD;
+ NoteLValueLocation(Info, Base);
+ return false;
+ }
}
return CheckConstantExpression(Info, DeclLoc, DeclTy, Value,
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index ee5874b26f534..0295f703b9061 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -1883,8 +1883,12 @@ llvm::Constant *ConstantEmitter::tryEmitPrivateForVarInit(const VarDecl &D) {
// Try to emit the initializer. Note that this can allow some things that
// are not allowed by tryEmitPrivateForMemory alone.
- if (APValue *value = D.evaluateValue())
+ // Bail out on constexpr-unknown values since they are invalid in CodeGen.
+ if (APValue *value = D.evaluateValue()) {
+ assert(!value->allowConstexprUnknown() &&
+ "Constexpr unknown values are not allowed in CodeGen");
return tryEmitPrivateForMemory(*value, destType);
+ }
return nullptr;
}
diff --git a/clang/test/CodeGenCXX/cxx23-p2280r4.cpp b/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
new file mode 100644
index 0000000000000..d5409be451df0
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx23-p2280r4.cpp
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++23 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++17 %s -emit-llvm -o - | FileCheck %s
+
+extern int& s;
+
+// CHECK: @_Z4testv()
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[I:%.*]] = alloca ptr, align {{.*}}
+// CHECK-NEXT: [[X:%.*]] = load ptr, ptr @s, align {{.*}}
+// CHECK-NEXT: store ptr [[X]], ptr [[I]], align {{.*}}
+int& test() {
+ auto &i = s;
+ return i;
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should the other Expr::Evaluate* entry points have the same bailout? Do you want to do that in this patch, or a followup?
const auto *NewVD = Base.dyn_cast<const ValueDecl *>(); | ||
if (!NewVD) | ||
NewVD = VD; | ||
Info.FFDiag(getExprLoc(), diag::note_constexpr_var_init_non_constant, 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what you mean by a "lazy" note; the whole point of constexpr-unknown is that it's not an error at the point it's constructed.
If you need more information to generate a good diagnostic, you could pass that information to createConstexprUnknownAPValues, and store it in the APValue itself, I guess. Computing the whole diagnostic in advance seems like it would be too expensive, though.
I don't think it's a big deal if we generate slightly different diagnostics depending on whether we're in C++23 mode, as long as we generate some explanation for what's happening.
Sorry I don't have enough bandwidth to work on other potential constexpr-unknown-related issues. I just want to close #127475 as soon as possible. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get that we are allowing constexpr unknown values into codegen and that is a mistake but I don't totally follow the fix. Can you go into more details?
If I am reading the code correctly there should be some constexpr cases that generate a diagnostic, can we verify that with a test?
Here's a testcase that's should generate a diagnostic, but doesn't without this patch:
Some related testcases are a little weird... consider the following:
There's a gap between checking for constant expressions, and codegen, due to the following diagnostic; it triggers in constexpr, but allows evaluating for the value because a CCEDiag doesn't stop the evaluation: llvm-project/clang/lib/AST/ExprConstant.cpp Line 3607 in 52c8159
|
It has been tested by the following case:
Without diagnostic-related code in this patch, we will lose some notes on |
So it looks like 20.1.0 is planned to release tomorrow as there are "no critical issues"... https://discourse.llvm.org/t/20-1-0-release-update-releasing-1-week-early-tomorrow/84932 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am happy to see a fix here but I would still like some more context on whether we think this still leave some cases uncaught or not.
/cherry-pick 27757fb |
/pull-request #129836 |
Opened #129844 with a case that still fails. Other entry-points to constant evaluation need similar treatment to EvaluateAsInitializer. |
And the check for allowConstexprUnknown() isn't catching all the relevant cases; opened #129845. |
…consistently. Perform the check for constexpr-unknown values in the same place we perform checks for other values which don't count as constant expressions. While I'm here, also fix a rejects-valid with a reference that doesn't have an initializer. This diagnostic was also covering up some of the bugs here. The existing behavior with -fexperimental-new-constant-interpreter seems to be correct, but the diagnostics are slightly different; it would be helpful if someone could check on that as a followup. Followup to llvm#128409. Fixes llvm#129844. Fixes llvm#129845.
…consistently (#129952) Perform the check for constexpr-unknown values in the same place we perform checks for other values which don't count as constant expressions. While I'm here, also fix a rejects-valid with a reference that doesn't have an initializer. This diagnostic was also covering up some of the bugs here. The existing behavior with -fexperimental-new-constant-interpreter seems to be correct, but the diagnostics are slightly different; it would be helpful if someone could check on that as a followup. Followup to #128409. Fixes #129844. Fixes #129845.
…lizer` (llvm#128409) It is an alternative to llvm#127525. Close llvm#127475.
…consistently (llvm#129952) Perform the check for constexpr-unknown values in the same place we perform checks for other values which don't count as constant expressions. While I'm here, also fix a rejects-valid with a reference that doesn't have an initializer. This diagnostic was also covering up some of the bugs here. The existing behavior with -fexperimental-new-constant-interpreter seems to be correct, but the diagnostics are slightly different; it would be helpful if someone could check on that as a followup. Followup to llvm#128409. Fixes llvm#129844. Fixes llvm#129845.
…lizer` (llvm#128409) It is an alternative to llvm#127525. Close llvm#127475.
…consistently (llvm#129952) Perform the check for constexpr-unknown values in the same place we perform checks for other values which don't count as constant expressions. While I'm here, also fix a rejects-valid with a reference that doesn't have an initializer. This diagnostic was also covering up some of the bugs here. The existing behavior with -fexperimental-new-constant-interpreter seems to be correct, but the diagnostics are slightly different; it would be helpful if someone could check on that as a followup. Followup to llvm#128409. Fixes llvm#129844. Fixes llvm#129845.
…lizer` (llvm#128409) It is an alternative to llvm#127525. Close llvm#127475.
It is an alternative to #127525.
Close #127475.