Skip to content

Commit 75ae080

Browse files
committed
[clang] Consistently handle consteval constructors for variables.
443377a handled simple variables definitions, but it didn't handle uninitialized variables with a constexpr constructor, and it didn't handle template instantiation. Fixes #135281 .
1 parent aa3c5d0 commit 75ae080

File tree

8 files changed

+67
-20
lines changed

8 files changed

+67
-20
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6759,6 +6759,7 @@ class Sema final : public SemaBase {
67596759
EK_Decltype,
67606760
EK_TemplateArgument,
67616761
EK_AttrArgument,
6762+
EK_VariableInit,
67626763
EK_Other
67636764
} ExprContext;
67646765

clang/lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2710,6 +2710,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
27102710
break;
27112711
}
27122712
case InitKind::Uninitialized: {
2713+
InitializerScopeRAII InitScope(*this, D, ThisDecl);
27132714
Actions.ActOnUninitializedDecl(ThisDecl);
27142715
break;
27152716
}

clang/lib/Sema/SemaCoroutine.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,8 @@ static bool checkSuspensionContext(Sema &S, SourceLocation Loc,
783783
const auto ExprContext = S.currentEvaluationContext().ExprContext;
784784
const bool BadContext =
785785
S.isUnevaluatedContext() ||
786-
ExprContext != Sema::ExpressionEvaluationContextRecord::EK_Other;
786+
(ExprContext != Sema::ExpressionEvaluationContextRecord::EK_Other &&
787+
ExprContext != Sema::ExpressionEvaluationContextRecord::EK_VariableInit);
787788
if (BadContext) {
788789
S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
789790
return false;

clang/lib/Sema/SemaDecl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14400,6 +14400,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
1440014400
Var->getType().getAddressSpace() == LangAS::hlsl_input)
1440114401
return;
1440214402

14403+
if (getLangOpts().CPlusPlus)
14404+
ActOnCXXEnterDeclInitializer(nullptr, Var);
14405+
1440314406
// C++03 [dcl.init]p9:
1440414407
// If no initializer is specified for an object, and the
1440514408
// object is of (possibly cv-qualified) non-POD class type (or
@@ -14435,6 +14438,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
1443514438
}
1443614439

1443714440
CheckCompleteVariableDeclaration(Var);
14441+
14442+
if (getLangOpts().CPlusPlus)
14443+
ActOnCXXExitDeclInitializer(nullptr, Var);
1443814444
}
1443914445
}
1444014446

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18937,7 +18937,8 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
1893718937
EnterDeclaratorContext(S, D->getDeclContext());
1893818938

1893918939
PushExpressionEvaluationContext(
18940-
ExpressionEvaluationContext::PotentiallyEvaluated, D);
18940+
ExpressionEvaluationContext::PotentiallyEvaluated, D,
18941+
ExpressionEvaluationContextRecord::EK_VariableInit);
1894118942
}
1894218943

1894318944
void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
@@ -18946,23 +18947,6 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
1894618947
if (S && D->isOutOfLine())
1894718948
ExitDeclaratorContext(S);
1894818949

18949-
if (getLangOpts().CPlusPlus23) {
18950-
// An expression or conversion is 'manifestly constant-evaluated' if it is:
18951-
// [...]
18952-
// - the initializer of a variable that is usable in constant expressions or
18953-
// has constant initialization.
18954-
if (auto *VD = dyn_cast<VarDecl>(D);
18955-
VD && (VD->isUsableInConstantExpressions(Context) ||
18956-
VD->hasConstantInitialization())) {
18957-
// An expression or conversion is in an 'immediate function context' if it
18958-
// is potentially evaluated and either:
18959-
// [...]
18960-
// - it is a subexpression of a manifestly constant-evaluated expression
18961-
// or conversion.
18962-
ExprEvalContexts.back().InImmediateFunctionContext = true;
18963-
}
18964-
}
18965-
1896618950
// Unless the initializer is in an immediate function context (as determined
1896718951
// above), this will evaluate all contained immediate function calls as
1896818952
// constant expressions. If the initializer IS an immediate function context,

