diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index b960954d4754a..59e09a44d747b 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -2371,9 +2371,9 @@ bool Compiler::VisitStringLiteral(const StringLiteral *E) { template bool Compiler::VisitObjCStringLiteral(const ObjCStringLiteral *E) { - if (std::optional I = P.getOrCreateDummy(E)) - return this->emitGetPtrGlobal(*I, E); - return false; + if (DiscardResult) + return true; + return this->emitDummyPtr(E, E); } template @@ -3445,11 +3445,8 @@ bool Compiler::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { assert(RD); // If the definiton of the result type is incomplete, just return a dummy. // If (and when) that is read from, we will fail, but not now. - if (!RD->isCompleteDefinition()) { - if (std::optional I = P.getOrCreateDummy(GuidDecl)) - return this->emitGetPtrGlobal(*I, E); - return false; - } + if (!RD->isCompleteDefinition()) + return this->emitDummyPtr(GuidDecl, E); std::optional GlobalIndex = P.getOrCreateGlobal(GuidDecl); if (!GlobalIndex) @@ -3687,11 +3684,11 @@ bool Compiler::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) { if (!E->isExpressibleAsConstantInitializer()) return this->discard(SubExpr) && this->emitInvalid(E); - assert(classifyPrim(E) == PT_Ptr); - if (std::optional I = P.getOrCreateDummy(E)) - return this->emitGetPtrGlobal(*I, E); + if (DiscardResult) + return true; - return false; + assert(classifyPrim(E) == PT_Ptr); + return this->emitDummyPtr(E, E); } template @@ -4483,15 +4480,9 @@ bool Compiler::VisitBuiltinCallExpr(const CallExpr *E, BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString || BuiltinID == Builtin::BI__builtin_ptrauth_sign_constant || BuiltinID == Builtin::BI__builtin_function_start) { - if (std::optional GlobalOffset = P.getOrCreateDummy(E)) { - if (!this->emitGetPtrGlobal(*GlobalOffset, E)) - return false; - - if (PrimType PT = classifyPrim(E); PT != PT_Ptr && isPtrType(PT)) - return this->emitDecayPtr(PT_Ptr, PT, E); + if (DiscardResult) return true; - } - return false; + return this->emitDummyPtr(E, E); } QualType ReturnType = E->getType(); @@ -6097,6 +6088,10 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { if (VD->evaluateValue()) return revisit(VD); + + if (!D->getType()->isReferenceType()) + return this->emitDummyPtr(D, E); + return this->emitInvalidDeclRef(cast(E), /*InitializerFailed=*/true, E); } @@ -6109,23 +6104,7 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { } } - if (std::optional I = P.getOrCreateDummy(D)) { - if (!this->emitGetPtrGlobal(*I, E)) - return false; - if (E->getType()->isVoidType()) - return true; - // Convert the dummy pointer to another pointer type if we have to. - if (PrimType PT = classifyPrim(E); PT != PT_Ptr) { - if (isPtrType(PT)) - return this->emitDecayPtr(PT_Ptr, PT, E); - return false; - } - return true; - } - - if (const auto *DRE = dyn_cast(E)) - return this->emitInvalidDeclRef(DRE, /*InitializerFailed=*/false, E); - return false; + return this->emitDummyPtr(D, E); } template @@ -6428,6 +6407,29 @@ bool Compiler::emitDestruction(const Descriptor *Desc, return this->emitRecordDestruction(Desc->ElemRecord, Loc); } +/// Create a dummy pointer for the given decl (or expr) and +/// push a pointer to it on the stack. +template +bool Compiler::emitDummyPtr(const DeclTy &D, const Expr *E) { + assert(!DiscardResult && "Should've been checked before"); + + unsigned DummyID = P.getOrCreateDummy(D); + + if (!this->emitGetPtrGlobal(DummyID, E)) + return false; + if (E->getType()->isVoidType()) + return true; + + // Convert the dummy pointer to another pointer type if we have to. + if (PrimType PT = classifyPrim(E); PT != PT_Ptr) { + if (isPtrType(PT)) + return this->emitDecayPtr(PT_Ptr, PT, E); + return false; + } + + return true; +} + namespace clang { namespace interp { diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h index 4253e7b3248c9..5627d5071e810 100644 --- a/clang/lib/AST/ByteCode/Compiler.h +++ b/clang/lib/AST/ByteCode/Compiler.h @@ -370,6 +370,7 @@ class Compiler : public ConstStmtVisitor, bool>, const BinaryOperator *E); bool emitRecordDestruction(const Record *R, SourceInfo Loc); bool emitDestruction(const Descriptor *Desc, SourceInfo Loc); + bool emitDummyPtr(const DeclTy &D, const Expr *E); unsigned collectBaseOffset(const QualType BaseType, const QualType DerivedType); bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD); diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp index cd2665f755d7c..0da518ec92afa 100644 --- a/clang/lib/AST/ByteCode/Program.cpp +++ b/clang/lib/AST/ByteCode/Program.cpp @@ -147,7 +147,7 @@ std::optional Program::getOrCreateGlobal(const ValueDecl *VD, return std::nullopt; } -std::optional Program::getOrCreateDummy(const DeclTy &D) { +unsigned Program::getOrCreateDummy(const DeclTy &D) { assert(D); // Dedup blocks since they are immutable and pointers cannot be compared. if (auto It = DummyVariables.find(D.getOpaqueValue()); diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h index f676672fb7ced..9aabe67b550ec 100644 --- a/clang/lib/AST/ByteCode/Program.h +++ b/clang/lib/AST/ByteCode/Program.h @@ -85,7 +85,7 @@ class Program final { const Expr *Init = nullptr); /// Returns or creates a dummy value for unknown declarations. - std::optional getOrCreateDummy(const DeclTy &D); + unsigned getOrCreateDummy(const DeclTy &D); /// Creates a global and returns its index. std::optional createGlobal(const ValueDecl *VD, const Expr *Init); diff --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp index 215f26bd5da8e..2eeaafc04c516 100644 --- a/clang/test/AST/ByteCode/records.cpp +++ b/clang/test/AST/ByteCode/records.cpp @@ -1661,3 +1661,18 @@ namespace NullptrUpcast { constexpr A &ra = *nb; // both-error {{constant expression}} \ // both-note {{cannot access base class of null pointer}} } + +namespace NonConst { + template + struct S { + static constexpr int Size = I; + constexpr int getSize() const { return I; } + explicit S(int a) {} + }; + + void func() { + int a,b ; + const S<10> s{a}; + static_assert(s.getSize() == 10, ""); + } +}