Author: Timm Bäder Date: 2024-04-29T14:34:33+02:00 New Revision: f5ed9170464b73a7a0a386358e995ce8373ef153
URL: https://github.com/llvm/llvm-project/commit/f5ed9170464b73a7a0a386358e995ce8373ef153 DIFF: https://github.com/llvm/llvm-project/commit/f5ed9170464b73a7a0a386358e995ce8373ef153.diff LOG: [clang][Interp] Fix creating variables for TemplateParamObjectDecls Actually initialize them with their value. While at it, fix doing it for non-primitive (only struct so far) types as well. Added: Modified: clang/lib/AST/Interp/ByteCodeExprGen.cpp clang/lib/AST/Interp/ByteCodeExprGen.h clang/lib/AST/Interp/Program.cpp clang/test/AST/Interp/records.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index aebefd716e27cc..626c30157b228f 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -2372,41 +2372,8 @@ bool ByteCodeExprGen<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { assert(V.isStruct()); assert(V.getStructNumBases() == 0); - // FIXME: This could be useful in visitAPValue, too. - for (unsigned I = 0, N = V.getStructNumFields(); I != N; ++I) { - const APValue &F = V.getStructField(I); - const Record::Field *RF = R->getField(I); - - if (F.isInt()) { - PrimType T = classifyPrim(RF->Decl->getType()); - if (!this->visitAPValue(F, T, E)) - return false; - if (!this->emitInitField(T, RF->Offset, E)) - return false; - } else if (F.isArray()) { - assert(RF->Desc->isPrimitiveArray()); - const auto *ArrType = RF->Decl->getType()->getAsArrayTypeUnsafe(); - PrimType ElemT = classifyPrim(ArrType->getElementType()); - assert(ArrType); - - if (!this->emitDupPtr(E)) - return false; - if (!this->emitGetPtrField(RF->Offset, E)) - return false; - - for (unsigned A = 0, AN = F.getArraySize(); A != AN; ++A) { - if (!this->visitAPValue(F.getArrayInitializedElt(A), ElemT, E)) - return false; - if (!this->emitInitElem(ElemT, A, E)) - return false; - } - - if (!this->emitPopPtr(E)) - return false; - } else { - assert(false && "I don't think this should be possible"); - } - } + if (!this->visitAPValueInitializer(V, E)) + return false; return this->emitFinishInit(E); } @@ -2971,6 +2938,54 @@ bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val, return false; } +template <class Emitter> +bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val, + const Expr *E) { + if (Val.isStruct()) { + const Record *R = this->getRecord(E->getType()); + assert(R); + + for (unsigned I = 0, N = Val.getStructNumFields(); I != N; ++I) { + const APValue &F = Val.getStructField(I); + const Record::Field *RF = R->getField(I); + + if (F.isInt()) { + PrimType T = classifyPrim(RF->Decl->getType()); + if (!this->visitAPValue(F, T, E)) + return false; + if (!this->emitInitField(T, RF->Offset, E)) + return false; + } else if (F.isArray()) { + assert(RF->Desc->isPrimitiveArray()); + const auto *ArrType = RF->Decl->getType()->getAsArrayTypeUnsafe(); + PrimType ElemT = classifyPrim(ArrType->getElementType()); + assert(ArrType); + + if (!this->emitDupPtr(E)) + return false; + if (!this->emitGetPtrField(RF->Offset, E)) + return false; + + for (unsigned A = 0, AN = F.getArraySize(); A != AN; ++A) { + if (!this->visitAPValue(F.getArrayInitializedElt(A), ElemT, E)) + return false; + if (!this->emitInitElem(ElemT, A, E)) + return false; + } + + if (!this->emitPopPtr(E)) + return false; + } else { + assert(false && "I don't think this should be possible"); + } + } + return true; + } + // TODO: Other types. + + return false; +} + template <class Emitter> bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) { const Function *Func = getFunction(E->getDirectCallee()); @@ -3492,9 +3507,17 @@ bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) { } else if (const auto *FuncDecl = dyn_cast<FunctionDecl>(D)) { const Function *F = getFunction(FuncDecl); return F && this->emitGetFnPtr(F, E); - } else if (isa<TemplateParamObjectDecl>(D)) { - if (std::optional<unsigned> Index = P.getOrCreateGlobal(D)) - return this->emitGetPtrGlobal(*Index, E); + } else if (const auto *TPOD = dyn_cast<TemplateParamObjectDecl>(D)) { + if (std::optional<unsigned> Index = P.getOrCreateGlobal(D)) { + if (!this->emitGetPtrGlobal(*Index, E)) + return false; + if (std::optional<PrimType> T = classify(E->getType())) { + if (!this->visitAPValue(TPOD->getValue(), *T, E)) + return false; + return this->emitInitGlobal(*T, *Index, E); + } + return this->visitAPValueInitializer(TPOD->getValue(), E); + } return false; } diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index 4a57f76ae5b372..2c3127968a1c77 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -181,6 +181,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, bool visitVarDecl(const VarDecl *VD); /// Visit an APValue. bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E); + bool visitAPValueInitializer(const APValue &Val, const Expr *E); /// Visits an expression and converts it to a boolean. bool visitBool(const Expr *E); diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index 3773e0662f784c..02075c20cf556d 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -173,7 +173,8 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD, if (const auto *Var = dyn_cast<VarDecl>(VD)) { IsStatic = Context::shouldBeGloballyIndexed(VD); IsExtern = Var->hasExternalStorage(); - } else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl>(VD)) { + } else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl, + TemplateParamObjectDecl>(VD)) { IsStatic = true; IsExtern = false; } else { diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index ba5c58c96c7bf5..866fa7240d2fae 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1420,3 +1420,17 @@ namespace ZeroInit { constexpr S3 s3d; // both-error {{default initialization of an object of const type 'const S3' without a user-provided default constructor}} static_assert(s3d.n == 0, ""); } + +namespace { +#if __cplusplus >= 202002L + struct C { + template <unsigned N> constexpr C(const char (&)[N]) : n(N) {} + unsigned n; + }; + template <C c> + constexpr auto operator""_c() { return c.n; } + + constexpr auto waldo = "abc"_c; + static_assert(waldo == 4, ""); +#endif +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits