Author: Tyker Date: 2020-06-15T10:47:14+02:00 New Revision: 3bab88b7baa20b276faaee0aa7ca87f636c91877
URL: https://github.com/llvm/llvm-project/commit/3bab88b7baa20b276faaee0aa7ca87f636c91877 DIFF: https://github.com/llvm/llvm-project/commit/3bab88b7baa20b276faaee0aa7ca87f636c91877.diff LOG: Prevent IR-gen from emitting consteval declarations Summary: with this patch instead of emitting calls to consteval function. the IR-gen will emit a store of the already computed result. Reviewers: rsmith Reviewed By: rsmith Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D76420 Added: clang/test/CodeGenCXX/cxx2a-consteval.cpp Modified: clang/lib/AST/Expr.cpp clang/lib/AST/ExprConstant.cpp clang/lib/CodeGen/CGCall.cpp clang/lib/CodeGen/CGDecl.cpp clang/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CGExprAgg.cpp clang/lib/CodeGen/CGExprComplex.cpp clang/lib/CodeGen/CGExprConstant.cpp clang/lib/CodeGen/CGExprScalar.cpp clang/lib/CodeGen/CGStmt.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/CodeGen/CodeGenModule.cpp clang/lib/CodeGen/ConstantEmitter.h clang/lib/Sema/SemaExpr.cpp clang/test/SemaCXX/cxx2a-consteval.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 89eb8e9c0220..27a12b880a7b 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -272,6 +272,7 @@ void ConstantExpr::DefaultInit(ResultStorageKind StorageKind) { ConstantExprBits.ResultKind = StorageKind; ConstantExprBits.APValueKind = APValue::None; ConstantExprBits.HasCleanup = false; + ConstantExprBits.IsImmediateInvocation = false; if (StorageKind == ConstantExpr::RSK_APValue) ::new (getTrailingObjects<APValue>()) APValue(); } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index c8f1a92d0725..870bf7696093 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9986,8 +9986,6 @@ class IntExprEvaluator // Visitor Methods //===--------------------------------------------------------------------===// - bool VisitConstantExpr(const ConstantExpr *E); - bool VisitIntegerLiteral(const IntegerLiteral *E) { return Success(E->getValue(), E); } @@ -10769,13 +10767,6 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type, return true; } -bool IntExprEvaluator::VisitConstantExpr(const ConstantExpr *E) { - llvm::SaveAndRestore<bool> InConstantContext(Info.InConstantContext, true); - if (E->getResultAPValueKind() != APValue::None) - return Success(E->getAPValueResult(), E); - return ExprEvaluatorBaseTy::VisitConstantExpr(E); -} - bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { if (unsigned BuiltinOp = E->getBuiltinCallee()) return VisitBuiltinCallExpr(E, BuiltinOp); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 17282e2bafe6..78a0ecef4f3f 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1272,18 +1272,17 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty, // store the elements rather than the aggregate to be more friendly to // fast-isel. // FIXME: Do we need to recurse here? -static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val, - Address Dest, bool DestIsVolatile) { +void CodeGenFunction::EmitAggregateStore(llvm::Value *Val, Address Dest, + bool DestIsVolatile) { // Prefer scalar stores to first-class aggregate stores. - if (llvm::StructType *STy = - dyn_cast<llvm::StructType>(Val->getType())) { + if (llvm::StructType *STy = dyn_cast<llvm::StructType>(Val->getType())) { for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { - Address EltPtr = CGF.Builder.CreateStructGEP(Dest, i); - llvm::Value *Elt = CGF.Builder.CreateExtractValue(Val, i); - CGF.Builder.CreateStore(Elt, EltPtr, DestIsVolatile); + Address EltPtr = Builder.CreateStructGEP(Dest, i); + llvm::Value *Elt = Builder.CreateExtractValue(Val, i); + Builder.CreateStore(Elt, EltPtr, DestIsVolatile); } } else { - CGF.Builder.CreateStore(Val, Dest, DestIsVolatile); + Builder.CreateStore(Val, Dest, DestIsVolatile); } } @@ -1334,7 +1333,7 @@ static void CreateCoercedStore(llvm::Value *Src, // If store is legal, just bitcast the src pointer. if (SrcSize <= DstSize) { Dst = CGF.Builder.CreateElementBitCast(Dst, SrcTy); - BuildAggStore(CGF, Src, Dst, DstIsVolatile); + CGF.EmitAggregateStore(Src, Dst, DstIsVolatile); } else { // Otherwise do coercion through memory. This is stupid, but // simple. @@ -5070,7 +5069,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, DestPtr = CreateMemTemp(RetTy, "agg.tmp"); DestIsVolatile = false; } - BuildAggStore(*this, CI, DestPtr, DestIsVolatile); + EmitAggregateStore(CI, DestPtr, DestIsVolatile); return RValue::getAggregate(DestPtr); } case TEK_Scalar: { diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 52ed90d837fd..f2549769080e 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -762,9 +762,8 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, // If we're emitting a value with lifetime, we have to do the // initialization *before* we leave the cleanup scopes. - if (const FullExpr *fe = dyn_cast<FullExpr>(init)) - init = fe->getSubExpr(); - + if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(init)) + init = EWC->getSubExpr(); CodeGenFunction::RunCleanupsScope Scope(*this); // We have to maintain the illusion that the variable is diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index c8147ede93c9..bead7e8996c0 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1302,8 +1302,15 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitVAArgExprLValue(cast<VAArgExpr>(E)); case Expr::DeclRefExprClass: return EmitDeclRefLValue(cast<DeclRefExpr>(E)); - case Expr::ConstantExprClass: + case Expr::ConstantExprClass: { + const ConstantExpr *CE = cast<ConstantExpr>(E); + if (llvm::Value *Result = ConstantEmitter(*this).tryEmitConstantExpr(CE)) { + QualType RetType = cast<CallExpr>(CE->getSubExpr()->IgnoreImplicit()) + ->getCallReturnType(getContext()); + return MakeNaturalAlignAddrLValue(Result, RetType); + } return EmitLValue(cast<ConstantExpr>(E)->getSubExpr()); + } case Expr::ParenExprClass: return EmitLValue(cast<ParenExpr>(E)->getSubExpr()); case Expr::GenericSelectionExprClass: diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 74702dda789d..fb96d70732e8 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -127,6 +127,11 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { } void VisitConstantExpr(ConstantExpr *E) { + if (llvm::Value *Result = ConstantEmitter(CGF).tryEmitConstantExpr(E)) { + CGF.EmitAggregateStore(Result, Dest.getAddress(), + E->getType().isVolatileQualified()); + return; + } return Visit(E->getSubExpr()); } diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index 1cf497c7dfda..13a571352137 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -13,6 +13,7 @@ #include "CGOpenMPRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "ConstantEmitter.h" #include "clang/AST/StmtVisitor.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Constants.h" @@ -102,6 +103,9 @@ class ComplexExprEmitter } ComplexPairTy VisitExpr(Expr *S); ComplexPairTy VisitConstantExpr(ConstantExpr *E) { + if (llvm::Constant *Result = ConstantEmitter(CGF).tryEmitConstantExpr(E)) + return ComplexPairTy(Result->getAggregateElement(0U), + Result->getAggregateElement(1U)); return Visit(E->getSubExpr()); } ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());} diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 0138edbb9df8..a01571633f6c 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1011,6 +1011,8 @@ class ConstExprEmitter : } llvm::Constant *VisitConstantExpr(ConstantExpr *CE, QualType T) { + if (llvm::Constant *Result = Emitter.tryEmitConstantExpr(CE)) + return Result; return Visit(CE->getSubExpr(), T); } @@ -1358,6 +1360,20 @@ ConstantEmitter::tryEmitAbstract(const APValue &value, QualType destType) { return validateAndPopAbstract(C, state); } +llvm::Constant *ConstantEmitter::tryEmitConstantExpr(const ConstantExpr *CE) { + if (!CE->hasAPValueResult()) + return nullptr; + const Expr *Inner = CE->getSubExpr()->IgnoreImplicit(); + QualType RetType; + if (auto *Call = dyn_cast<CallExpr>(Inner)) + RetType = Call->getCallReturnType(CGF->getContext()); + else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Inner)) + RetType = Ctor->getType(); + llvm::Constant *Res = + emitAbstract(CE->getBeginLoc(), CE->getAPValueResult(), RetType); + return Res; +} + llvm::Constant * ConstantEmitter::emitAbstract(const Expr *E, QualType destType) { auto state = pushAbstract(); @@ -1903,6 +1919,8 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { ConstantLValue ConstantLValueEmitter::VisitConstantExpr(const ConstantExpr *E) { + if (llvm::Constant *Result = Emitter.tryEmitConstantExpr(E)) + return Result; return Visit(E->getSubExpr()); } diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 6b33d807a7bd..f48f7185b55f 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -419,6 +419,12 @@ class ScalarExprEmitter Value *VisitExpr(Expr *S); Value *VisitConstantExpr(ConstantExpr *E) { + if (Value *Result = ConstantEmitter(CGF).tryEmitConstantExpr(E)) { + if (E->isGLValue()) + return CGF.Builder.CreateLoad(Address( + Result, CGF.getContext().getTypeAlignInChars(E->getType()))); + return Result; + } return Visit(E->getSubExpr()); } Value *VisitParenExpr(ParenExpr *PE) { diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index c9b8da1d4d39..672909849bb7 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -1119,9 +1119,8 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { SaveRetExprRAII SaveRetExpr(RV, *this); RunCleanupsScope cleanupScope(*this); - if (const FullExpr *fe = dyn_cast_or_null<FullExpr>(RV)) - RV = fe->getSubExpr(); - + if (const auto *EWC = dyn_cast_or_null<ExprWithCleanups>(RV)) + RV = EWC->getSubExpr(); // FIXME: Clean this up by using an LValue for ReturnTemp, // EmitStoreThroughLValue, and EmitAnyExpr. // Check if the NRVO candidate was not globalized in OpenMP mode. diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 5dbaf2ee7281..273aa1c962c3 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4138,6 +4138,10 @@ class CodeGenFunction : public CodeGenTypeCache { /// aggregate type into a temporary LValue. LValue EmitAggExprToLValue(const Expr *E); + /// Build all the stores needed to initialize an aggregate at Dest with the + /// value Val. + void EmitAggregateStore(llvm::Value *Val, Address Dest, bool DestIsVolatile); + /// EmitExtendGCLifetime - Given a pointer to an Objective-C object, /// make sure it survives garbage collection until this point. void EmitExtendGCLifetime(llvm::Value *object); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 26d34fa293e4..887df8a97f34 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3336,6 +3336,8 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD, bool ForVTable, bool DontDefer, ForDefinition_t IsForDefinition) { + assert(!cast<FunctionDecl>(GD.getDecl())->isConsteval() && + "consteval function should never be emitted"); // If there was no specific requested type, just convert it now. if (!Ty) { const auto *FD = cast<FunctionDecl>(GD.getDecl()); @@ -5330,6 +5332,11 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { if (D->isTemplated()) return; + // Consteval function shouldn't be emitted. + if (auto *FD = dyn_cast<FunctionDecl>(D)) + if (FD->isConsteval()) + return; + switch (D->getKind()) { case Decl::CXXConversion: case Decl::CXXMethod: diff --git a/clang/lib/CodeGen/ConstantEmitter.h b/clang/lib/CodeGen/ConstantEmitter.h index 121acbac4fa9..188b82e56f53 100644 --- a/clang/lib/CodeGen/ConstantEmitter.h +++ b/clang/lib/CodeGen/ConstantEmitter.h @@ -110,6 +110,8 @@ class ConstantEmitter { llvm::Constant *tryEmitAbstract(const APValue &value, QualType T); llvm::Constant *tryEmitAbstractForMemory(const APValue &value, QualType T); + llvm::Constant *tryEmitConstantExpr(const ConstantExpr *CE); + llvm::Constant *emitNullForMemory(QualType T) { return emitNullForMemory(CGM, T); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 6965acdb6163..66a2ec1fe9dc 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -16139,7 +16139,7 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { ConstantExpr *Res = ConstantExpr::Create( getASTContext(), E.get(), - ConstantExpr::getStorageKind(E.get()->getType().getTypePtr(), + ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(), getASTContext()), /*IsImmediateInvocation*/ true); ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0); diff --git a/clang/test/CodeGenCXX/cxx2a-consteval.cpp b/clang/test/CodeGenCXX/cxx2a-consteval.cpp new file mode 100644 index 000000000000..8856cb5fd765 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx2a-consteval.cpp @@ -0,0 +1,210 @@ +// NOTE: Assertions have been autogenerated by utils/update_test_checks.py +// RUN: %clang_cc1 -emit-llvm %s -std=c++2a -o %t.ll +// RUN: FileCheck -check-prefix=EVAL -input-file=%t.ll %s +// RUN: FileCheck -check-prefix=EVAL-FN -input-file=%t.ll %s +// RUN: FileCheck -check-prefix=EVAL-STATIC -input-file=%t.ll %s +// RUN: %clang_cc1 -emit-llvm %s -Dconsteval="" -std=c++2a -o %t.ll +// RUN: FileCheck -check-prefix=EXPR -input-file=%t.ll %s + +// there is two version of symbol checks to ensure +// that the symbol we are looking for are correct +// EVAL-NOT: @__cxx_global_var_init() +// EXPR: @__cxx_global_var_init() + +// EVAL-NOT: @_Z4ret7v() +// EXPR: @_Z4ret7v() +consteval int ret7() { + return 7; +} + +int test_ret7() { + // EVAL-FN-LABEL: @_Z9test_ret7v( + // EVAL-FN-NEXT: entry: + // EVAL-FN-NEXT: [[I:%.*]] = alloca i32, align 4 + // EVAL-FN-NEXT: store i32 7, i32* [[I]], align 4 + // EVAL-FN-NEXT: [[TMP0:%.*]] = load i32, i32* [[I]], align 4 + // EVAL-FN-NEXT: ret i32 [[TMP0]] + // + int i = ret7(); + return i; +} + +// EVAL-STATIC: @global_i = global i32 7, align 4 +int global_i = ret7(); + +// EVAL-STATIC: @_ZL7i_const = internal constant i32 5, align 4 +constexpr int i_const = 5; + +// EVAL-NOT: @_Z4retIv() +// EXPR: @_Z4retIv() +consteval const int &retI() { + return i_const; +} + +const int &test_retRefI() { + // EVAL-FN-LABEL: @_Z12test_retRefIv( + // EVAL-FN-NEXT: entry: + // EVAL-FN-NEXT: ret i32* @_ZL7i_const + // + return retI(); +} + +int test_retI() { + // EVAL-FN-LABEL: @_Z9test_retIv( + // EVAL-FN-NEXT: entry: + // EVAL-FN-NEXT: [[TMP0:%.*]] = load i32, i32* @_ZL7i_const, align 4 + // EVAL-FN-NEXT: ret i32 [[TMP0]] + // + return retI(); +} + +// EVAL-NOT: @_Z4retIv() +// EXPR: @_Z4retIv() +consteval const int *retIPtr() { + return &i_const; +} + +int test_retIPtr() { + // EVAL-FN-LABEL: @_Z12test_retIPtrv( + // EVAL-FN-NEXT: entry: + // EVAL-FN-NEXT: [[TMP0:%.*]] = load i32, i32* @_ZL7i_const, align 4 + // EVAL-FN-NEXT: ret i32 [[TMP0]] + // + return *retIPtr(); +} + +const int *test_retPIPtr() { + // EVAL-FN-LABEL: @_Z13test_retPIPtrv( + // EVAL-FN-NEXT: entry: + // EVAL-FN-NEXT: ret i32* @_ZL7i_const + // + return retIPtr(); +} + +// EVAL-NOT: @_Z4retIv() +// EXPR: @_Z4retIv() +consteval const int &&retIRRef() { + return static_cast<const int &&>(i_const); +} + +const int &&test_retIRRef() { + return static_cast<const int &&>(retIRRef()); +} + +int test_retIRRefI() { + // EVAL-FN-LABEL: @_Z14test_retIRRefIv( + // EVAL-FN-NEXT: entry: + // EVAL-FN-NEXT: [[TMP0:%.*]] = load i32, i32* @_ZL7i_const, align 4 + // EVAL-FN-NEXT: ret i32 [[TMP0]] + // + return retIRRef(); +} + +struct Agg { + int a; + long b; +}; + +// EVAL-NOT: @_Z6retAggv() +// EXPR: @_Z6retAggv() +consteval Agg retAgg() { + return {13, 17}; +} + +long test_retAgg() { + // EVAL-FN-LABEL: @_Z11test_retAggv( + // EVAL-FN-NEXT: entry: + // EVAL-FN-NEXT: [[B:%.*]] = alloca i64, align 8 + // EVAL-FN-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8 + // EVAL-FN-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 0 + // EVAL-FN-NEXT: store i32 13, i32* [[TMP0]], align 8 + // EVAL-FN-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 1 + // EVAL-FN-NEXT: store i64 17, i64* [[TMP1]], align 8 + // EVAL-FN-NEXT: store i64 17, i64* [[B]], align 8 + // EVAL-FN-NEXT: [[TMP2:%.*]] = load i64, i64* [[B]], align 8 + // EVAL-FN-NEXT: ret i64 [[TMP2]] + // + long b = retAgg().b; + return b; +} + +// EVAL-STATIC: @A = global %struct.Agg { i32 13, i64 17 }, align 8 +Agg A = retAgg(); + +// EVAL-NOT: @_Z9retRefAggv() +// EXPR: @_Z9retRefAggv() +consteval const Agg &retRefAgg() { + const Agg &tmp = A; + return A; +} + +long test_retRefAgg() { + // EVAL-FN-LABEL: @_Z14test_retRefAggv( + // EVAL-FN-NEXT: entry: + // EVAL-FN-NEXT: [[B:%.*]] = alloca i64, align 8 + // EVAL-FN-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8 + // EVAL-FN-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 0 + // EVAL-FN-NEXT: store i32 13, i32* [[TMP0]], align 8 + // EVAL-FN-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 1 + // EVAL-FN-NEXT: store i64 17, i64* [[TMP1]], align 8 + // EVAL-FN-NEXT: store i64 17, i64* [[B]], align 8 + // EVAL-FN-NEXT: [[TMP2:%.*]] = load i64, i64* [[B]], align 8 + // EVAL-FN-NEXT: ret i64 [[TMP2]] + // + long b = retAgg().b; + return b; +} + +// EVAL-NOT: @_Z8is_constv() +// EXPR: @_Z8is_constv() +consteval Agg is_const() { + return {5, 19 * __builtin_is_constant_evaluated()}; +} + +long test_is_const() { + // EVAL-FN-LABEL: @_Z13test_is_constv( + // EVAL-FN-NEXT: entry: + // EVAL-FN-NEXT: [[B:%.*]] = alloca i64, align 8 + // EVAL-FN-NEXT: [[REF_TMP:%.*]] = alloca [[STRUCT_AGG:%.*]], align 8 + // EVAL-FN-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 0 + // EVAL-FN-NEXT: store i32 5, i32* [[TMP0]], align 8 + // EVAL-FN-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_AGG]], %struct.Agg* [[REF_TMP]], i32 0, i32 1 + // EVAL-FN-NEXT: store i64 19, i64* [[TMP1]], align 8 + // EVAL-FN-NEXT: store i64 19, i64* [[B]], align 8 + // EVAL-FN-NEXT: [[TMP2:%.*]] = load i64, i64* [[B]], align 8 + // EVAL-FN-NEXT: ret i64 [[TMP2]] + // + long b = is_const().b; + return b; +} + +// EVAL-NOT: @_ZN7AggCtorC +// EXPR: @_ZN7AggCtorC +struct AggCtor { + consteval AggCtor(int a = 3, long b = 5) : a(a * a), b(a * b) {} + int a; + long b; +}; + +long test_AggCtor() { + // CHECK-LABEL: @_Z12test_AggCtorv( + // CHECK-NEXT: entry: + // CHECK-NEXT: [[I:%.*]] = alloca i32, align 4 + // CHECK-NEXT: [[C:%.*]] = alloca [[STRUCT_AGGCTOR:%.*]], align 8 + // CHECK-NEXT: store i32 2, i32* [[I]], align 4 + // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_AGGCTOR]], %struct.AggCtor* [[C]], i32 0, i32 0 + // CHECK-NEXT: store i32 4, i32* [[TMP0]], align 8 + // CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_AGGCTOR]], %struct.AggCtor* [[C]], i32 0, i32 1 + // CHECK-NEXT: store i64 10, i64* [[TMP1]], align 8 + // CHECK-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_AGGCTOR]], %struct.AggCtor* [[C]], i32 0, i32 0 + // CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[A]], align 8 + // CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP2]] to i64 + // CHECK-NEXT: [[B:%.*]] = getelementptr inbounds [[STRUCT_AGGCTOR]], %struct.AggCtor* [[C]], i32 0, i32 1 + // CHECK-NEXT: [[TMP3:%.*]] = load i64, i64* [[B]], align 8 + // CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[CONV]], [[TMP3]] + // CHECK-NEXT: ret i64 [[ADD]] + // + const int i = 2; + AggCtor C(i); + return C.a + C.b; +} diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index a1716b4fa8c3..0a6d137e9670 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++2a -fsyntax-only -Wno-unused-value %s -verify +// RUN: %clang_cc1 -std=c++2a -emit-llvm-only -Wno-unused-value %s -verify typedef __SIZE_TYPE__ size_t; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits