-
Notifications
You must be signed in to change notification settings - Fork 12.4k
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] Handle consteval expression in array bounds expressions #66222
Conversation
@llvm/pr-subscribers-clang ChangesThe bounds of a c++ array is a _constant-expression_. And in C++ it is also a constant expression.But we also support VLAs, ie arrays with non-constant bounds. We need to take care to handle the case of a consteval function (which are specified to be only immediately called in non-constant contexts) that appear in arrays bounds. This introduces Sema had both The change in Fixes #65520Patch is 20.71 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/66222.diff 11 Files Affected:
<pre> +- Fix a crash when calling a consteval function in an expression used as
Bug Fixes to AST Handling
bool isImmediateFunctionContext() const {
bool isCheckingDefaultArgumentOrInitializer() const {
+ExprResult Parser::ParseArrayBoundExpression() {
ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
bool Sema::CheckARMCoprocessorImmediate(const TargetInfo &TI,
@@ -9666,7 +9666,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
@@ -9971,9 +9971,11 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
@@ -10001,7 +10003,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
@@ -13928,7 +13930,7 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, IntRange OtherValueRange = GetExprRange(
@@ -15041,7 +15044,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
@@ -15064,7 +15067,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
@@ -15090,8 +15093,9 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
@@ -16032,7 +16036,8 @@ class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> {
@@ -17159,7 +17164,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) {
|
a95e4a8
to
d7f281e
Compare
@hazohelet Does this collide or intersect with the work wrt. (un)evaluated contexts in https://reviews.llvm.org/D155064 ? |
clang/lib/Sema/SemaChecking.cpp
Outdated
@@ -13928,7 +13930,7 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, | |||
return false; | |||
|
|||
IntRange OtherValueRange = GetExprRange( | |||
S.Context, Other, S.isConstantEvaluated(), /*Approximate*/ false); | |||
S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate*/ false); |
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.
S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate*/ false); | |
S.Context, Other, S.isConstantEvaluatedContext(), /*Approximate=*/ false); |
clang/include/clang/Sema/Sema.h
Outdated
|
||
/// Used to change context to isConstantEvaluated without pushing a heavy | ||
/// ExpressionEvaluationContextRecord object. | ||
bool isConstantEvaluatedOverride; |
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.
Is there no good default value?
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.
This is set in sema constructors, but i can move the initialization here (this is just code that i moved around). We are a bit inconsistent in general at using or not default member init.
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 the function is constexpr
do we treat it as a VLA?
If it can be constant evaluated, yes. (So anything with UB in it is promoted to a VLA, it's fabulous) |
a9c3d1a
to
727204e
Compare
I wasn't aware of VLA cases in that patch. @cor3ntin ExprResult Parser::ParseArrayBoundExpression() {
+ bool IsAlwaysConstantEvaluated = Actions.isAlwaysConstantEvaluatedContext();
EnterExpressionEvaluationContext ConstantEvaluated(
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
// If we parse the bound of a VLA... we parse a non-constant
// constant-expression!
- Actions.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true;
+ Actions.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = !IsAlwaysConstantEvaluated;
return ParseConstantExpressionInExprEvalContext(NotTypeCast);
} Also, does this change suggest that we let some diagnostic mechanisms consider VLA cases? (e.g. |
Where do you think it matters? I can't this of cases where ConstantEvaluated context are nested in one another without some intertwined potentially evaluated context
Yes. We probably should fix that (i think it's a separate patch) |
I was mostly thinking about cases where the array-bound expression appears inside immediate function context. |
Hum, maybe to do that we need to set ahead of time whether we support VLAs or not because if we don't then it's not tautological... But if we do that then whether we get tautological warnings depend on the value of
I'll add a test. immediate contexts are recursive, constant evaluated contexts are not, i don't think there is a case where you would get an additional evaluation context that is not for a full expression, and if you have a full expression you do expect the immediate invocation to be called anyway - eg, lambda case. |
It turns out I was misunderstanding the standard about the recursiveness of constant-evaluated-context. I found a flaw in my patch that comes from it (pushing constant-evaluated context upon lambda body if it happens in constant-evaluated context). Thanks! |
727204e
to
4b62211
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
4b62211
to
d8b2e70
Compare
clang/lib/Sema/TreeTransform.h
Outdated
@@ -5490,6 +5490,9 @@ TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB, | |||
EnterExpressionEvaluationContext Unevaluated( | |||
SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); | |||
|
|||
// VLA bounds are not truly constant. |
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.
This is not always a VLA right? So maybe saying If we have a VLA then it won't be a constant
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 think this generally makes a lot of sense, I have 1 nit (plus a bunch of the 'bool' comments without the = sign that @shafik suggested, but were closed without comment), otherwise LGTM.
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); | ||
// If we parse the bound of a VLA... we parse a non-constant | ||
// constant-expression! | ||
Actions.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true; |
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 think I'd rather this be an argument to the above constructor here.
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.
@erichkeane this constructor already has a bunch of defaulted boolean / pointer parameters, it would be a mess. We'd need to add a tag which seems overkill for 1 use
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.
In reality, I'd probably prefer something like;
auto Expr = ExpressionEvaluationContext::CreateForVLA
kind of thing (or perhaps a builder-pattern like below), but that is probably a sizable refactor for everything. I think I can hold my nose here and be OK for now.
ExprEvalContext Eva(ThingsEverythingNeeds).ForVLA()
91e7e15
to
2872661
Compare
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.
Still OK with this, but Shafik should do the final approval.
@shafik ping! |
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 after fixing nits.
The bounds of a c++ array is a _constant-expression_. And in C++ it is also a constant expression. But we also support VLAs, ie arrays with non-constant bounds. We need to take care to handle the case of a consteval function (which are specified to be only immediately called in non-constant contexts) that appear in arrays bounds. This introduces `Sema::isAlwayConstantEvaluatedContext`, and a flag in ExpressionEvaluationContextRecord, such that immediate functions in array bounds are always immediately invoked. Sema had both `isConstantEvaluatedContext` and `isConstantEvaluated`, so I took the opportunity to cleanup that. The change in `TimeProfilerTest.cpp` is an unfortunate manifestation of the problem that llvm#66203 seeks to address. Fixes llvm#65520
2872661
to
5dc044a
Compare
The bounds of a c++ array is a constant-expression. And in C++ it is also a constant expression.
But we also support VLAs, ie arrays with non-constant bounds.
We need to take care to handle the case of a consteval function (which are specified to be only immediately called in non-constant contexts) that appear in arrays bounds.
This introduces
Sema::isAlwayConstantEvaluatedContext
, and a flag in ExpressionEvaluationContextRecord, such that immediate functions in array bounds are always immediately invoked.Sema had both
isConstantEvaluatedContext
andisConstantEvaluated
, so I took the opportunity to cleanup that.The change in
TimeProfilerTest.cpp
is an unfortunate manifestation of the problem that #66203 seeks to address.Fixes #65520