Author: Timm Baeder Date: 2026-03-28T05:22:55+01:00 New Revision: fb094491ac04ef57ffbf0a212d7056e23332b1c7
URL: https://github.com/llvm/llvm-project/commit/fb094491ac04ef57ffbf0a212d7056e23332b1c7 DIFF: https://github.com/llvm/llvm-project/commit/fb094491ac04ef57ffbf0a212d7056e23332b1c7.diff LOG: [clang][bytecode] Skip rvalue subobject adjustments for global temporaries (#189044) We only did this for local variables but were were missing it for globals. Added: Modified: clang/lib/AST/ByteCode/Compiler.cpp clang/lib/AST/ByteCode/EvalEmitter.cpp clang/lib/AST/ByteCode/Program.cpp clang/lib/AST/ByteCode/Program.h clang/test/CodeGenCXX/reference-temporary-subobject.cpp clang/test/CodeGenCXX/static-local-in-local-class.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 4d129a7ccd497..aa3aa6854247d 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -3205,22 +3205,37 @@ bool Compiler<Emitter>::VisitExprWithCleanups(const ExprWithCleanups *E) { template <class Emitter> bool Compiler<Emitter>::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { - const Expr *SubExpr = E->getSubExpr(); - if (Initializing) { // We already have a value, just initialize that. - return this->delegate(SubExpr); + return this->delegate(E->getSubExpr()); } // If we don't end up using the materialized temporary anyway, don't // bother creating it. if (DiscardResult) - return this->discard(SubExpr); + return this->discard(E->getSubExpr()); + + SmallVector<const Expr *, 2> CommaLHSs; + SmallVector<SubobjectAdjustment, 2> Adjustments; + const Expr *Inner; + if (!Ctx.getLangOpts().CPlusPlus11) + Inner = + E->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); + else + Inner = E->getSubExpr(); + + // If we passed any comma operators, evaluate their LHSs. + for (const Expr *LHS : CommaLHSs) { + if (!this->discard(LHS)) + return false; + } + + // FIXME: Find a test case where Adjustments matters. // When we're initializing a global variable *or* the storage duration of // the temporary is explicitly static, create a global variable. - OptPrimType SubExprT = classify(SubExpr); + OptPrimType InnerT = classify(Inner); if (E->getStorageDuration() == SD_Static) { - UnsignedOrNone GlobalIndex = P.createGlobal(E); + UnsignedOrNone GlobalIndex = P.createGlobal(E, Inner->getType()); if (!GlobalIndex) return false; @@ -3228,20 +3243,20 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr( E->getLifetimeExtendedTemporaryDecl(); assert(TempDecl); - if (SubExprT) { - if (!this->visit(SubExpr)) + if (InnerT) { + if (!this->visit(Inner)) return false; - if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E)) + if (!this->emitInitGlobalTemp(*InnerT, *GlobalIndex, TempDecl, E)) return false; return this->emitGetPtrGlobal(*GlobalIndex, E); } - if (!this->checkLiteralType(SubExpr)) + if (!this->checkLiteralType(Inner)) return false; // Non-primitive values. if (!this->emitGetPtrGlobal(*GlobalIndex, E)) return false; - if (!this->visitInitializer(SubExpr)) + if (!this->visitInitializer(Inner)) return false; return this->emitInitGlobalTempComp(TempDecl, E); } @@ -3251,27 +3266,26 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr( : ScopeKind::Block; // For everyhing else, use local variables. - if (SubExprT) { - bool IsConst = SubExpr->getType().isConstQualified(); - bool IsVolatile = SubExpr->getType().isVolatileQualified(); + if (InnerT) { + bool IsConst = Inner->getType().isConstQualified(); + bool IsVolatile = Inner->getType().isVolatileQualified(); unsigned LocalIndex = - allocateLocalPrimitive(E, *SubExprT, IsConst, IsVolatile, VarScope); + allocateLocalPrimitive(E, *InnerT, IsConst, IsVolatile, VarScope); if (!this->VarScope->LocalsAlwaysEnabled && !this->emitEnableLocal(LocalIndex, E)) return false; - if (!this->visit(SubExpr)) + if (!this->visit(Inner)) return false; - if (!this->emitSetLocal(*SubExprT, LocalIndex, E)) + if (!this->emitSetLocal(*InnerT, LocalIndex, E)) return false; return this->emitGetPtrLocal(LocalIndex, E); } - if (!this->checkLiteralType(SubExpr)) + if (!this->checkLiteralType(Inner)) return false; - const Expr *Inner = E->getSubExpr()->skipRValueSubobjectAdjustments(); if (UnsignedOrNone LocalIndex = allocateLocal(E, Inner->getType(), VarScope)) { InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex)); @@ -3282,7 +3296,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr( if (!this->emitGetPtrLocal(*LocalIndex, E)) return false; - return this->visitInitializer(SubExpr) && this->emitFinishInit(E); + return this->visitInitializer(Inner) && this->emitFinishInit(E); } return false; } @@ -3323,7 +3337,7 @@ bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { if (T && !E->isLValue()) return this->delegate(Init); - UnsignedOrNone GlobalIndex = P.createGlobal(E); + UnsignedOrNone GlobalIndex = P.createGlobal(E, E->getType()); if (!GlobalIndex) return false; @@ -5220,7 +5234,6 @@ Compiler<Emitter>::visitVarDecl(const VarDecl *VD, const Expr *Init, }; DeclScope<Emitter> LocalScope(this, VD); - UnsignedOrNone GlobalIndex = P.getGlobal(VD); if (GlobalIndex) { // The global was previously created but the initializer failed. diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 8e8ffc131814b..9cbd786e883a2 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -11,6 +11,7 @@ #include "IntegralAP.h" #include "Interp.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" #include "llvm/ADT/ScopeExit.h" using namespace clang; @@ -370,12 +371,16 @@ void EvalEmitter::updateGlobalTemporaries() { assert(GlobalIndex); const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex); APValue *Cached = Temp->getOrCreateValue(true); - if (OptPrimType T = Ctx.classify(E->getType())) { + + QualType TempType = E->getType(); + if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) + TempType = MTE->getSubExpr()->skipRValueSubobjectAdjustments()->getType(); + + if (OptPrimType T = Ctx.classify(TempType)) { TYPE_SWITCH(*T, { *Cached = Ptr.deref<T>().toAPValue(Ctx.getASTContext()); }); } else { - if (std::optional<APValue> APV = - Ptr.toRValue(Ctx, Temp->getTemporaryExpr()->getType())) + if (std::optional<APValue> APV = Ptr.toRValue(Ctx, TempType)) *Cached = *APV; } } diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index ccef38ab14ebe..2ad5879b4e82a 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -232,10 +232,10 @@ UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init) { return *Idx; } -UnsignedOrNone Program::createGlobal(const Expr *E) { +UnsignedOrNone Program::createGlobal(const Expr *E, QualType ExprType) { if (auto Idx = getGlobal(E)) return Idx; - if (auto Idx = createGlobal(E, E->getType(), /*IsStatic=*/true, + if (auto Idx = createGlobal(E, ExprType, /*IsStatic=*/true, /*IsExtern=*/false, /*IsWeak=*/false)) { GlobalIndices[E] = *Idx; return *Idx; @@ -402,7 +402,6 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, bool IsConst, bool IsTemporary, bool IsMutable, bool IsVolatile, const Expr *Init) { - // Classes and structures. if (const auto *RD = Ty->getAsRecordDecl()) { if (const auto *Record = getOrCreateRecord(RD)) diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h index c8795504391fa..91126a51e8ddc 100644 --- a/clang/lib/AST/ByteCode/Program.h +++ b/clang/lib/AST/ByteCode/Program.h @@ -92,7 +92,7 @@ class Program final { UnsignedOrNone createGlobal(const ValueDecl *VD, const Expr *Init); /// Creates a global from a lifetime-extended temporary. - UnsignedOrNone createGlobal(const Expr *E); + UnsignedOrNone createGlobal(const Expr *E, QualType ExprType); /// Creates a new function from a code range. template <typename... Ts> diff --git a/clang/test/CodeGenCXX/reference-temporary-subobject.cpp b/clang/test/CodeGenCXX/reference-temporary-subobject.cpp index 828bd53692448..b4ff133d4e483 100644 --- a/clang/test/CodeGenCXX/reference-temporary-subobject.cpp +++ b/clang/test/CodeGenCXX/reference-temporary-subobject.cpp @@ -10,6 +10,8 @@ // // RUN: %clang_cc1 -std=c++98 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -std=c++98 -triple x86_64-linux-gnu -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm -o - %s -fexperimental-new-constant-interpreter | FileCheck %s // `const int &` bound to a member of an S temporary. // The backing store is the whole S object, which can't be stored const. diff --git a/clang/test/CodeGenCXX/static-local-in-local-class.cpp b/clang/test/CodeGenCXX/static-local-in-local-class.cpp index dd760b4b529d5..7d2c83eccb7e4 100644 --- a/clang/test/CodeGenCXX/static-local-in-local-class.cpp +++ b/clang/test/CodeGenCXX/static-local-in-local-class.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-linux -fblocks -emit-llvm -o - %s -std=c++1y | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-linux -fblocks -emit-llvm -o - %s -std=c++1y -fexperimental-new-constant-interpreter | FileCheck %s // CHECK: @"_ZZZNK17pr18020_constexpr3$_1clEvENKUlvE_clEvE2l2" = // CHECK: internal global ptr @"_ZZNK17pr18020_constexpr3$_1clEvE2l1" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