clang/lib/Sema/SemaExpr.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17935,6 +17935,25 @@ HandleImmediateInvocations(Sema &SemaRef,
1793517935
Rec.isImmediateFunctionContext() || SemaRef.RebuildingImmediateInvocation)
1793617936
return;
1793717937

17938+
// An expression or conversion is 'manifestly constant-evaluated' if it is:
17939+
// [...]
17940+
// - the initializer of a variable that is usable in constant expressions or
17941+
// has constant initialization.
17942+
if (SemaRef.getLangOpts().CPlusPlus23 &&
17943+
Rec.ExprContext ==
17944+
Sema::ExpressionEvaluationContextRecord::EK_VariableInit) {
17945+
auto *VD = cast<VarDecl>(Rec.ManglingContextDecl);
17946+
if (VD->isUsableInConstantExpressions(SemaRef.Context) ||
17947+
VD->hasConstantInitialization()) {
17948+
// An expression or conversion is in an 'immediate function context' if it
17949+
// is potentially evaluated and either:
17950+
// [...]
17951+
// - it is a subexpression of a manifestly constant-evaluated expression
17952+
// or conversion.
17953+
return;
17954+
}
17955+
}
17956+
1793817957
/// When we have more than 1 ImmediateInvocationCandidates or previously
1793917958
/// failed immediate invocations, we need to check for nested
1794017959
/// ImmediateInvocationCandidates in order to avoid duplicate diagnostics.

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6103,7 +6103,8 @@ void Sema::InstantiateVariableInitializer(
61036103
ContextRAII SwitchContext(*this, Var->getDeclContext());
61046104

61056105
EnterExpressionEvaluationContext Evaluated(
6106-
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
6106+
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var,
6107+
ExpressionEvaluationContextRecord::EK_VariableInit);
61076108
currentEvaluationContext().InLifetimeExtendingContext =
61086109
parentEvaluationContext().InLifetimeExtendingContext;
61096110
currentEvaluationContext().RebuildDefaultArgOrDefaultInit =

clang/test/SemaCXX/cxx2b-consteval-propagate.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,3 +576,37 @@ int f() {
576576
//expected-note@-2 {{read of non-const variable 'a' is not allowed in a constant expression}}
577577
}
578578
}
579+
580+
#if __cplusplus >= 202302L
581+
namespace GH135281 {
582+
struct B {
583+
const void* p;
584+
consteval B() : p{this} {}
585+
};
586+
B b;
587+
B b2{};
588+
B &&b3{};
589+
void f() {
590+
static B b4;
591+
B b5; // expected-error {{call to consteval function 'GH135281::B::B' is not a constant expression}} \
592+
// expected-note {{pointer to temporary is not a constant expression}} \
593+
// expected-note {{temporary created here}}
594+
}
595+
template<typename T> T temp_var_uninit;
596+
template<typename T> T temp_var_brace_init{};
597+
B* b6 = &temp_var_uninit<B>;
598+
B* b7 = &temp_var_brace_init<B>;
599+
B* b8 = &temp_var_brace_init<B&&>;
600+
template<typename T> void f2() {
601+
static T b9;
602+
T b10; // expected-error {{call to consteval function 'GH135281::B::B' is not a constant expression}} \
603+
// expected-note {{pointer to temporary is not a constant expression}} \
604+
// expected-note {{temporary created here}}
605+
static B b11;
606+
B b12; // expected-error 2 {{call to consteval function 'GH135281::B::B' is not a constant expression}} \
607+
// expected-note 2 {{pointer to temporary is not a constant expression}} \
608+
// expected-note 2 {{temporary created here}}
609+
}
610+
void (*ff)() = f2<B>; // expected-note {{instantiation of function template specialization}}
611+
}
612+
#endif

0 commit comments

Comments
 (0)