[clang] e0316c1 - Revert "[clang][bytecode] Stop relying on `CheckEvaluationResult()` (… (#226637)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 25 22:43:29 PDT 2026
Author: Timm Baeder
Date: 2026-09-26T05:43:22Z
New Revision: e0316c1b4762263caa49e3c41ddde752a2b6b775
URL: https://github.com/llvm/llvm-project/commit/e0316c1b4762263caa49e3c41ddde752a2b6b775
DIFF: https://github.com/llvm/llvm-project/commit/e0316c1b4762263caa49e3c41ddde752a2b6b775.diff
LOG: Revert "[clang][bytecode] Stop relying on `CheckEvaluationResult()` (… (#226637)
…#186045)"
This reverts commit 55b498466a7b2620d09fcdf1b2300f71a35f6d8b.
This breaks two msan builders and reproducing the failure locally takes
forever.
Added:
Modified:
clang/lib/AST/ByteCode/ByteCodeEmitter.h
clang/lib/AST/ByteCode/Compiler.cpp
clang/lib/AST/ByteCode/Context.cpp
clang/lib/AST/ByteCode/Disasm.cpp
clang/lib/AST/ByteCode/EvalEmitter.cpp
clang/lib/AST/ByteCode/EvalEmitter.h
clang/lib/AST/ByteCode/EvaluationResult.cpp
clang/lib/AST/ByteCode/EvaluationResult.h
clang/lib/AST/ByteCode/Interp.cpp
clang/lib/AST/ByteCode/InterpBuiltinObjectSize.cpp
clang/lib/AST/ByteCode/Pointer.cpp
clang/lib/AST/ByteCode/Pointer.h
clang/lib/AST/ExprConstShared.h
clang/lib/AST/ExprConstant.cpp
clang/test/AST/ByteCode/builtin-functions.cpp
clang/test/AST/ByteCode/codegen-constexpr-unknown.cpp
clang/test/AST/ByteCode/references.cpp
clang/test/CodeGenCXX/global-init.cpp
clang/test/SemaCXX/PR19955.cpp
clang/test/SemaCXX/cxx2c-expansion-stmts.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
index 4174a26b80464..57d967c2b11cd 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
@@ -68,7 +68,6 @@ class ByteCodeEmitter {
/// We're always emitting bytecode.
bool isActive() const { return true; }
bool checkingForUndefinedBehavior() const { return false; }
- bool constantFolding() const { return false; }
/// Callback for local registration.
Local createLocal(const Descriptor *D);
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 631a91519974d..81c8fb0b9f17d 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -3579,10 +3579,6 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
bool IsStatic = E->getStorageDuration() == SD_Static;
if (IsStatic ||
(ExtendingDecl && Context::shouldBeGloballyIndexed(ExtendingDecl))) {
-
- if (this->constantFolding())
- return false;
-
UnsignedOrNone GlobalIndex = P.createGlobal(E, Inner->getType());
if (!GlobalIndex)
return false;
@@ -5495,8 +5491,6 @@ const Function *Compiler<Emitter>::getFunction(const FunctionDecl *FD) {
template <class Emitter>
bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) {
- assert(E);
- assert(!E->getType().isNull());
LocalScope<Emitter> RootScope(this, ScopeKind::FullExpression);
auto maybeDestroyLocals = [&]() -> bool {
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index 9cdb2725a9204..61ee2d255e905 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -76,7 +76,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
size_t StackSizeBefore = Stk.size();
Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
- auto Res = C.interpretExpr(E);
+ auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());
if (Res.isInvalid()) {
C.cleanup();
@@ -96,6 +96,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
}
Result = Res.stealAPValue();
+
return true;
}
@@ -104,7 +105,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,
++EvalID;
bool Recursing = !Stk.empty();
size_t StackSizeBefore = Stk.size();
- Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc, Kind);
+ Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/false,
/*DestroyToplevelScope=*/true);
@@ -136,8 +137,8 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
Compiler<EvalEmitter> C(*this, *P, Parent, Stk, FrameAlloc);
bool CheckGlobalInitialized =
+ shouldBeGloballyIndexed(VD) &&
(VD->getType()->isRecordType() || VD->getType()->isArrayType());
-
auto Res = C.interpretDecl(VD, Init, CheckGlobalInitialized);
if (Res.isInvalid()) {
C.cleanup();
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp
index 22d0828df423f..98fbac4dd0eec 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -643,6 +643,9 @@ LLVM_DUMP_METHOD void EvaluationResult::dump() const {
OS << "Invalid\n";
} else {
OS << "Value: ";
- Value.dump(OS, Ctx.getASTContext());
+#ifndef NDEBUG
+ assert(Ctx);
+ Value.dump(OS, Ctx->getASTContext());
+#endif
}
}
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index ec7550eb4cc17..0e8b6f9dce56f 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -18,14 +18,12 @@ using namespace clang;
using namespace clang::interp;
EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
- InterpStack &Stk, FrameAllocator &FA,
- ConstantExprKind ConstexprKind)
- : Ctx(Ctx), P(P), S(Parent, P, Stk, FA, Ctx, this), EvalResult(Ctx),
- ConstexprKind(ConstexprKind) {}
+ InterpStack &Stk, FrameAllocator &FA)
+ : Ctx(Ctx), P(P), S(Parent, P, Stk, FA, Ctx, this), EvalResult(&Ctx) {}
EvalEmitter::EvalEmitter(Context &Ctx, Program &P, Expr::EvalStatus &Status,
InterpStack &Stk, FrameAllocator &FA)
- : Ctx(Ctx), P(P), S(Status, P, Stk, FA, Ctx, this), EvalResult(Ctx) {}
+ : Ctx(Ctx), P(P), S(Status, P, Stk, FA, Ctx, this), EvalResult(&Ctx) {}
/// Clean up all our resources. This needs to done in failed evaluations before
/// we call InterpStack::clear(), because there might be a Pointer on the stack
@@ -242,18 +240,6 @@ template <PrimType OpType> bool EvalEmitter::emitRet(SourceInfo Info) {
return true;
}
-template <> bool EvalEmitter::emitRet<PT_MemberPtr>(SourceInfo Info) {
- if (!isActive())
- return true;
-
- const MemberPointer &MP = S.Stk.pop<MemberPointer>();
- if (!EvalResult.checkMemberPointer(S, MP, Info, ConstexprKind))
- return false;
-
- EvalResult.takeValue(MP.toAPValue(Ctx.getASTContext()));
- return true;
-}
-
template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo Info) {
if (!isActive())
return true;
@@ -265,7 +251,6 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo Info) {
if (!EvalResult.checkDynamicAllocations(S, Ptr, Info))
return false;
-
if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
return false;
@@ -273,9 +258,6 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo Info) {
if (Ptr.isFunctionPointer()) {
if (ConvertResultToRValue && Ptr.asFunctionPointer().Func->getDecl())
return false;
- if (!EvalResult.checkFunctionPointer(S, Ptr, Info, ConstexprKind))
- return false;
-
EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
return true;
}
@@ -294,39 +276,37 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(SourceInfo Info) {
Ptr.block()->getEvalID() != Ctx.getEvalID())
return false;
- if (!EvalResult.checkLValueFields(S, Ptr, Info, ConstexprKind))
- return false;
-
if (std::optional<APValue> V =
Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
EvalResult.takeValue(std::move(*V));
+ } else {
+ return false;
+ }
+ } else {
+ // If this is pointing to a local variable, just return
+ // the result, even if the pointer is dead.
+ // This will later be diagnosed by CheckLValueConstantExpression.
+ if (Ptr.isBlockPointer() && !Ptr.block()->isStatic()) {
+ EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
return true;
}
- return false;
- }
-
- // Return as lvalue.
- if (!EvalResult.checkLValue(S, Ptr, Info, ConstexprKind))
- return false;
- if (!Ptr.isLive() && !Ptr.isTemporary())
- return false;
+ if (!Ptr.isLive() && !Ptr.isTemporary())
+ return false;
- if (const Descriptor *DeclDesc = Ptr.getDeclDesc();
- DeclDesc && S.EvaluatingDecl &&
- ((DeclDesc->asVarDecl() == S.EvaluatingDecl &&
+ // 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()) ||
- DeclDesc->IsConstexprUnknown)) {
- S.FFDiag(Info, diag::note_constexpr_var_init_non_constant, 1)
- << DeclDesc->asVarDecl();
- S.Note(DeclDesc->asVarDecl()->getLocation(), diag::note_declared_at);
-
- return false;
+ S.EvaluatingDecl->getType()->isReferenceType()) {
+ V.setConstexprUnknown(true);
+ }
+ EvalResult.takeValue(std::move(V));
}
- APValue V = Ptr.toAPValue(Ctx.getASTContext());
- EvalResult.takeValue(std::move(V));
return true;
}
@@ -342,8 +322,6 @@ bool EvalEmitter::emitRetValue(SourceInfo Info) {
return false;
if (CheckFullyInitialized && !EvalResult.checkFullyInitialized(S, Ptr))
return false;
- if (!EvalResult.checkLValueFields(S, Ptr, Info, ConstexprKind))
- return false;
if (std::optional<APValue> APV =
Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h b/clang/lib/AST/ByteCode/EvalEmitter.h
index 70ad775e84f81..069758615012d 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.h
+++ b/clang/lib/AST/ByteCode/EvalEmitter.h
@@ -37,14 +37,9 @@ class EvalEmitter : public SourceMapper {
using PtrCallback =
llvm::function_ref<bool(InterpState &S, CodePtr OpPC, const Pointer &)>;
- EvaluationResult interpretExpr(const Expr *E) {
- return interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue(),
- /*DestroyToplevelScope=*/false);
- }
-
- EvaluationResult interpretExpr(const Expr *E, bool ConvertResultToRValue,
+ EvaluationResult interpretExpr(const Expr *E,
+ bool ConvertResultToRValue = false,
bool DestroyToplevelScope = false);
-
EvaluationResult interpretDecl(const VarDecl *VD, const Expr *Init,
bool CheckFullyInitialized);
EvaluationResult interpretDestructor(const VarDecl *VD, const APValue &Value);
@@ -66,14 +61,9 @@ class EvalEmitter : public SourceMapper {
/// Returns the source location of the current opcode.
SourceInfo getSource(CodePtr PC) const override { return CurrentSource; }
- bool constantFolding() const {
- return S.EvalMode == EvaluationMode::ConstantFold;
- }
-
protected:
EvalEmitter(Context &Ctx, Program &P, State &Parent, InterpStack &Stk,
- FrameAllocator &FrameAlloc,
- ConstantExprKind ConstexprKind = ConstantExprKind::Normal);
+ FrameAllocator &FrameAlloc);
EvalEmitter(Context &Ctx, Program &P, Expr::EvalStatus &Status,
InterpStack &Stk, FrameAllocator &FrameAlloc);
@@ -130,7 +120,6 @@ class EvalEmitter : public SourceMapper {
InterpState S;
/// Location to write the result to.
EvaluationResult EvalResult;
- ConstantExprKind ConstexprKind = ConstantExprKind::Normal;
/// Whether the result should be converted to an RValue.
bool ConvertResultToRValue = false;
/// Whether we should check if the result has been fully
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index 30976fcf1d521..09b1eb822b13e 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.cpp
+++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp
@@ -7,14 +7,9 @@
//===----------------------------------------------------------------------===//
#include "EvaluationResult.h"
-#include "../ExprConstShared.h"
#include "InterpState.h"
#include "Pointer.h"
#include "Record.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include <iterator>
@@ -22,19 +17,6 @@
namespace clang {
namespace interp {
-QualType EvaluationResult::getStorageType() const {
- if (const auto *E = Source.asExpr()) {
- if (E->isPRValue())
- return E->getType();
-
- return Ctx.getASTContext().getLValueReferenceType(E->getType());
- }
-
- if (const auto *D = Source.asValueDecl())
- return D->getType();
- return QualType();
-}
-
static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,
const FieldDecl *SubObjDecl) {
assert(SubObjDecl && "Subobject declaration does not exist");
@@ -263,10 +245,9 @@ static void collectBlocks(PtrView Ptr,
bool EvaluationResult::checkDynamicAllocations(InterpState &S,
const Pointer &Ptr,
- SourceInfo Info) const {
+ SourceInfo Info) {
if (!Ptr.isBlockPointer())
return true;
-
// Collect all blocks that this pointer (transitively) points to and
// return false if any of them is a dynamic block.
llvm::SmallPtrSet<const Block *, 4> Blocks;
@@ -290,366 +271,5 @@ bool EvaluationResult::checkDynamicAllocations(InterpState &S,
return true;
}
-static bool isGlobalLValue(const Pointer &Ptr) {
- if (Ptr.isDynamic())
- return true;
- if (Ptr.isTypeidPointer())
- return true;
-
- return ::isGlobalLValue(Ptr.getRootValueDecl(), Ptr.getRootExpr());
-}
-
-/// Check if the given function pointer can be returned from an evaluation.
-static bool checkFunctionPtr(InterpState &S, const Pointer &Ptr,
- QualType PtrType, SourceInfo Info,
- ConstantExprKind ConstexprKind) {
- assert(Ptr.isFunctionPointer());
- const FunctionPointer &FuncPtr = Ptr.asFunctionPointer();
-
- if (!FuncPtr.Func)
- return true;
-
- const FunctionDecl *FD = FuncPtr.Func->getDecl();
- // E.g. ObjC block pointers.
- if (!FD)
- return true;
- if (FD->isImmediateFunction()) {
- S.FFDiag(Info, diag::note_consteval_address_accessible)
- << !PtrType->isAnyPointerType();
- S.Note(FD->getLocation(), diag::note_declared_at);
- return false;
- }
-
- // __declspec(dllimport) must be handled very carefully:
- // We must never initialize an expression with the thunk in C++.
- // Doing otherwise would allow the same id-expression to yield
- //
diff erent addresses for the same function in
diff erent translation
- // units. However, this means that we must dynamically initialize the
- // expression with the contents of the import address table at runtime.
- //
- // The C language has no notion of ODR; furthermore, it has no notion of
- // dynamic initialization. This means that we are permitted to
- // perform initialization with the address of the thunk.
- if (S.getLangOpts().CPlusPlus && !isForManglingOnly(ConstexprKind) &&
- FD->hasAttr<DLLImportAttr>())
- // FIXME: Diagnostic!
- return false;
- return true;
-}
-
-static bool lvalFields(InterpState &S, const ASTContext &Ctx, PtrView Ptr,
- QualType PtrType, SourceInfo Info,
- ConstantExprKind ConstexprKind,
- llvm::SmallPtrSet<const Block *, 4> &CheckedBlocks);
-static bool lval(InterpState &S, const ASTContext &Ctx, const Pointer &Ptr,
- QualType PtrType, SourceInfo Info,
- ConstantExprKind ConstexprKind,
- llvm::SmallPtrSet<const Block *, 4> &CheckedBlocks) {
- if (Ptr.isFunctionPointer())
- return checkFunctionPtr(S, Ptr, PtrType, Info, ConstexprKind);
-
- if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer())
- return true;
-
- const Expr *BaseE = Ptr.getRootExpr();
- const ValueDecl *BaseVD = Ptr.getRootValueDecl();
- assert(BaseE || BaseVD);
- bool IsReferenceType = PtrType->isReferenceType();
- bool IsSubObj = !Ptr.isRoot() || (Ptr.inArray() && !Ptr.isArrayRoot());
-
- if (!isGlobalLValue(Ptr)) {
- if (S.getLangOpts().CPlusPlus11) {
- S.FFDiag(Info, diag::note_constexpr_non_global, 1)
- << IsReferenceType << IsSubObj << !!BaseVD << BaseVD;
- const VarDecl *VarD = dyn_cast_if_present<VarDecl>(BaseVD);
- if (VarD && VarD->isConstexpr()) {
- // Non-static local constexpr variables have unintuitive semantics:
- // constexpr int a = 1;
- // constexpr const int *p = &a;
- // ... is invalid because the address of 'a' is not constant. Suggest
- // adding a 'static' in this case.
- S.Note(VarD->getLocation(), diag::note_constexpr_not_static)
- << VarD
- << FixItHint::CreateInsertion(VarD->getBeginLoc(), "static ");
- } else {
- if (BaseVD)
- S.Note(BaseVD->getLocation(), diag::note_declared_at);
- else if (BaseE)
- S.Note(BaseE->getExprLoc(), diag::note_constexpr_temporary_here);
- }
- } else {
- S.FFDiag(Info);
- }
- return false;
- }
-
- if (const auto *VD = dyn_cast_if_present<VarDecl>(BaseVD)) {
- // Check if this is a thread-local variable.
- if (VD->getTLSKind()) {
- // FIXME: Diagnostic!
- return false;
- }
-
- // A dllimport variable never acts like a constant, unless we're
- // evaluating a value for use only in name mangling, and unless it's a
- // static local. For the latter case, we'd still need to evaluate the
- // constant expression in case we're inside a (inlined) function.
- if (!isForManglingOnly(ConstexprKind) && VD->hasAttr<DLLImportAttr>() &&
- !VD->isStaticLocal())
- return false;
-
- // Address of a managed variable is never a constant expression.
- if (S.getLangOpts().CUDA && VD->hasAttr<HIPManagedAttr>())
- return false;
-
- // In CUDA/HIP device compilation, only device side variables have
- // constant addresses.
- if (S.getLangOpts().CUDA && S.getLangOpts().CUDAIsDevice &&
- Ctx.CUDAConstantEvalCtx.NoWrongSidedVars) {
- if ((!VD->hasAttr<CUDADeviceAttr>() && !VD->hasAttr<CUDAConstantAttr>() &&
- !VD->getType()->isCUDADeviceBuiltinSurfaceType() &&
- !VD->getType()->isCUDADeviceBuiltinTextureType()))
- return false;
- }
-
- return true;
- }
-
- if (const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(BaseE)) {
- QualType TempType = Ptr.getType();
-
- if (TempType.isDestructedType()) {
- S.FFDiag(MTE->getExprLoc(),
- diag::note_constexpr_unsupported_temporary_nontrivial_dtor)
- << TempType;
- return false;
- }
-
- if (Ptr.getFieldDesc()->isPrimitive() &&
- Ptr.getFieldDesc()->getPrimType() == PT_Ptr) {
- // Recurse!
- Pointer Pointee = Ptr.deref<Pointer>();
- if (!Pointee.isBlockPointer() ||
- CheckedBlocks.insert(Pointee.block()).second) {
- if (!lval(S, Ctx, Pointee, Pointee.getType(),
- Ptr.getDeclDesc()->getLoc(), ConstexprKind, CheckedBlocks))
- return false;
- }
- } else {
- if (!lvalFields(S, Ctx, Ptr.view(), TempType, Info, ConstexprKind,
- CheckedBlocks))
- return false;
- }
- }
-
- return true;
-}
-
-static bool lvalFields(InterpState &S, const ASTContext &Ctx, PtrView Ptr,
- QualType PtrType, SourceInfo Info,
- ConstantExprKind ConstexprKind,
- llvm::SmallPtrSet<const Block *, 4> &CheckedBlocks) {
- const Descriptor *FieldDesc = Ptr.getFieldDesc();
- if (const Record *R = Ptr.getRecord()) {
- if (!R->hasPtrField())
- return true;
-
- for (const Record::Base &B : R->bases()) {
- if (!B.R->hasPtrField())
- continue;
-
- PtrView BasePtr = Ptr.atField(B.Offset);
- if (!lvalFields(S, Ctx, BasePtr, B.Desc->getType(), Info, ConstexprKind,
- CheckedBlocks))
- return false;
- }
-
- for (const Record::Field &F : R->fields()) {
- PtrView FieldPtr = Ptr.atField(F.Offset);
- if (!isOrHasPtr(F.Desc))
- continue;
-
- if (F.Desc->isPrimitive() && F.Desc->getPrimType() == PT_Ptr) {
- if (!FieldPtr.isLive())
- return false;
-
- Pointer Pointee = FieldPtr.deref<Pointer>();
- if (!Pointee.isBlockPointer() ||
- CheckedBlocks.insert(Pointee.block()).second) {
- QualType FieldType = F.Decl->getType();
- if (!lval(S, Ctx, Pointee, FieldType, Info, ConstexprKind,
- CheckedBlocks))
- return false;
- }
- } else {
- if (!lvalFields(S, Ctx, FieldPtr, F.Decl->getType(), Info,
- ConstexprKind, CheckedBlocks))
- return false;
- }
- }
-
- for (const Record::Base &B : R->virtual_bases()) {
- if (!B.R->hasPtrField())
- continue;
- PtrView BasePtr = Ptr.atField(B.Offset);
- if (!lvalFields(S, Ctx, BasePtr, B.Desc->getType(), Info, ConstexprKind,
- CheckedBlocks))
- return false;
- }
- return true;
- }
-
- if (FieldDesc->isPrimitiveArray() && FieldDesc->getPrimType() == PT_Ptr) {
- for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
- if (!Ptr.isLive())
- return false;
- Pointer Pointee = Ptr.elem<Pointer>(I);
-
- if (!Pointee.isBlockPointer() ||
- CheckedBlocks.insert(Pointee.block()).second) {
- if (!lval(S, Ctx, Pointee, FieldDesc->getElemQualType(), Info,
- ConstexprKind, CheckedBlocks))
- return false;
- }
- }
- return true;
- }
-
- if (FieldDesc->isCompositeArray()) {
- if (FieldDesc->ElemRecord && !FieldDesc->ElemRecord->hasPtrField())
- return true;
-
- for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
- PtrView Elem = Ptr.atIndex(I).narrow();
- if (!lvalFields(S, Ctx, Elem, FieldDesc->getElemQualType(), Info,
- ConstexprKind, CheckedBlocks))
- return false;
- }
- return true;
- }
- if (FieldDesc->isPrimitive() && FieldDesc->getPrimType() == PT_MemberPtr) {
- MemberPointer MP = Ptr.deref<MemberPointer>();
- if (!EvaluationResult::checkMemberPointer(S, MP, Info, ConstexprKind))
- return false;
- }
-
- return true;
-}
-
-/// Toplevel accessor to check all lvalue fields.
-bool EvaluationResult::checkLValueFields(InterpState &S, const Pointer &Ptr,
- SourceInfo Info,
- ConstantExprKind ConstexprKind) const {
- if (!Ptr.isBlockPointer())
- return true;
-
- QualType SourceType = getStorageType();
- llvm::SmallPtrSet<const Block *, 4> CheckedBlocks;
-
- return lvalFields(S, Ctx.getASTContext(), Ptr.view(), SourceType, Info,
- ConstexprKind, CheckedBlocks);
-}
-
-bool EvaluationResult::checkLValue(InterpState &S, const Pointer &Ptr,
- SourceInfo Info,
- ConstantExprKind ConstexprKind) const {
- QualType SourceType = getStorageType();
- if (Ptr.isFunctionPointer())
- return checkFunctionPtr(S, Ptr, SourceType, Info, ConstexprKind);
-
- if (Ptr.isZero())
- return true;
-
- bool IsReferenceType = SourceType->isReferenceType();
- if (Ptr.isTypeidPointer()) {
- if (isTemplateArgument(ConstexprKind)) {
- S.FFDiag(Info, diag::note_constexpr_invalid_template_arg)
- << IsReferenceType << /*IsSubObj=*/false << /*InvalidBaseKind=*/0;
- return false;
- }
- return true;
- }
-
- if (Ptr.isStringPointer()) {
- // Additional restrictions apply in a template argument. We only enforce the
- // C++20 restrictions here; additional syntactic and semantic restrictions
- // are applied elsewhere.
- if (isTemplateArgument(ConstexprKind)) {
- bool IsSubObj = Ptr.asStringPointer().Decayed || Ptr.getIndex() != 0;
- int InvalidBaseKind = -1;
- StringRef Ident;
- const Expr *BaseE = Ptr.asStringPointer().Base;
- if (isa_and_nonnull<StringLiteral>(BaseE))
- InvalidBaseKind = 1;
- else if (const auto *PE = dyn_cast_if_present<PredefinedExpr>(BaseE)) {
- InvalidBaseKind = 3;
- Ident = PE->getIdentKindName();
- }
-
- if (InvalidBaseKind != -1) {
- S.FFDiag(Info, diag::note_constexpr_invalid_template_arg)
- << IsReferenceType << IsSubObj << InvalidBaseKind << Ident;
- return false;
- }
- }
- return true;
- }
-
- if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer())
- return true;
-
- // Additional restrictions apply in a template argument. We only enforce the
- // C++20 restrictions here; additional syntactic and semantic restrictions
- // are applied elsewhere.
- if (isTemplateArgument(ConstexprKind)) {
- const Expr *BaseE = Ptr.getRootExpr();
- const ValueDecl *BaseVD = Ptr.getRootValueDecl();
- assert(BaseE || BaseVD);
- if (isa_and_nonnull<MaterializeTemporaryExpr>(BaseE) ||
- isa_and_nonnull<LifetimeExtendedTemporaryDecl>(BaseVD)) {
- bool IsSubObj = !Ptr.isRoot() || (Ptr.inArray() && !Ptr.isArrayRoot());
- S.FFDiag(Info, diag::note_constexpr_invalid_template_arg)
- << IsReferenceType << IsSubObj << 2;
- return false;
- }
- }
-
- llvm::SmallPtrSet<const Block *, 4> CheckedBlocks;
- if (!lval(S, Ctx.getASTContext(), Ptr, SourceType, Info, ConstexprKind,
- CheckedBlocks)) {
- return false;
- }
-
- return true;
-}
-
-bool EvaluationResult::checkMemberPointer(InterpState &S,
- const MemberPointer &MemberPtr,
- SourceInfo Info,
- ConstantExprKind ConstexprKind) {
- const CXXMethodDecl *MD = MemberPtr.getMemberFunction();
- if (!MD)
- return true;
-
- if (MD->isImmediateFunction()) {
- S.FFDiag(Info, diag::note_consteval_address_accessible)
- << /*pointer=*/false;
- S.Note(MD->getLocation(), diag::note_declared_at);
- return false;
- }
-
- if (isForManglingOnly(ConstexprKind) || MD->isVirtual() ||
- !MD->hasAttr<DLLImportAttr>()) {
- return true;
- }
- return false;
-}
-
-bool EvaluationResult::checkFunctionPointer(
- InterpState &S, const Pointer &Ptr, SourceInfo Info,
- ConstantExprKind ConstexprKind) const {
- return checkFunctionPtr(S, Ptr, getStorageType(), Info, ConstexprKind);
-}
-
} // namespace interp
} // namespace clang
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.h b/clang/lib/AST/ByteCode/EvaluationResult.h
index 948f822e69142..b8d8ddf981f5a 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.h
+++ b/clang/lib/AST/ByteCode/EvaluationResult.h
@@ -18,7 +18,6 @@ namespace clang {
namespace interp {
class EvalEmitter;
class Context;
-class MemberPointer;
class Pointer;
class SourceInfo;
class InterpState;
@@ -39,7 +38,9 @@ class EvaluationResult final {
};
private:
- const Context &Ctx;
+#ifndef NDEBUG
+ const Context *Ctx = nullptr;
+#endif
APValue Value;
ResultKind Kind = Empty;
DeclOrExpr Source = nullptr;
@@ -62,14 +63,17 @@ class EvaluationResult final {
Kind = Valid;
}
- QualType getStorageType() const;
-
public:
- EvaluationResult(const Context &Ctx) : Ctx(Ctx) {}
+#ifndef NDEBUG
+ EvaluationResult(const Context *Ctx) : Ctx(Ctx) {}
+#else
+ EvaluationResult(const Context *Ctx) {}
+#endif
bool empty() const { return Kind == Empty; }
bool isInvalid() const { return Kind == Invalid; }
+ /// Moves the APValue containing the evaluation result to the caller.
APValue stealAPValue() { return std::move(Value); }
/// Check that all subobjects of the given pointer have been initialized.
@@ -77,23 +81,7 @@ class EvaluationResult final {
/// Check that none of the blocks the given pointer (transitively) points
/// to are dynamically allocated.
bool checkDynamicAllocations(InterpState &S, const Pointer &Ptr,
- SourceInfo Info) const;
-
- /// Check the given pointer as an lvalue, i.e. make sure it's a global
- /// lvalue and diagnose if it's not.
- bool checkLValue(InterpState &S, const Pointer &Ptr, SourceInfo Info,
- ConstantExprKind ConstexprKind) const;
- /// Check all fields of the given pointer.
- bool checkLValueFields(InterpState &S, const Pointer &Ptr, SourceInfo Info,
- ConstantExprKind ConstexprKind) const;
-
- /// Check if the given member pointer can be returned from an evaluation.
- static bool checkMemberPointer(InterpState &S, const MemberPointer &MemberPtr,
- SourceInfo Info,
- ConstantExprKind ConstexprKind);
- /// Check if the given function pointer can be returned from an evaluation.
- bool checkFunctionPointer(InterpState &S, const Pointer &Ptr, SourceInfo Info,
- ConstantExprKind ConstexprKind) const;
+ SourceInfo Info);
QualType getSourceType() const {
if (const auto *D = Source.asValueDecl())
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index aa47b6115eb27..f885c0dc9cdb2 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -875,8 +875,6 @@ static bool CheckLifetime(InterpState &S, CodePtr OpPC, Lifetime LT,
}
static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
- if (!Ptr.isBlockPointer())
- return true;
return CheckLifetime(S, OpPC, Ptr.getLifetime(), Ptr.block(), AK);
}
@@ -1098,7 +1096,7 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckMutable(S, OpPC, Ptr.view()))
return false;
}
- if (!S.inConstantContext() && isConstexprUnknown(Ptr))
+ if (Ptr.isConstexprUnknown())
return false;
return true;
}
diff --git a/clang/lib/AST/ByteCode/InterpBuiltinObjectSize.cpp b/clang/lib/AST/ByteCode/InterpBuiltinObjectSize.cpp
index 41b347150886f..ec3a7af4e1e13 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltinObjectSize.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltinObjectSize.cpp
@@ -352,7 +352,7 @@ computeOpaqueSize(const ASTContext &ASTCtx, const Pointer &Ptr,
return TypeSize.getQuantity();
// Check if we need to add the flexible array member size.
- const VarDecl *Base = OP.getBaseVarDecl();
+ const VarDecl *Base = OP.getBaseDecl();
if (!Base)
return TypeSize.getQuantity();
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 22eb7f1e67dd1..0f564306704a6 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -1333,12 +1333,8 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
}
const VarDecl *Pointer::getRootVarDecl() const {
- return dyn_cast_if_present<VarDecl>(getRootValueDecl());
-}
-
-const ValueDecl *Pointer::getRootValueDecl() const {
if (isBlockPointer())
- return getDeclDesc()->asValueDecl();
+ return getDeclDesc()->asVarDecl();
if (isOpaquePointer())
return Opaque.getBaseDecl();
return nullptr;
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index c7f0da0951121..207ec06a32a34 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -445,8 +445,7 @@ struct OpaquePointer {
ArrayRef<PointerPathEntry> path() const { return ArrayRef(Path, PathLength); }
bool hasDeclBase() const { return Base.isDecl(); }
- const ValueDecl *getBaseDecl() const { return Base.asValueDecl(); }
- const VarDecl *getBaseVarDecl() const { return Base.asVarDecl(); }
+ const VarDecl *getBaseDecl() const { return Base.asVarDecl(); }
const Expr *getBaseExpr() const { return Base.asExpr(); }
bool hasValidBase() const;
@@ -743,7 +742,6 @@ class Pointer {
}
const VarDecl *getRootVarDecl() const;
- const ValueDecl *getRootValueDecl() const;
const Expr *getRootExpr() const;
[[nodiscard]] Pointer getDeclPtr() const { return Pointer(BS.Pointee); }
@@ -923,7 +921,7 @@ class Pointer {
}
if (isOpaquePointer()) {
- if (const VarDecl *BaseDecl = Opaque.getBaseVarDecl())
+ if (const VarDecl *BaseDecl = Opaque.getBaseDecl())
return BaseDecl->isWeak();
return false;
}
@@ -1000,10 +998,7 @@ class Pointer {
return view().getNumElems();
}
- const Block *block() const {
- assert(isBlockPointer());
- return BS.Pointee;
- }
+ const Block *block() const { return BS.Pointee; }
/// If backed by actual data (i.e. a block or string pointer), return
/// an address to that data.
diff --git a/clang/lib/AST/ExprConstShared.h b/clang/lib/AST/ExprConstShared.h
index 7693ea25592f1..ca3481270605e 100644
--- a/clang/lib/AST/ExprConstShared.h
+++ b/clang/lib/AST/ExprConstShared.h
@@ -14,7 +14,6 @@
#ifndef LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H
#define LLVM_CLANG_LIB_AST_EXPRCONSTSHARED_H
-#include "ByteCode/State.h"
#include "clang/Basic/BuiltinTraits.h"
#include <cstdint>
#include <optional>
@@ -116,46 +115,5 @@ const Expr *ignorePointerCastsAndParens(const Expr *E);
bool isReadByLvalueToRvalueConversion(const CXXRecordDecl *RD);
bool isReadByLvalueToRvalueConversion(QualType T);
-/// Determines whether the given kind of constant expression is only ever
-/// used for name mangling. If so, it's permitted to reference things that we
-/// can't generate code for (in particular, dllimported functions).
-inline bool isForManglingOnly(ConstantExprKind Kind) {
- switch (Kind) {
- case ConstantExprKind::Normal:
- case ConstantExprKind::ClassTemplateArgument:
- case ConstantExprKind::ImmediateInvocation:
- // Note that non-type template arguments of class type are emitted as
- // template parameter objects.
- return false;
-
- case ConstantExprKind::NonClassTemplateArgument:
- return true;
- }
- llvm_unreachable("unknown ConstantExprKind");
-}
-
-inline bool isTemplateArgument(ConstantExprKind Kind) {
- switch (Kind) {
- case ConstantExprKind::Normal:
- case ConstantExprKind::ImmediateInvocation:
- return false;
-
- case ConstantExprKind::ClassTemplateArgument:
- case ConstantExprKind::NonClassTemplateArgument:
- return true;
- }
- llvm_unreachable("unknown ConstantExprKind");
-}
-
-/// Should this call expression be treated as forming an opaque constant?
-inline bool isOpaqueConstantCall(const CallExpr *E) {
- unsigned Builtin = E->getBuiltinCallee();
- return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
- Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
- Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
- Builtin == Builtin::BI__builtin_function_start);
-}
-
-bool isGlobalLValue(const ValueDecl *D, const Expr *E);
#endif
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index dea859382918b..2df754dc9007f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -150,6 +150,37 @@ namespace {
return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E);
}
+ /// Determines whether the given kind of constant expression is only ever
+ /// used for name mangling. If so, it's permitted to reference things that we
+ /// can't generate code for (in particular, dllimported functions).
+ static bool isForManglingOnly(ConstantExprKind Kind) {
+ switch (Kind) {
+ case ConstantExprKind::Normal:
+ case ConstantExprKind::ClassTemplateArgument:
+ case ConstantExprKind::ImmediateInvocation:
+ // Note that non-type template arguments of class type are emitted as
+ // template parameter objects.
+ return false;
+
+ case ConstantExprKind::NonClassTemplateArgument:
+ return true;
+ }
+ llvm_unreachable("unknown ConstantExprKind");
+ }
+
+ static bool isTemplateArgument(ConstantExprKind Kind) {
+ switch (Kind) {
+ case ConstantExprKind::Normal:
+ case ConstantExprKind::ImmediateInvocation:
+ return false;
+
+ case ConstantExprKind::ClassTemplateArgument:
+ case ConstantExprKind::NonClassTemplateArgument:
+ return true;
+ }
+ llvm_unreachable("unknown ConstantExprKind");
+ }
+
/// The bound to claim that an array of unknown bound has.
/// The value in MostDerivedArraySize is undefined in this case. So, set it
/// to an arbitrary value that's likely to loudly break things if it's used.
@@ -1909,30 +1940,31 @@ static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {
return true;
}
+/// Should this call expression be treated as forming an opaque constant?
+static bool IsOpaqueConstantCall(const CallExpr *E) {
+ unsigned Builtin = E->getBuiltinCallee();
+ return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
+ Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
+ Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
+ Builtin == Builtin::BI__builtin_function_start);
+}
+
static bool IsOpaqueConstantCall(const LValue &LVal) {
const auto *BaseExpr =
llvm::dyn_cast_if_present<CallExpr>(LVal.Base.dyn_cast<const Expr *>());
- return BaseExpr && isOpaqueConstantCall(BaseExpr);
+ return BaseExpr && IsOpaqueConstantCall(BaseExpr);
}
static bool IsGlobalLValue(APValue::LValueBase B) {
- if (B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>())
- return true;
-
- return isGlobalLValue(B.dyn_cast<const ValueDecl *>(),
- B.dyn_cast<const Expr *>());
-}
-
-bool isGlobalLValue(const ValueDecl *D, const Expr *E) {
// C++11 [expr.const]p3 An address constant expression is a prvalue core
// constant expression of pointer type that evaluates to...
// ... a null pointer value, or a prvalue core constant expression of type
// std::nullptr_t.
- if (!D && !E)
+ if (!B)
return true;
- if (D) {
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
// ... the address of an object with static storage duration,
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->hasGlobalStorage();
@@ -1944,8 +1976,10 @@ bool isGlobalLValue(const ValueDecl *D, const Expr *E) {
return isa<FunctionDecl, MSGuidDecl, UnnamedGlobalConstantDecl>(D);
}
- assert(E);
+ if (B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>())
+ return true;
+ const Expr *E = B.get<const Expr*>();
switch (E->getStmtClass()) {
default:
return false;
@@ -1968,7 +2002,7 @@ bool isGlobalLValue(const ValueDecl *D, const Expr *E) {
case Expr::ObjCDictionaryLiteralClass:
return cast<ObjCObjectLiteral>(E)->isExpressibleAsConstantInitializer();
case Expr::CallExprClass:
- return isOpaqueConstantCall(cast<CallExpr>(E));
+ return IsOpaqueConstantCall(cast<CallExpr>(E));
// For GCC compatibility, &&label has static storage duration.
case Expr::AddrLabelExprClass:
return true;
@@ -1989,8 +2023,6 @@ bool isGlobalLValue(const ValueDecl *D, const Expr *E) {
// an expression might be a global lvalue.
return true;
}
-
- llvm_unreachable("Unhandled stmt kind in switch with default?");
}
static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
@@ -10604,7 +10636,7 @@ static bool isOneByteCharacterType(QualType T) {
bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
- if (isOpaqueConstantCall(E))
+ if (IsOpaqueConstantCall(E))
return Success(E);
switch (BuiltinOp) {
@@ -21805,8 +21837,12 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
if (!CheckLiteralType(Info, E))
return false;
- if (Info.EnableNewConstInterp)
- return Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result);
+ if (Info.EnableNewConstInterp) {
+ if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
+ return false;
+ return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
+ ConstantExprKind::Normal);
+ }
if (!::Evaluate(Result, Info, E))
return false;
@@ -22007,8 +22043,14 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
CheckedTemporaries CheckedTemps;
if (Info.EnableNewConstInterp) {
- return Info.Ctx.getInterpContext().evaluate(Info, this, Result.Val,
- ConstantExprKind::Normal);
+ if (!Info.Ctx.getInterpContext().evaluate(Info, this, Result.Val,
+ ConstantExprKind::Normal))
+ return false;
+
+ LV.setFrom(Ctx, Result.Val);
+ return CheckLValueConstantExpression(
+ Info, getExprLoc(), Ctx.getLValueReferenceType(getType()), LV,
+ ConstantExprKind::Normal, CheckedTemps);
}
if (!EvaluateLValue(this, LV, Info) || !Info.discardCleanups() ||
@@ -22060,8 +22102,12 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
EvalInfo Info(Ctx, Result, EM);
Info.InConstantContext = true;
- if (Info.EnableNewConstInterp)
- return Info.Ctx.getInterpContext().evaluate(Info, this, Result.Val, Kind);
+ if (Info.EnableNewConstInterp) {
+ if (!Info.Ctx.getInterpContext().evaluate(Info, this, Result.Val, Kind))
+ return false;
+ return CheckConstantExpression(Info, getExprLoc(),
+ getStorageType(Ctx, this), Result.Val, Kind);
+ }
// The type of the object we're initializing is 'const T' for a class NTTP.
QualType T = getType();
@@ -22135,35 +22181,40 @@ bool Expr::EvaluateAsInitializer(const ASTContext &Ctx, const VarDecl *VD,
if (Info.EnableNewConstInterp) {
auto &InterpCtx = Ctx.getInterpContext();
- return InterpCtx.evaluateAsInitializer(Info, VD, this, EStatus.Val);
- }
+ if (!InterpCtx.evaluateAsInitializer(Info, VD, this, EStatus.Val))
+ return false;
- LValue LVal;
- LVal.set(VD);
+ return CheckConstantExpression(Info, DeclLoc, DeclTy, EStatus.Val,
+ ConstantExprKind::Normal);
+ } else {
+ LValue LVal;
+ LVal.set(VD);
- {
- // C++23 [intro.execution]/p5
- // A full-expression is ... an init-declarator ([dcl.decl]) or a
- // mem-initializer.
- // So we need to make sure temporary objects are destroyed after having
- // evaluated the expression (per C++23 [class.temporary]/p4).
- //
- // FIXME: Otherwise this may break test/Modules/pr68702.cpp because the
- // serialization code calls ParmVarDecl::getDefaultArg() which strips the
- // outermost FullExpr, such as ExprWithCleanups.
- FullExpressionRAII Scope(Info);
- if (!EvaluateInPlace(EStatus.Val, Info, LVal, this,
- /*AllowNonLiteralTypes=*/true) ||
- EStatus.HasSideEffects)
- return false;
- }
+ {
+ // C++23 [intro.execution]/p5
+ // A full-expression is ... an init-declarator ([dcl.decl]) or a
+ // mem-initializer.
+ // So we need to make sure temporary objects are destroyed after having
+ // evaluated the expression (per C++23 [class.temporary]/p4).
+ //
+ // FIXME: Otherwise this may break test/Modules/pr68702.cpp because the
+ // serialization code calls ParmVarDecl::getDefaultArg() which strips the
+ // outermost FullExpr, such as ExprWithCleanups.
+ FullExpressionRAII Scope(Info);
+ if (!EvaluateInPlace(EStatus.Val, Info, LVal, this,
+ /*AllowNonLiteralTypes=*/true) ||
+ EStatus.HasSideEffects)
+ return false;
+ }
- // At this point, any lifetime-extended temporaries are completely
- // initialized.
- Info.performLifetimeExtension();
+ // At this point, any lifetime-extended temporaries are completely
+ // initialized.
+ Info.performLifetimeExtension();
+
+ if (!Info.discardCleanups())
+ llvm_unreachable("Unhandled cleanup; missing full expression marker?");
+ }
- if (!Info.discardCleanups())
- llvm_unreachable("Unhandled cleanup; missing full expression marker?");
return CheckConstantExpression(Info, DeclLoc, DeclTy, EStatus.Val,
ConstantExprKind::Normal) &&
CheckMemoryLeaks(Info);
diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index 5d8c0fa2b7b6b..51e1b6cde4779 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -2040,9 +2040,9 @@ namespace WithinLifetime {
constexpr const int &temp = 0; // both-error {{must be initialized by a constant expression}} \
// both-note {{reference to temporary is not a constant expression}} \
// both-note {{temporary created here}} \
- // both-note {{declared here}}
- static_assert(__builtin_is_within_lifetime(&temp)); // both-error {{not an integral constant expression}} \
- // both-note {{initializer of 'temp' is not a constant expression}}
+ // ref-note {{declared here}}
+ static_assert(__builtin_is_within_lifetime(&temp)); // ref-error {{not an integral constant expression}} \
+ // ref-note {{initializer of 'temp' is not a constant expression}}
}
}
diff --git a/clang/test/AST/ByteCode/codegen-constexpr-unknown.cpp b/clang/test/AST/ByteCode/codegen-constexpr-unknown.cpp
index 3d1e31d5292ed..8b70f5a4251ad 100644
--- a/clang/test/AST/ByteCode/codegen-constexpr-unknown.cpp
+++ b/clang/test/AST/ByteCode/codegen-constexpr-unknown.cpp
@@ -21,7 +21,6 @@ void rightscope() {
// CHECK-NEXT: entry:
// CHECK-NEXT: %p = alloca i32
// CHECK-NEXT: store i32 0, ptr %p
-// CHECK-NEXT: ret void
/// In the if expression below, the read from s.i should fail.
diff --git a/clang/test/AST/ByteCode/references.cpp b/clang/test/AST/ByteCode/references.cpp
index 3da3996aaca75..a4a8100f5b31e 100644
--- a/clang/test/AST/ByteCode/references.cpp
+++ b/clang/test/AST/ByteCode/references.cpp
@@ -188,9 +188,10 @@ namespace ReadFromNullBlockPtr {
constexpr S s = {&x}; // both-error {{must be initialized by a constant expression}} \
// both-note {{reference to temporary}} \
// both-note {{created here}} \
- // ref-note {{declared here}}
+ // ref-note {{declared here}} \
+ // expected-note {{created here}}
static_assert(s.t == &x, ""); // both-error {{not an integral constant expression}} \
- // expected-note {{read of dereferenced null pointer}} \
+ // expected-note {{read of temporary is not allowed in a constant expression outside the expression that created the temporary}} \
// ref-note {{initializer of 's' is not a constant expression}}
}
}
diff --git a/clang/test/CodeGenCXX/global-init.cpp b/clang/test/CodeGenCXX/global-init.cpp
index f10f1be4ce95d..52039a5208223 100644
--- a/clang/test/CodeGenCXX/global-init.cpp
+++ b/clang/test/CodeGenCXX/global-init.cpp
@@ -6,14 +6,6 @@
// RUN: | FileCheck -check-prefix CHECK-NOBUILTIN %s
// RUN: %clang_cc1 %std_cxx17- -triple=x86_64-apple-darwin10 -emit-llvm -fexceptions %s -o - | FileCheck %s
-// RUN: %clang_cc1 %std_cxx98-14 -triple=x86_64-apple-darwin10 -emit-llvm -fexceptions %s -o - -fexperimental-new-constant-interpreter | FileCheck %s --check-prefixes=CHECK,PRE17
-// RUN: %clang_cc1 %std_cxx98-14 -triple=x86_64-apple-darwin10 -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s --check-prefixes=CHECK-NOEXC,PRE17
-// RUN: %clang_cc1 %std_cxx98-14 -triple=x86_64-apple-darwin10 -emit-llvm -mframe-pointer=non-leaf %s -o - -fexperimental-new-constant-interpreter \
-// RUN: | FileCheck -check-prefix CHECK-FP %s
-// RUN: %clang_cc1 %std_cxx98-14 -triple=x86_64-apple-darwin10 -emit-llvm %s -o - -fno-builtin -fexperimental-new-constant-interpreter \
-// RUN: | FileCheck -check-prefix CHECK-NOBUILTIN %s
-// RUN: %clang_cc1 %std_cxx17- -triple=x86_64-apple-darwin10 -emit-llvm -fexceptions %s -o - -fexperimental-new-constant-interpreter | FileCheck %s
-
struct A {
A();
~A();
diff --git a/clang/test/SemaCXX/PR19955.cpp b/clang/test/SemaCXX/PR19955.cpp
index 6fa22ab846374..cbbe2fe9af164 100644
--- a/clang/test/SemaCXX/PR19955.cpp
+++ b/clang/test/SemaCXX/PR19955.cpp
@@ -1,8 +1,5 @@
// RUN: %clang_cc1 -triple i686-win32 -verify -std=c++11 %s
// RUN: %clang_cc1 -triple i686-mingw32 -verify -std=c++11 %s
-// RUN: %clang_cc1 -triple i686-win32 -verify -std=c++11 %s -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -triple i686-mingw32 -verify -std=c++11 %s -fexperimental-new-constant-interpreter
-
extern int __attribute__((dllimport)) var;
constexpr int *varp = &var; // expected-error {{must be initialized by a constant expression}}
diff --git a/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp b/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp
index 9045c9b4ae7ae..44189ff31dae8 100644
--- a/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp
+++ b/clang/test/SemaCXX/cxx2c-expansion-stmts.cpp
@@ -799,8 +799,8 @@ void not_constant_expression() {
expected-note {{in instantiation of expansion statement requested here}} \
old-interp-note {{read of variable '[__u0]' whose value is not known}} \
old-interp-note {{declared here}} \
- new-interp-note {{declared here}} \
- new-interp-note {{initializer of '[__u0]' is not a constant expression}}
+ new-interp-note {{temporary created here}} \
+ new-interp-note {{read of temporary is not allowed in a constant expression outside the expression that created the temporary}}
g(x);
}
}
More information about the cfe-commits
mailing list