Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -6759,6 +6759,7 @@ class Sema final : public SemaBase {
EK_Decltype,
EK_TemplateArgument,
EK_AttrArgument,
EK_VariableInit,
EK_Other
} ExprContext;

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2710,6 +2710,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
break;
}
case InitKind::Uninitialized: {
InitializerScopeRAII InitScope(*this, D, ThisDecl);
Actions.ActOnUninitializedDecl(ThisDecl);
break;
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaCoroutine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,8 @@ static bool checkSuspensionContext(Sema &S, SourceLocation Loc,
const auto ExprContext = S.currentEvaluationContext().ExprContext;
const bool BadContext =
S.isUnevaluatedContext() ||
ExprContext != Sema::ExpressionEvaluationContextRecord::EK_Other;
(ExprContext != Sema::ExpressionEvaluationContextRecord::EK_Other &&
ExprContext != Sema::ExpressionEvaluationContextRecord::EK_VariableInit);
if (BadContext) {
S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword;
return false;
Expand Down
26 changes: 2 additions & 24 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18937,7 +18937,8 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) {
EnterDeclaratorContext(S, D->getDeclContext());

PushExpressionEvaluationContext(
ExpressionEvaluationContext::PotentiallyEvaluated, D);
ExpressionEvaluationContext::PotentiallyEvaluated, D,
ExpressionEvaluationContextRecord::EK_VariableInit);
}

void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
Expand All @@ -18946,29 +18947,6 @@ void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) {
if (S && D->isOutOfLine())
ExitDeclaratorContext(S);

if (getLangOpts().CPlusPlus23) {
// An expression or conversion is 'manifestly constant-evaluated' if it is:
// [...]
// - the initializer of a variable that is usable in constant expressions or
// has constant initialization.
if (auto *VD = dyn_cast<VarDecl>(D);
VD && (VD->isUsableInConstantExpressions(Context) ||
VD->hasConstantInitialization())) {
// An expression or conversion is in an 'immediate function context' if it
// is potentially evaluated and either:
// [...]
// - it is a subexpression of a manifestly constant-evaluated expression
// or conversion.
ExprEvalContexts.back().InImmediateFunctionContext = true;
}
}

// Unless the initializer is in an immediate function context (as determined
// above), this will evaluate all contained immediate function calls as
// constant expressions. If the initializer IS an immediate function context,
// the initializer has been determined to be a constant expression, and all
// such evaluations will be elided (i.e., as if we "knew the whole time" that
// it was a constant expression).
PopExpressionEvaluationContext();
}

Expand Down
19 changes: 19 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17935,6 +17935,25 @@ HandleImmediateInvocations(Sema &SemaRef,
Rec.isImmediateFunctionContext() || SemaRef.RebuildingImmediateInvocation)
return;

// An expression or conversion is 'manifestly constant-evaluated' if it is:
// [...]
// - the initializer of a variable that is usable in constant expressions or
// has constant initialization.
if (SemaRef.getLangOpts().CPlusPlus23 &&
Rec.ExprContext ==
Sema::ExpressionEvaluationContextRecord::EK_VariableInit) {
auto *VD = cast<VarDecl>(Rec.ManglingContextDecl);
if (VD->isUsableInConstantExpressions(SemaRef.Context) ||
VD->hasConstantInitialization()) {
// An expression or conversion is in an 'immediate function context' if it
// is potentially evaluated and either:
// [...]
// - it is a subexpression of a manifestly constant-evaluated expression
// or conversion.
return;
}
}

/// When we have more than 1 ImmediateInvocationCandidates or previously
/// failed immediate invocations, we need to check for nested
/// ImmediateInvocationCandidates in order to avoid duplicate diagnostics.
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6103,7 +6103,8 @@ void Sema::InstantiateVariableInitializer(
ContextRAII SwitchContext(*this, Var->getDeclContext());

EnterExpressionEvaluationContext Evaluated(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var,
ExpressionEvaluationContextRecord::EK_VariableInit);
currentEvaluationContext().InLifetimeExtendingContext =
parentEvaluationContext().InLifetimeExtendingContext;
currentEvaluationContext().RebuildDefaultArgOrDefaultInit =
Expand Down
34 changes: 34 additions & 0 deletions clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,3 +576,37 @@ int f() {
//expected-note@-2 {{read of non-const variable 'a' is not allowed in a constant expression}}
}
}

#if __cplusplus >= 202302L
namespace GH135281 {
struct B {
const void* p;
consteval B() : p{this} {}
};
B b;
B b2{};
B &&b3{};
void f() {
static B b4;
B b5; // expected-error {{call to consteval function 'GH135281::B::B' is not a constant expression}} \
// expected-note {{pointer to temporary is not a constant expression}} \
// expected-note {{temporary created here}}
}
template<typename T> T temp_var_uninit;
template<typename T> T temp_var_brace_init{};
B* b6 = &temp_var_uninit<B>;
B* b7 = &temp_var_brace_init<B>;
B* b8 = &temp_var_brace_init<B&&>;
template<typename T> void f2() {
static T b9;
T b10; // expected-error {{call to consteval function 'GH135281::B::B' is not a constant expression}} \
// expected-note {{pointer to temporary is not a constant expression}} \
// expected-note {{temporary created here}}
static B b11;
B b12; // expected-error 2 {{call to consteval function 'GH135281::B::B' is not a constant expression}} \
// expected-note 2 {{pointer to temporary is not a constant expression}} \
// expected-note 2 {{temporary created here}}
}
void (*ff)() = f2<B>; // expected-note {{instantiation of function template specialization}}
}
#endif
Loading