https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/204165
>From bddedb251cdde8fe1b1d1600283a22d0ee3d38fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Tue, 16 Jun 2026 15:56:22 +0200 Subject: [PATCH] asdf --- clang/lib/AST/ByteCode/Compiler.cpp | 47 ++++++++++++++----- clang/lib/AST/ByteCode/EvalEmitter.cpp | 12 ++++- clang/lib/AST/ByteCode/Interp.h | 8 ++++ .../SemaCXX/constant-expression-p2280r4.cpp | 12 ++--- 4 files changed, 60 insertions(+), 19 deletions(-) diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 389a0094509a9..20b110b38ff78 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -7672,16 +7672,21 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) { template <class Emitter> bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { - if (DiscardResult) - return true; - - if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) + if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) { + if (DiscardResult) + return true; return this->emitConst(ECD->getInitVal(), E); + } if (const auto *FuncDecl = dyn_cast<FunctionDecl>(D)) { + if (DiscardResult) + return true; const Function *F = getFunction(FuncDecl); return F && this->emitGetFnPtr(F, E); } if (const auto *TPOD = dyn_cast<TemplateParamObjectDecl>(D)) { + if (DiscardResult) + return true; + if (UnsignedOrNone Index = P.getOrCreateGlobal(D)) { if (OptPrimType T = classify(D->getType())) { if (!this->visitAPValue(TPOD->getValue(), *T, E)) @@ -7705,10 +7710,19 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { QualType DeclType = D->getType(); bool IsReference = DeclType->isReferenceType(); + auto maybePopPtr = [&]() -> bool { + if (DiscardResult) + return this->emitPopPtr(E); + return true; + }; + // Function parameters. // Note that it's important to check them first since we might have a local // variable created for a ParmVarDecl as well. if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) { + if (DiscardResult) + return true; + if (Ctx.getLangOpts().CPlusPlus && !Ctx.getLangOpts().CPlusPlus11 && !DeclType->isIntegralOrEnumerationType()) { return this->emitInvalidDeclRef(cast<DeclRefExpr>(E), @@ -7730,9 +7744,9 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { const unsigned Offset = It->second.Offset; if (IsReference) { assert(classifyPrim(E) == PT_Ptr); - return this->emitGetRefLocal(Offset, E); + return this->emitGetRefLocal(Offset, E) && maybePopPtr(); } - return this->emitGetPtrLocal(Offset, E); + return this->emitGetPtrLocal(Offset, E) && maybePopPtr(); } // Global variables. if (auto GlobalIndex = P.getGlobal(D)) { @@ -7741,10 +7755,11 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { return this->emitGetGlobal(classifyPrim(E), *GlobalIndex, E); if (!Ctx.getLangOpts().CPlusPlus23) return this->emitGetGlobalUnchecked(classifyPrim(E), *GlobalIndex, E); - return this->emitGetRefGlobal(*GlobalIndex, E); + + return this->emitGetRefGlobal(*GlobalIndex, E) && maybePopPtr(); } - return this->emitGetPtrGlobal(*GlobalIndex, E); + return this->emitGetPtrGlobal(*GlobalIndex, E) && maybePopPtr(); } // In case we need to re-visit a declaration. @@ -7774,8 +7789,8 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { auto [Offset, IsPtr] = It->second; if (IsPtr) - return this->emitGetThisFieldPtr(Offset, E); - return this->emitGetPtrThisField(Offset, E); + return this->emitGetThisFieldPtr(Offset, E) && maybePopPtr(); + return this->emitGetPtrThisField(Offset, E) && maybePopPtr(); } } @@ -7786,11 +7801,14 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { } if (const auto *BD = dyn_cast<BindingDecl>(D)) - return this->visit(BD->getBinding()); + return this->delegate(BD->getBinding()); // Avoid infinite recursion. - if (D == InitializingDecl) + if (D == InitializingDecl) { + if (DiscardResult) + return true; return this->emitDummyPtr(D, E); + } // Try to lazily visit (or emit dummy pointers for) declarations // we haven't seen yet. @@ -7804,6 +7822,9 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { DeclType.isConstant(Ctx.getASTContext()) && !VD->isWeak() && VD->evaluateValue()) return revisit(VD, /*IsConstexprUnknown=*/false); + + if (DiscardResult) + return true; return this->emitDummyPtr(D, E); } @@ -7849,6 +7870,8 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) { /*InitializerFailed=*/true, E); } + if (DiscardResult) + return true; return this->emitDummyPtr( D, E, Ctx.getLangOpts().CPlusPlus23 && DeclType->isReferenceType()); } diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index e862d945e020f..83dac57353944 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -281,7 +281,17 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo Info) { if (!Ptr.isLive() && !Ptr.isTemporary()) return false; - EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext())); + // If the variable of this pointer is being evaluated when returning + // its value, mark it as constexpr-unknown. + APValue V = Ptr.toAPValue(Ctx.getASTContext()); + if (const Descriptor *DeclDesc = Ptr.getDeclDesc(); + DeclDesc && S.EvaluatingDecl && + DeclDesc->asVarDecl() == S.EvaluatingDecl && + S.getLangOpts().CPlusPlus23 && + S.EvaluatingDecl->getType()->isReferenceType()) { + V.setConstexprUnknown(true); + } + EvalResult.takeValue(std::move(V)); } return true; diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index ed640f7325f7e..aa2dffc2b982a 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -2052,6 +2052,14 @@ inline bool GetRefLocal(InterpState &S, CodePtr OpPC, uint32_t I) { inline bool GetRefGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { Block *B = S.P.getGlobal(I); + // If we're currently evaluating this variable, use that in-flight value. + // It will otherwise be diagnosed as non-initialized reference and we will + // complain about a missing initializer. + if (S.EvaluatingDecl && B->getDescriptor()->asVarDecl() == S.EvaluatingDecl) { + S.Stk.push<Pointer>(B); + return true; + } + if (isConstexprUnknown(B)) { S.Stk.push<Pointer>(B); return true; diff --git a/clang/test/SemaCXX/constant-expression-p2280r4.cpp b/clang/test/SemaCXX/constant-expression-p2280r4.cpp index bb5499e57ac78..77a9891e6620c 100644 --- a/clang/test/SemaCXX/constant-expression-p2280r4.cpp +++ b/clang/test/SemaCXX/constant-expression-p2280r4.cpp @@ -205,8 +205,8 @@ int f() { namespace uninit_reference_used { int y; constexpr int &r = r; // expected-error {{must be initialized by a constant expression}} \ - // expected-note {{initializer of 'r' is not a constant expression}} \ - // expected-note {{declared here}} + // expected-note {{initializer of 'r' is not a constant expression}} \ + // expected-note {{declared here}} constexpr int &rr = (rr, y); constexpr int &g() { int &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \ @@ -224,12 +224,12 @@ namespace uninit_reference_used { // expected-note {{in call to 'g2()'}} constexpr int &g3() { int &x = (x,y); // expected-warning{{left operand of comma operator has no effect}} \ - // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \ - // nointerpreter-note {{use of reference outside its lifetime is not allowed in a constant expression}} + // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \ + // expected-note {{use of reference outside its lifetime is not allowed in a constant expression}} return x; } - constexpr int &gg3 = g3(); // nointerpreter-error {{must be initialized by a constant expression}} \ - // nointerpreter-note {{in call to 'g3()'}} + constexpr int &gg3 = g3(); // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{in call to 'g3()'}} typedef decltype(sizeof(1)) uintptr_t; constexpr uintptr_t g4() { uintptr_t * &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
