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); } } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
