cor3ntin updated this revision to Diff 540902.
cor3ntin added a comment.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.
Add more tests for aggregates and a codegen test
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D155175/new/
https://reviews.llvm.org/D155175
Files:
clang/include/clang/Sema/Sema.h
clang/lib/CodeGen/CGExpr.cpp
clang/lib/Sema/SemaDecl.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/lib/Sema/SemaExpr.cpp
clang/test/CodeGenCXX/cxx2c-consteval-consteval.cpp
clang/test/SemaCXX/cxx2a-consteval-default-params.cpp
clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
llvm/cmake/modules/HandleLLVMOptions.cmake
Index: llvm/cmake/modules/HandleLLVMOptions.cmake
===================================================================
--- llvm/cmake/modules/HandleLLVMOptions.cmake
+++ llvm/cmake/modules/HandleLLVMOptions.cmake
@@ -610,7 +610,7 @@
# crash if LLVM is built with GCC and LTO enabled (#57740). Until
# these bugs are fixed, we need to disable dead store eliminations
# based on object lifetime.
- add_flag_if_supported("-fno-lifetime-dse" CMAKE_CXX_FLAGS)
+ # add_flag_if_supported("-fno-lifetime-dse" CMAKE_CXX_FLAGS)
endif ( LLVM_COMPILER_IS_GCC_COMPATIBLE )
# Modules enablement for GCC-compatible compilers:
Index: clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
===================================================================
--- clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
+++ clang/test/SemaCXX/cxx2b-consteval-propagate.cpp
@@ -164,3 +164,164 @@
int i = g(x); // expected-error {{call to immediate function 'ConstevalConstructor::g<int>' is not a constant expression}} \
// expected-note {{read of non-const variable 'x' is not allowed in a constant expression}}
}
+
+
+
+namespace Aggregate {
+consteval int f(int); // expected-note {{declared here}}
+struct S {
+ int x = f(42); // expected-note {{undefined function 'f' cannot be used in a constant expression}}
+};
+
+constexpr S immediate(auto) {
+ return S{};
+}
+
+void test_runtime() {
+ (void)immediate(0); // expected-error {{call to immediate function 'Aggregate::immediate<int>' is not a constant expression}} \
+ // expected-note {{in call to 'immediate(0)'}}
+}
+consteval int f(int i) {
+ return i;
+}
+consteval void test() {
+ constexpr S s = immediate(0);
+ static_assert(s.x == 42);
+}
+}
+
+
+
+namespace GH63742 {
+void side_effect(); // expected-note {{declared here}}
+consteval int f(int x) {
+ if (!x) side_effect(); // expected-note {{non-constexpr function 'side_effect' cannot be used in a constant expression}}
+ return x;
+}
+struct SS {
+ int x = f(0); // expected-error {{call to consteval function 'GH63742::f' is not a constant expression}} \
+ // expected-note {{declared here}} \
+ // expected-note {{in call to 'f(0)'}}
+ SS();
+};
+SS::SS(){} // expected-note {{in the default initializer of 'x'}}
+
+consteval int f2(int x) {
+ if (!__builtin_is_constant_evaluated()) side_effect();
+ return x;
+}
+struct S2 {
+ int x = f2(0);
+ constexpr S2();
+};
+
+constexpr S2::S2(){}
+S2 s = {};
+
+struct S3 {
+ int x = f2(0);
+ S3();
+};
+S3::S3(){}
+
+}
+
+namespace Defaulted {
+consteval int f(int x);
+struct SS {
+ int x = f(0);
+ SS() = default;
+};
+}
+
+namespace DefaultedUse{
+consteval int f(int x); // expected-note {{declared here}}
+struct SS {
+ int x = f(0); // expected-note {{undefined function 'f' cannot be used in a constant expression}}
+ SS() = default;
+};
+
+void test() {
+ [[maybe_unused]] SS s; // expected-error {{call to immediate function 'DefaultedUse::SS::SS' is not a constant expression}} \
+ // expected-note {{in call to 'SS()'}}
+}
+}
+
+namespace UserDefinedConstructors {
+consteval int f(int x) {
+ return x;
+}
+extern int NonConst; // expected-note 2{{declared here}}
+
+struct ConstevalCtr {
+ int y;
+ int x = f(y);
+ consteval ConstevalCtr(int yy)
+ : y(f(yy)) {}
+};
+
+ConstevalCtr c1(1);
+ConstevalCtr c2(NonConst);
+// expected-error@-1 {{call to consteval function 'UserDefinedConstructors::ConstevalCtr::ConstevalCtr' is not a constant expression}} \
+// expected-note@-1 {{read of non-const variable 'NonConst' is not allowed in a constant expression}}
+
+struct ImmediateEscalating {
+ int y;
+ int x = f(y);
+ template<typename T>
+ constexpr ImmediateEscalating(T yy)
+ : y(f(yy)) {}
+};
+
+ImmediateEscalating c3(1);
+ImmediateEscalating c4(NonConst);
+// expected-error@-1 {{call to immediate function 'UserDefinedConstructors::ImmediateEscalating::ImmediateEscalating<int>' is not a constant expression}} \
+// expected-note@-1 {{read of non-const variable 'NonConst' is not allowed in a constant expression}}
+
+
+struct NonEscalating {
+ int y;
+ int x = f(this->y); // expected-error {{call to consteval function 'UserDefinedConstructors::f' is not a constant expression}} \
+ // expected-note {{declared here}} \
+ // expected-note {{use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function}}
+ constexpr NonEscalating(int yy) : y(yy) {} // expected-note {{in the default initializer of 'x'}}
+};
+NonEscalating s = {1};
+
+}
+
+namespace AggregateInit {
+
+consteval int f(int x) {
+ return x;
+}
+
+struct S {
+ int i;
+ int j = f(i);
+};
+
+constexpr S test(auto) {
+ return {};
+}
+
+S s = test(0);
+
+}
+
+namespace GlobalAggregateInit {
+
+consteval int f(int x) {
+ return x;
+}
+
+struct S {
+ int i;
+ int j = f(i); // expected-error {{call to consteval function 'GlobalAggregateInit::f' is not a constant expression}} \
+ // expected-note {{in the default initializer of 'j'}} \
+ // expected-note {{implicit use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function}} \
+ // expected-note {{declared here}}
+};
+
+S s(0);
+}
Index: clang/test/SemaCXX/cxx2a-consteval-default-params.cpp
===================================================================
--- clang/test/SemaCXX/cxx2a-consteval-default-params.cpp
+++ clang/test/SemaCXX/cxx2a-consteval-default-params.cpp
@@ -41,19 +41,21 @@
}();
};
-consteval int ub(int n) { // expected-note {{declared here}}
+consteval int ub(int n) {
return 0/n;
}
struct InitWithLambda {
- int b = [](int error = undefined()) { // expected-error {{cannot take address of consteval function 'undefined' outside of an immediate invocation}}
+ int b = [](int error = undefined()) { // expected-note {{undefined function 'undefined' cannot be used in a constant expression}}
return error;
}();
- int c = [](int error = sizeof(undefined()) + ub(0)) { // expected-error {{cannot take address of consteval function 'ub' outside of an immediate invocation}}
+ int c = [](int error = sizeof(undefined()) + ub(0)) {
return error;
}();
} i;
+// expected-error@-1 {{call to immediate function 'InitWithLambda::InitWithLambda' is not a constant expression}} \
+// expected-note@-1 {{in call to 'InitWithLambda()'}}
namespace ShouldNotCrash {
template<typename T>
Index: clang/test/CodeGenCXX/cxx2c-consteval-consteval.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/cxx2c-consteval-consteval.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -emit-llvm %s -std=c++2a -triple x86_64-unknown-linux-gnu -o %t.ll
+// RUN: FileCheck -input-file=%t.ll %s
+
+namespace GH63742 {
+
+void side_effect();
+consteval int f(int x) {
+ if (!__builtin_is_constant_evaluated()) side_effect();
+ return x;
+}
+struct SS {
+ int x = f(42);
+ SS();
+};
+SS::SS(){}
+
+}
+
+// CHECK-LABEL: @_ZN7GH637422SSC2Ev
+// CHECK-NOT: call
+// CHECK: store i32 42, ptr {{.*}}
+// CHECK: ret void
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -6084,17 +6084,11 @@
ImmediateCallVisitor(const ASTContext &Ctx) : Context(Ctx) {}
bool HasImmediateCalls = false;
- bool IsImmediateInvocation = false;
-
bool shouldVisitImplicitCode() const { return true; }
bool VisitCallExpr(CallExpr *E) {
- if (const FunctionDecl *FD = E->getDirectCallee()) {
+ if (const FunctionDecl *FD = E->getDirectCallee())
HasImmediateCalls |= FD->isImmediateFunction();
- if (FD->isConsteval() && !E->isCXX11ConstantExpr(Context))
- IsImmediateInvocation = true;
- }
-
return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E);
}
@@ -6224,6 +6218,9 @@
if (Field->isInvalidDecl())
return ExprError();
+ CXXThisScopeRAII This(*this, Field->getParent(), Qualifiers(),
+ Field->getParent() != nullptr);
+
auto *ParentRD = cast<CXXRecordDecl>(Field->getParent());
std::optional<ExpressionEvaluationContextRecord::InitializationContext>
@@ -6271,13 +6268,6 @@
if (!NestedDefaultChecking)
V.TraverseDecl(Field);
if (V.HasImmediateCalls) {
- // C++23 [expr.const]/p15
- // An aggregate initialization is an immediate invocation
- // if it evaluates a default member initializer that has a subexpression
- // that is an immediate-escalating expression.
- ExprEvalContexts.back().InImmediateFunctionContext |=
- V.IsImmediateInvocation;
-
ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field,
CurContext};
ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
@@ -18418,6 +18408,11 @@
if (!CE.getInt())
EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE);
for (auto *DR : Rec.ReferenceToConsteval) {
+ // If the expression is immediate escalating, it is not an error;
+ // The outer context itself becomes immediate and further errors,
+ // if any, will be handled by DiagnoseImmediateEscalatingReason
+ if (DR->isImmediateEscalating())
+ continue;
const auto *FD = cast<FunctionDecl>(DR->getDecl());
const NamedDecl *ND = FD;
if (const auto *MD = dyn_cast<CXXMethodDecl>(ND);
@@ -18443,8 +18438,15 @@
SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address)
<< ND << isa<CXXRecordDecl>(ND) << FD->isConsteval();
SemaRef.Diag(ND->getLocation(), diag::note_declared_at);
+ if (auto Context =
+ SemaRef.InnermostDeclarationWithDelayedImmediateInvocations()) {
+ SemaRef.Diag(Context->Loc, diag::note_invalid_consteval_initializer)
+ << Context->Decl;
+ SemaRef.Diag(Context->Decl->getBeginLoc(), diag::note_declared_at);
+ }
if (FD->isImmediateEscalating() && !FD->isConsteval())
SemaRef.DiagnoseImmediateEscalatingReason(FD);
+
} else {
SemaRef.MarkExpressionAsImmediateEscalating(DR);
}
@@ -18893,6 +18895,12 @@
// or of another default member initializer (ie a PotentiallyEvaluatedIfUsed
// context), its initializers may not be referenced yet.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
+ EnterExpressionEvaluationContext EvalContext(
+ *this,
+ Constructor->isImmediateFunction()
+ ? ExpressionEvaluationContext::ImmediateFunctionContext
+ : ExpressionEvaluationContext::PotentiallyEvaluated,
+ Constructor);
for (CXXCtorInitializer *Init : Constructor->inits()) {
if (Init->isInClassMemberInitializer())
runWithSufficientStackSpace(Init->getSourceLocation(), [&]() {
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -2438,13 +2438,12 @@
}
bool Sema::CheckImmediateEscalatingFunctionDefinition(
- FunctionDecl *FD, bool HasImmediateEscalatingExpression) {
- if (!FD->hasBody() || !getLangOpts().CPlusPlus20 ||
- !FD->isImmediateEscalating())
+ FunctionDecl *FD, const sema::FunctionScopeInfo *FSI) {
+ if (!getLangOpts().CPlusPlus20 || !FD->isImmediateEscalating())
return true;
FD->setBodyContainsImmediateEscalatingExpressions(
- HasImmediateEscalatingExpression);
- if (HasImmediateEscalatingExpression) {
+ FSI->FoundImmediateEscalatingExpression);
+ if (FSI->FoundImmediateEscalatingExpression) {
auto it = UndefinedButUsed.find(FD->getCanonicalDecl());
if (it != UndefinedButUsed.end()) {
Diag(it->second, diag::err_immediate_function_used_before_definition)
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -15575,8 +15575,7 @@
if (FD) {
FD->setBody(Body);
FD->setWillHaveBody(false);
- CheckImmediateEscalatingFunctionDefinition(
- FD, FSI->FoundImmediateEscalatingExpression);
+ CheckImmediateEscalatingFunctionDefinition(FD, FSI);
if (getLangOpts().CPlusPlus14) {
if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() &&
Index: clang/lib/CodeGen/CGExpr.cpp
===================================================================
--- clang/lib/CodeGen/CGExpr.cpp
+++ clang/lib/CodeGen/CGExpr.cpp
@@ -5319,6 +5319,10 @@
const Decl *TargetDecl =
OrigCallee.getAbstractInfo().getCalleeDecl().getDecl();
+ assert((!isa_and_present<FunctionDecl>(TargetDecl) ||
+ !cast<FunctionDecl>(TargetDecl)->isImmediateFunction()) &&
+ "trying to emit a call to an immediate function");
+
CalleeType = getContext().getCanonicalType(CalleeType);
auto PointeeType = cast<PointerType>(CalleeType)->getPointeeType();
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -1068,10 +1068,13 @@
public:
SynthesizedFunctionScope(Sema &S, DeclContext *DC)
: S(S), SavedContext(S, DC) {
+ auto *FD = dyn_cast<FunctionDecl>(DC);
S.PushFunctionScope();
S.PushExpressionEvaluationContext(
- Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
- if (auto *FD = dyn_cast<FunctionDecl>(DC)) {
+ (FD && FD->isConsteval())
+ ? ExpressionEvaluationContext::ImmediateFunctionContext
+ : ExpressionEvaluationContext::PotentiallyEvaluated);
+ if (FD) {
FD->setWillHaveBody(true);
S.ExprEvalContexts.back().InImmediateFunctionContext =
FD->isImmediateFunction();
@@ -1096,8 +1099,10 @@
~SynthesizedFunctionScope() {
if (PushedCodeSynthesisContext)
S.popCodeSynthesisContext();
- if (auto *FD = dyn_cast<FunctionDecl>(S.CurContext))
+ if (auto *FD = dyn_cast<FunctionDecl>(S.CurContext)) {
FD->setWillHaveBody(false);
+ S.CheckImmediateEscalatingFunctionDefinition(FD, S.getCurFunction());
+ }
S.PopExpressionEvaluationContext();
S.PopFunctionScopeInfo();
}
@@ -6558,8 +6563,9 @@
/// invocation.
ExprResult CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl);
- bool CheckImmediateEscalatingFunctionDefinition(
- FunctionDecl *FD, bool HasImmediateEscalatingExpression);
+ bool
+ CheckImmediateEscalatingFunctionDefinition(FunctionDecl *FD,
+ const sema::FunctionScopeInfo *);
void MarkExpressionAsImmediateEscalating(Expr *E);
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits