diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:04 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:11 +0000 |
commit | e3b557809604d036af6e00c60f012c2025b59a5e (patch) | |
tree | 8a11ba2269a3b669601e2fd41145b174008f4da8 /clang/lib/AST/ExprConstant.cpp | |
parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) | |
download | src-e3b557809604d036af6e00c60f012c2025b59a5e.tar.gz src-e3b557809604d036af6e00c60f012c2025b59a5e.zip |
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 688 |
1 files changed, 473 insertions, 215 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9d92c848ccb8..912a210fd254 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -52,13 +52,14 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/APFixedPoint.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/Debug.h" #include "llvm/Support/SaveAndRestore.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include <cstring> #include <functional> +#include <optional> #define DEBUG_TYPE "exprconstant" @@ -68,7 +69,6 @@ using llvm::APInt; using llvm::APSInt; using llvm::APFloat; using llvm::FixedPointSemantics; -using llvm::Optional; namespace { struct LValue; @@ -578,7 +578,7 @@ namespace { /// LambdaCaptureFields - Mapping from captured variables/this to /// corresponding data members in the closure class. - llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields; + llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields; FieldDecl *LambdaThisCaptureField; CallStackFrame(EvalInfo &Info, SourceLocation CallLoc, @@ -592,11 +592,6 @@ namespace { auto LB = Temporaries.lower_bound(KV); if (LB != Temporaries.end() && LB->first == KV) return &LB->second; - // Pair (Key,Version) wasn't found in the map. Check that no elements - // in the map have 'Key' as their key. - assert((LB == Temporaries.end() || LB->first.first != Key) && - (LB == Temporaries.begin() || std::prev(LB)->first.first != Key) && - "Element with key 'Key' found in map"); return nullptr; } @@ -660,6 +655,19 @@ namespace { CallStackFrame &Frame; const LValue *OldThis; }; + + // A shorthand time trace scope struct, prints source range, for example + // {"name":"EvaluateAsRValue","args":{"detail":"<test.cc:8:21, col:25>"}}} + class ExprTimeTraceScope { + public: + ExprTimeTraceScope(const Expr *E, const ASTContext &Ctx, StringRef Name) + : TimeScope(Name, [E, &Ctx] { + return E->getSourceRange().printToString(Ctx.getSourceManager()); + }) {} + + private: + llvm::TimeTraceScope TimeScope; + }; } static bool HandleDestruction(EvalInfo &Info, const Expr *E, @@ -917,10 +925,6 @@ namespace { /// fold (not just why it's not strictly a constant expression)? bool HasFoldFailureDiagnostic; - /// Whether or not we're in a context where the front end requires a - /// constant value. - bool InConstantContext; - /// Whether we're checking that an expression is a potential constant /// expression. If so, do not fail on constructs that could become constant /// later on (such as a use of an undefined global). @@ -976,8 +980,7 @@ namespace { BottomFrame(*this, SourceLocation(), nullptr, nullptr, CallRef()), EvaluatingDecl((const ValueDecl *)nullptr), EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false), - HasFoldFailureDiagnostic(false), InConstantContext(false), - EvalMode(Mode) {} + HasFoldFailureDiagnostic(false), EvalMode(Mode) {} ~EvalInfo() { discardCleanups(); @@ -1036,8 +1039,8 @@ namespace { APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV); - Optional<DynAlloc*> lookupDynamicAlloc(DynamicAllocLValue DA) { - Optional<DynAlloc*> Result; + std::optional<DynAlloc *> lookupDynamicAlloc(DynamicAllocLValue DA) { + std::optional<DynAlloc *> Result; auto It = HeapAllocs.find(DA); if (It != HeapAllocs.end()) Result = &It->second; @@ -1132,7 +1135,7 @@ namespace { if (!HasFoldFailureDiagnostic) break; // We've already failed to fold something. Keep that diagnostic. - LLVM_FALLTHROUGH; + [[fallthrough]]; case EM_ConstantExpression: case EM_ConstantExpressionUnevaluated: setActiveDiagnostic(false); @@ -1219,7 +1222,7 @@ namespace { /// (Foo(), 1) // use noteSideEffect /// (Foo() || true) // use noteSideEffect /// Foo() + 1 // use noteFailure - LLVM_NODISCARD bool noteFailure() { + [[nodiscard]] bool noteFailure() { // Failure when evaluating some expression often means there is some // subexpression whose evaluation was skipped. Therefore, (because we // don't track whether we skipped an expression when unwinding after an @@ -1954,8 +1957,8 @@ static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) { return true; } -/// Should this call expression be treated as a constant? -static bool IsConstantCall(const CallExpr *E) { +/// Should this call expression be treated as a no-op? +static bool IsNoOpCall(const CallExpr *E) { unsigned Builtin = E->getBuiltinCallee(); return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString || Builtin == Builtin::BI__builtin___NSStringMakeConstantString || @@ -2006,7 +2009,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) { case Expr::ObjCBoxedExprClass: return cast<ObjCBoxedExpr>(E)->isExpressibleAsConstantInitializer(); case Expr::CallExprClass: - return IsConstantCall(cast<CallExpr>(E)); + return IsNoOpCall(cast<CallExpr>(E)); // For GCC compatibility, &&label has static storage duration. case Expr::AddrLabelExprClass: return true; @@ -2095,7 +2098,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) { Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here); else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) { // FIXME: Produce a note for dangling pointers too. - if (Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA)) + if (std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA)) Info.Note((*Alloc)->AllocExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here); } @@ -2174,12 +2177,10 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, // assumed to be global here. if (!IsGlobalLValue(Base)) { if (Info.getLangOpts().CPlusPlus11) { - const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); Info.FFDiag(Loc, diag::note_constexpr_non_global, 1) - << IsReferenceType << !Designator.Entries.empty() - << !!VD << VD; - - auto *VarD = dyn_cast_or_null<VarDecl>(VD); + << IsReferenceType << !Designator.Entries.empty() << !!BaseVD + << BaseVD; + auto *VarD = dyn_cast_or_null<VarDecl>(BaseVD); if (VarD && VarD->isConstexpr()) { // Non-static local constexpr variables have unintuitive semantics: // constexpr int a = 1; @@ -2470,6 +2471,7 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) { // A null base expression indicates a null pointer. These are always // evaluatable, and they are false unless the offset is zero. if (!Value.getLValueBase()) { + // TODO: Should a non-null pointer with an offset of zero evaluate to true? Result = !Value.getLValueOffset().isZero(); return true; } @@ -2482,6 +2484,7 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) { } static bool HandleConversionToBool(const APValue &Val, bool &Result) { + // TODO: This function should produce notes if it fails. switch (Val.getKind()) { case APValue::None: case APValue::Indeterminate: @@ -2506,6 +2509,9 @@ static bool HandleConversionToBool(const APValue &Val, bool &Result) { case APValue::LValue: return EvalPointerValueAsBool(Val, Result); case APValue::MemberPointer: + if (Val.getMemberPointerDecl() && Val.getMemberPointerDecl()->isWeak()) { + return false; + } Result = Val.getMemberPointerDecl(); return true; case APValue::Vector: @@ -2636,14 +2642,9 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E, QualType SrcType, const APSInt &Value, QualType DestType, APFloat &Result) { Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1); - APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(), - APFloat::rmNearestTiesToEven); - if (!Info.InConstantContext && St != llvm::APFloatBase::opOK && - FPO.isFPConstrained()) { - Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict); - return false; - } - return true; + llvm::RoundingMode RM = getActiveRoundingMode(Info, E); + APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(), RM); + return checkFloatingPointResult(Info, E, St); } static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, @@ -2743,6 +2744,7 @@ static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E, static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, BinaryOperatorKind Opcode, APSInt RHS, APSInt &Result) { + bool HandleOverflowResult = true; switch (Opcode) { default: Info.FFDiag(E); @@ -2765,14 +2767,14 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, Info.FFDiag(E, diag::note_expr_divide_by_zero); return false; } - Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. APSInt supports // this operation and gives the two's complement result. if (RHS.isNegative() && RHS.isAllOnes() && LHS.isSigned() && LHS.isMinSignedValue()) - return HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), - E->getType()); - return true; + HandleOverflowResult = HandleOverflow( + Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType()); + Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); + return HandleOverflowResult; case BO_Shl: { if (Info.getLangOpts().OpenCL) // OpenCL 6.3j: shift values are effectively % word size of LHS. @@ -3647,9 +3649,9 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, if ((ObjType.isConstQualified() || ObjType.isVolatileQualified()) && ObjType->isRecordType() && Info.isEvaluatingCtorDtor( - Obj.Base, llvm::makeArrayRef(Sub.Entries.begin(), - Sub.Entries.begin() + I)) != - ConstructionPhase::None) { + Obj.Base, + llvm::ArrayRef(Sub.Entries.begin(), Sub.Entries.begin() + I)) != + ConstructionPhase::None) { ObjType = Info.Ctx.getCanonicalType(ObjType); ObjType.removeLocalConst(); ObjType.removeLocalVolatile(); @@ -4129,7 +4131,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal)) return CompleteObject(); } else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) { - Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA); + std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA); if (!Alloc) { Info.FFDiag(E, diag::note_constexpr_access_deleted_object) << AK; return CompleteObject(); @@ -4844,6 +4846,8 @@ enum EvalStmtResult { } static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) { + if (VD->isInvalidDecl()) + return false; // We don't need to evaluate the initializer for a static local. if (!VD->hasLocalStorage()) return true; @@ -5040,8 +5044,10 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info, static bool CheckLocalVariableDeclaration(EvalInfo &Info, const VarDecl *VD) { // An expression E is a core constant expression unless the evaluation of E // would evaluate one of the following: [C++2b] - a control flow that passes - // through a declaration of a variable with static or thread storage duration. - if (VD->isLocalVarDecl() && VD->isStaticLocal()) { + // through a declaration of a variable with static or thread storage duration + // unless that variable is usable in constant expressions. + if (VD->isLocalVarDecl() && VD->isStaticLocal() && + !VD->isUsableInConstantExpressions(Info.Ctx)) { Info.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local) << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD; return false; @@ -5663,13 +5669,15 @@ static const CXXRecordDecl *getBaseClassType(SubobjectDesignator &Designator, } /// Determine the dynamic type of an object. -static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E, - LValue &This, AccessKinds AK) { +static std::optional<DynamicType> ComputeDynamicType(EvalInfo &Info, + const Expr *E, + LValue &This, + AccessKinds AK) { // If we don't have an lvalue denoting an object of class type, there is no // meaningful dynamic type. (We consider objects of non-class type to have no // dynamic type.) if (!checkDynamicType(Info, E, This, AK, true)) - return None; + return std::nullopt; // Refuse to compute a dynamic type in the presence of virtual bases. This // shouldn't happen other than in constant-folding situations, since literal @@ -5681,7 +5689,7 @@ static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E, This.Designator.MostDerivedType->getAsCXXRecordDecl(); if (!Class || Class->getNumVBases()) { Info.FFDiag(E); - return None; + return std::nullopt; } // FIXME: For very deep class hierarchies, it might be beneficial to use a @@ -5714,14 +5722,14 @@ static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E, // 'This', so that object has not yet begun its period of construction and // any polymorphic operation on it results in undefined behavior. Info.FFDiag(E); - return None; + return std::nullopt; } /// Perform virtual dispatch. static const CXXMethodDecl *HandleVirtualDispatch( EvalInfo &Info, const Expr *E, LValue &This, const CXXMethodDecl *Found, llvm::SmallVectorImpl<QualType> &CovariantAdjustmentPath) { - Optional<DynamicType> DynType = ComputeDynamicType( + std::optional<DynamicType> DynType = ComputeDynamicType( Info, E, This, isa<CXXDestructorDecl>(Found) ? AK_Destroy : AK_MemberCall); if (!DynType) @@ -5839,7 +5847,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E, // For all the other cases, we need the pointer to point to an object within // its lifetime / period of construction / destruction, and we need to know // its dynamic type. - Optional<DynamicType> DynType = + std::optional<DynamicType> DynType = ComputeDynamicType(Info, E, Ptr, AK_DynamicCast); if (!DynType) return false; @@ -6728,10 +6736,10 @@ static const FunctionDecl *getVirtualOperatorDelete(QualType T) { /// still exists and is of the right kind for the purpose of a deletion. /// /// On success, returns the heap allocation to deallocate. On failure, produces -/// a diagnostic and returns None. -static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E, - const LValue &Pointer, - DynAlloc::Kind DeallocKind) { +/// a diagnostic and returns std::nullopt. +static std::optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E, + const LValue &Pointer, + DynAlloc::Kind DeallocKind) { auto PointerAsString = [&] { return Pointer.toString(Info.Ctx, Info.Ctx.VoidPtrTy); }; @@ -6742,13 +6750,13 @@ static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E, << PointerAsString(); if (Pointer.Base) NoteLValueLocation(Info, Pointer.Base); - return None; + return std::nullopt; } - Optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA); + std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA); if (!Alloc) { Info.FFDiag(E, diag::note_constexpr_double_delete); - return None; + return std::nullopt; } QualType AllocType = Pointer.Base.getDynamicAllocType(); @@ -6756,7 +6764,7 @@ static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E, Info.FFDiag(E, diag::note_constexpr_new_delete_mismatch) << DeallocKind << (*Alloc)->getKind() << AllocType; NoteLValueLocation(Info, Pointer.Base); - return None; + return std::nullopt; } bool Subobject = false; @@ -6770,7 +6778,7 @@ static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E, if (Subobject) { Info.FFDiag(E, diag::note_constexpr_delete_subobject) << PointerAsString() << Pointer.Designator.isOnePastTheEnd(); - return None; + return std::nullopt; } return Alloc; @@ -6822,7 +6830,7 @@ class BitCastBuffer { // FIXME: Its possible under the C++ standard for 'char' to not be 8 bits, but // we don't support a host or target where that is the case. Still, we should // use a more generic type in case we ever do. - SmallVector<Optional<unsigned char>, 32> Bytes; + SmallVector<std::optional<unsigned char>, 32> Bytes; static_assert(std::numeric_limits<unsigned char>::digits >= 8, "Need at least 8 bit unsigned char"); @@ -6834,9 +6842,8 @@ public: : Bytes(Width.getQuantity()), TargetIsLittleEndian(TargetIsLittleEndian) {} - LLVM_NODISCARD - bool readObject(CharUnits Offset, CharUnits Width, - SmallVectorImpl<unsigned char> &Output) const { + [[nodiscard]] bool readObject(CharUnits Offset, CharUnits Width, + SmallVectorImpl<unsigned char> &Output) const { for (CharUnits I = Offset, E = Offset + Width; I != E; ++I) { // If a byte of an integer is uninitialized, then the whole integer is // uninitialized. @@ -7013,12 +7020,12 @@ class APValueToBufferConverter { } public: - static Optional<BitCastBuffer> convert(EvalInfo &Info, const APValue &Src, - const CastExpr *BCE) { + static std::optional<BitCastBuffer> + convert(EvalInfo &Info, const APValue &Src, const CastExpr *BCE) { CharUnits DstSize = Info.Ctx.getTypeSizeInChars(BCE->getType()); APValueToBufferConverter Converter(Info, DstSize, BCE); if (!Converter.visit(Src, BCE->getSubExpr()->getType())) - return None; + return std::nullopt; return Converter.Buffer; } }; @@ -7036,22 +7043,22 @@ class BufferToAPValueConverter { // Emit an unsupported bit_cast type error. Sema refuses to build a bit_cast // with an invalid type, so anything left is a deficiency on our part (FIXME). // Ideally this will be unreachable. - llvm::NoneType unsupportedType(QualType Ty) { + std::nullopt_t unsupportedType(QualType Ty) { Info.FFDiag(BCE->getBeginLoc(), diag::note_constexpr_bit_cast_unsupported_type) << Ty; - return None; + return std::nullopt; } - llvm::NoneType unrepresentableValue(QualType Ty, const APSInt &Val) { + std::nullopt_t unrepresentableValue(QualType Ty, const APSInt &Val) { Info.FFDiag(BCE->getBeginLoc(), diag::note_constexpr_bit_cast_unrepresentable_value) << Ty << toString(Val, /*Radix=*/10); - return None; + return std::nullopt; } - Optional<APValue> visit(const BuiltinType *T, CharUnits Offset, - const EnumType *EnumSugar = nullptr) { + std::optional<APValue> visit(const BuiltinType *T, CharUnits Offset, + const EnumType *EnumSugar = nullptr) { if (T->isNullPtrType()) { uint64_t NullValue = Info.Ctx.getTargetNullPointerValue(QualType(T, 0)); return APValue((Expr *)nullptr, @@ -7087,7 +7094,7 @@ class BufferToAPValueConverter { Info.FFDiag(BCE->getExprLoc(), diag::note_constexpr_bit_cast_indet_dest) << DisplayType << Info.Ctx.getLangOpts().CharIsSigned; - return None; + return std::nullopt; } return APValue::IndeterminateValue(); @@ -7119,7 +7126,7 @@ class BufferToAPValueConverter { return unsupportedType(QualType(T, 0)); } - Optional<APValue> visit(const RecordType *RTy, CharUnits Offset) { + std::optional<APValue> visit(const RecordType *RTy, CharUnits Offset) { const RecordDecl *RD = RTy->getAsRecordDecl(); const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); @@ -7139,10 +7146,10 @@ class BufferToAPValueConverter { Info.Ctx.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero()) continue; - Optional<APValue> SubObj = visitType( + std::optional<APValue> SubObj = visitType( BS.getType(), Layout.getBaseClassOffset(BaseDecl) + Offset); if (!SubObj) - return None; + return std::nullopt; ResultVal.getStructBase(I) = *SubObj; } } @@ -7155,7 +7162,7 @@ class BufferToAPValueConverter { if (FD->isBitField()) { Info.FFDiag(BCE->getBeginLoc(), diag::note_constexpr_bit_cast_unsupported_bitfield); - return None; + return std::nullopt; } uint64_t FieldOffsetBits = Layout.getFieldOffset(FieldIdx); @@ -7165,9 +7172,9 @@ class BufferToAPValueConverter { CharUnits::fromQuantity(FieldOffsetBits / Info.Ctx.getCharWidth()) + Offset; QualType FieldTy = FD->getType(); - Optional<APValue> SubObj = visitType(FieldTy, FieldOffset); + std::optional<APValue> SubObj = visitType(FieldTy, FieldOffset); if (!SubObj) - return None; + return std::nullopt; ResultVal.getStructField(FieldIdx) = *SubObj; ++FieldIdx; } @@ -7175,7 +7182,7 @@ class BufferToAPValueConverter { return ResultVal; } - Optional<APValue> visit(const EnumType *Ty, CharUnits Offset) { + std::optional<APValue> visit(const EnumType *Ty, CharUnits Offset) { QualType RepresentationType = Ty->getDecl()->getIntegerType(); assert(!RepresentationType.isNull() && "enum forward decl should be caught by Sema"); @@ -7186,27 +7193,27 @@ class BufferToAPValueConverter { return visit(AsBuiltin, Offset, /*EnumTy=*/Ty); } - Optional<APValue> visit(const ConstantArrayType *Ty, CharUnits Offset) { + std::optional<APValue> visit(const ConstantArrayType *Ty, CharUnits Offset) { size_t Size = Ty->getSize().getLimitedValue(); CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(Ty->getElementType()); APValue ArrayValue(APValue::UninitArray(), Size, Size); for (size_t I = 0; I != Size; ++I) { - Optional<APValue> ElementValue = + std::optional<APValue> ElementValue = visitType(Ty->getElementType(), Offset + I * ElementWidth); if (!ElementValue) - return None; + return std::nullopt; ArrayValue.getArrayInitializedElt(I) = std::move(*ElementValue); } return ArrayValue; } - Optional<APValue> visit(const Type *Ty, CharUnits Offset) { + std::optional<APValue> visit(const Type *Ty, CharUnits Offset) { return unsupportedType(QualType(Ty, 0)); } - Optional<APValue> visitType(QualType Ty, CharUnits Offset) { + std::optional<APValue> visitType(QualType Ty, CharUnits Offset) { QualType Can = Ty.getCanonicalType(); switch (Can->getTypeClass()) { @@ -7231,8 +7238,8 @@ class BufferToAPValueConverter { public: // Pull out a full value of type DstType. - static Optional<APValue> convert(EvalInfo &Info, BitCastBuffer &Buffer, - const CastExpr *BCE) { + static std::optional<APValue> convert(EvalInfo &Info, BitCastBuffer &Buffer, + const CastExpr *BCE) { BufferToAPValueConverter Converter(Info, Buffer, BCE); return Converter.visitType(BCE->getType(), CharUnits::fromQuantity(0)); } @@ -7321,13 +7328,13 @@ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue, return false; // Read out SourceValue into a char buffer. - Optional<BitCastBuffer> Buffer = + std::optional<BitCastBuffer> Buffer = APValueToBufferConverter::convert(Info, SourceRValue, BCE); if (!Buffer) return false; // Write out the buffer into a new APValue. - Optional<APValue> MaybeDestValue = + std::optional<APValue> MaybeDestValue = BufferToAPValueConverter::convert(Info, *Buffer, BCE); if (!MaybeDestValue) return false; @@ -7406,6 +7413,12 @@ protected: bool ZeroInitialization(const Expr *E) { return Error(E); } + bool IsConstantEvaluatedBuiltinCall(const CallExpr *E) { + unsigned BuiltinOp = E->getBuiltinCallee(); + return BuiltinOp != 0 && + Info.Ctx.BuiltinInfo.isConstantEvaluated(BuiltinOp); + } + public: ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {} @@ -7613,7 +7626,7 @@ public: const FunctionDecl *FD = nullptr; LValue *This = nullptr, ThisVal; - auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs()); + auto Args = llvm::ArrayRef(E->getArgs(), E->getNumArgs()); bool HasQualifier = false; CallRef Call; @@ -7945,8 +7958,8 @@ public: bool VisitStmtExpr(const StmtExpr *E) { // We will have checked the full-expressions inside the statement expression // when they were completed, and don't need to check them again now. - llvm::SaveAndRestore<bool> NotCheckingForUB( - Info.CheckingForUndefinedBehavior, false); + llvm::SaveAndRestore NotCheckingForUB(Info.CheckingForUndefinedBehavior, + false); const CompoundStmt *CS = E->getSubStmt(); if (CS->body_empty()) @@ -8179,7 +8192,8 @@ public: return LValueExprEvaluatorBaseTy::VisitCastExpr(E); case CK_LValueBitCast: - this->CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + this->CCEDiag(E, diag::note_constexpr_invalid_cast) + << 2 << Info.Ctx.getLangOpts().CPlusPlus; if (!Visit(E->getSubExpr())) return false; Result.Designator.setInvalid(); @@ -8208,7 +8222,7 @@ static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info, bool InvalidBaseOK) { assert(!E->isValueDependent()); assert(E->isGLValue() || E->getType()->isFunctionType() || - E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E)); + E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E->IgnoreParens())); return LValueExprEvaluator(Info, Result, InvalidBaseOK).Visit(E); } @@ -8317,7 +8331,12 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { } bool LValueExprEvaluator::VisitCallExpr(const CallExpr *E) { + if (!IsConstantEvaluatedBuiltinCall(E)) + return ExprEvaluatorBaseTy::VisitCallExpr(E); + switch (E->getBuiltinCallee()) { + default: + return false; case Builtin::BIas_const: case Builtin::BIforward: case Builtin::BImove: @@ -8424,7 +8443,7 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { if (!Visit(E->getExprOperand())) return false; - Optional<DynamicType> DynType = + std::optional<DynamicType> DynType = ComputeDynamicType(Info, E, Result, AK_TypeId); if (!DynType) return false; @@ -8890,9 +8909,10 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { Result.Designator.setInvalid(); if (SubExpr->getType()->isVoidPointerType()) CCEDiag(E, diag::note_constexpr_invalid_cast) - << 3 << SubExpr->getType(); + << 3 << SubExpr->getType(); else - CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + CCEDiag(E, diag::note_constexpr_invalid_cast) + << 2 << Info.Ctx.getLangOpts().CPlusPlus; } } if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr) @@ -8929,7 +8949,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { return ZeroInitialization(E); case CK_IntegralToPointer: { - CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + CCEDiag(E, diag::note_constexpr_invalid_cast) + << 2 << Info.Ctx.getLangOpts().CPlusPlus; APValue Value; if (!EvaluateIntegerOrLValue(SubExpr, Value, Info)) @@ -9090,13 +9111,9 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) { } bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { - if (IsConstantCall(E)) - return Success(E); - - if (unsigned BuiltinOp = E->getBuiltinCallee()) - return VisitBuiltinCallExpr(E, BuiltinOp); - - return visitNonBuiltinCallExpr(E); + if (!IsConstantEvaluatedBuiltinCall(E)) + return visitNonBuiltinCallExpr(E); + return VisitBuiltinCallExpr(E, E->getBuiltinCallee()); } // Determine if T is a character type for which we guarantee that @@ -9107,6 +9124,9 @@ static bool isOneByteCharacterType(QualType T) { bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinOp) { + if (IsNoOpCall(E)) + return Success(E); + switch (BuiltinOp) { case Builtin::BIaddressof: case Builtin::BI__addressof: @@ -9213,11 +9233,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BIwmemchr: if (Info.getLangOpts().CPlusPlus11) Info.CCEDiag(E, diag::note_constexpr_invalid_function) - << /*isConstexpr*/0 << /*isConstructor*/0 - << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'"); + << /*isConstexpr*/ 0 << /*isConstructor*/ 0 + << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str(); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Builtin::BI__builtin_strchr: case Builtin::BI__builtin_wcschr: case Builtin::BI__builtin_memchr: @@ -9259,7 +9279,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, // FIXME: We can compare the bytes in the correct order. if (IsRawByte && !isOneByteCharacterType(CharTy)) { Info.FFDiag(E, diag::note_constexpr_memchr_unsupported) - << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'") + << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str() << CharTy; return false; } @@ -9278,7 +9298,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, Desired)) return ZeroInitialization(E); StopAtNull = true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case Builtin::BImemchr: case Builtin::BI__builtin_memchr: case Builtin::BI__builtin_char_memchr: @@ -9291,7 +9311,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BIwcschr: case Builtin::BI__builtin_wcschr: StopAtNull = true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case Builtin::BIwmemchr: case Builtin::BI__builtin_wmemchr: // wcschr and wmemchr are given a wchar_t to look for. Just use it. @@ -9321,11 +9341,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BIwmemmove: if (Info.getLangOpts().CPlusPlus11) Info.CCEDiag(E, diag::note_constexpr_invalid_function) - << /*isConstexpr*/0 << /*isConstructor*/0 - << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'"); + << /*isConstexpr*/ 0 << /*isConstructor*/ 0 + << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str(); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Builtin::BI__builtin_memcpy: case Builtin::BI__builtin_memmove: case Builtin::BI__builtin_wmemcpy: @@ -9461,10 +9481,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, } default: - break; + return false; } - - return visitNonBuiltinCallExpr(E); } static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This, @@ -9527,7 +9545,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { bool ValueInit = false; QualType AllocType = E->getAllocatedType(); - if (Optional<const Expr *> ArraySize = E->getArraySize()) { + if (std::optional<const Expr *> ArraySize = E->getArraySize()) { const Expr *Stripped = *ArraySize; for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped); Stripped = ICE->getSubExpr()) @@ -9809,6 +9827,9 @@ namespace { bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T); bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E); bool VisitBinCmp(const BinaryOperator *E); + bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E); + bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit, + ArrayRef<Expr *> Args); }; } @@ -9927,8 +9948,13 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) { bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { if (E->isTransparent()) return Visit(E->getInit(0)); + return VisitCXXParenListOrInitListExpr(E, E->inits()); +} - const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl(); +bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr( + const Expr *ExprToVisit, ArrayRef<Expr *> Args) { + const RecordDecl *RD = + ExprToVisit->getType()->castAs<RecordType>()->getDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); @@ -9939,7 +9965,16 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { CXXRD && CXXRD->getNumBases()); if (RD->isUnion()) { - const FieldDecl *Field = E->getInitializedFieldInUnion(); + const FieldDecl *Field; + if (auto *ILE = dyn_cast<InitListExpr>(ExprToVisit)) { + Field = ILE->getInitializedFieldInUnion(); + } else if (auto *PLIE = dyn_cast<CXXParenListInitExpr>(ExprToVisit)) { + Field = PLIE->getInitializedFieldInUnion(); + } else { + llvm_unreachable( + "Expression is neither an init list nor a C++ paren list"); + } + Result = APValue(Field); if (!Field) return true; @@ -9950,7 +9985,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // Is this difference ever observable for initializer lists which // we don't build? ImplicitValueInitExpr VIE(Field->getType()); - const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE; + const Expr *InitExpr = Args.empty() ? &VIE : Args[0]; LValue Subobject = This; if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout)) @@ -9979,8 +10014,8 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // Initialize base classes. if (CXXRD && CXXRD->getNumBases()) { for (const auto &Base : CXXRD->bases()) { - assert(ElementNo < E->getNumInits() && "missing init for base class"); - const Expr *Init = E->getInit(ElementNo); + assert(ElementNo < Args.size() && "missing init for base class"); + const Expr *Init = Args[ElementNo]; LValue Subobject = This; if (!HandleLValueBase(Info, Init, Subobject, CXXRD, &Base)) @@ -10007,18 +10042,18 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { LValue Subobject = This; - bool HaveInit = ElementNo < E->getNumInits(); + bool HaveInit = ElementNo < Args.size(); // FIXME: Diagnostics here should point to the end of the initializer // list, not the start. - if (!HandleLValueMember(Info, HaveInit ? E->getInit(ElementNo) : E, + if (!HandleLValueMember(Info, HaveInit ? Args[ElementNo] : ExprToVisit, Subobject, Field, &Layout)) return false; // Perform an implicit value-initialization for members beyond the end of // the initializer list. ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType()); - const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE; + const Expr *Init = HaveInit ? Args[ElementNo++] : &VIE; if (Field->getType()->isIncompleteArrayType()) { if (auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType())) { @@ -10093,7 +10128,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, if (ZeroInit && !ZeroInitialization(E, T)) return false; - auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs()); + auto Args = llvm::ArrayRef(E->getArgs(), E->getNumArgs()); return HandleConstructorCall(E, This, Args, cast<CXXConstructorDecl>(Definition), Info, Result); @@ -10504,10 +10539,10 @@ bool VectorExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return Success(LHSValue, E); } -static llvm::Optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx, - QualType ResultTy, - UnaryOperatorKind Op, - APValue Elt) { +static std::optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx, + QualType ResultTy, + UnaryOperatorKind Op, + APValue Elt) { switch (Op) { case UO_Plus: // Nothing to do here. @@ -10550,7 +10585,7 @@ static llvm::Optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx, } default: // FIXME: Implement the rest of the unary operators. - return llvm::None; + return std::nullopt; } } @@ -10581,7 +10616,7 @@ bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { SmallVector<APValue, 4> ResultElements; for (unsigned EltNum = 0; EltNum < VD->getNumElements(); ++EltNum) { - llvm::Optional<APValue> Elt = handleVectorUnaryOperator( + std::optional<APValue> Elt = handleVectorUnaryOperator( Info.Ctx, ResultEltTy, Op, SubExprValue.getVectorElt(EltNum)); if (!Elt) return false; @@ -10652,6 +10687,11 @@ namespace { expandStringLiteral(Info, E, Result, AllocType); return true; } + bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E); + bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit, + ArrayRef<Expr *> Args, + const Expr *ArrayFiller, + QualType AllocType = QualType()); }; } // end anonymous namespace @@ -10695,6 +10735,11 @@ static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) { if (MaybeElementDependentArrayFiller(ILE->getInit(I))) return true; } + + if (ILE->hasArrayFiller() && + MaybeElementDependentArrayFiller(ILE->getArrayFiller())) + return true; + return false; } return true; @@ -10722,6 +10767,16 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E, assert(!E->isTransparent() && "transparent array list initialization is not string literal init?"); + return VisitCXXParenListOrInitListExpr(E, E->inits(), E->getArrayFiller(), + AllocType); +} + +bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr( + const Expr *ExprToVisit, ArrayRef<Expr *> Args, const Expr *ArrayFiller, + QualType AllocType) { + const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType( + AllocType.isNull() ? ExprToVisit->getType() : AllocType); + bool Success = true; assert((!Result.isArray() || Result.getArrayInitializedElts() == 0) && @@ -10730,13 +10785,12 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E, if (Result.isArray() && Result.hasArrayFiller()) Filler = Result.getArrayFiller(); - unsigned NumEltsToInit = E->getNumInits(); + unsigned NumEltsToInit = Args.size(); unsigned NumElts = CAT->getSize().getZExtValue(); - const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : nullptr; // If the initializer might depend on the array index, run it for each // array element. - if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(FillerExpr)) + if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(ArrayFiller)) NumEltsToInit = NumElts; LLVM_DEBUG(llvm::dbgs() << "The number of elements to initialize: " @@ -10754,10 +10808,9 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E, } LValue Subobject = This; - Subobject.addArray(Info, E, CAT); + Subobject.addArray(Info, ExprToVisit, CAT); for (unsigned Index = 0; Index != NumEltsToInit; ++Index) { - const Expr *Init = - Index < E->getNumInits() ? E->getInit(Index) : FillerExpr; + const Expr *Init = Index < Args.size() ? Args[Index] : ArrayFiller; if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, Subobject, Init) || !HandleLValueArrayAdjustment(Info, Init, Subobject, @@ -10773,9 +10826,10 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E, // If we get here, we have a trivial filler, which we can just evaluate // once and splat over the rest of the array elements. - assert(FillerExpr && "no array filler for incomplete init list"); + assert(ArrayFiller && "no array filler for incomplete init list"); return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, - FillerExpr) && Success; + ArrayFiller) && + Success; } bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { @@ -10833,6 +10887,9 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, if (FinalSize == 0) return true; + bool HasTrivialConstructor = CheckTrivialDefaultConstructor( + Info, E->getExprLoc(), E->getConstructor(), + E->requiresZeroInitialization()); LValue ArrayElt = Subobject; ArrayElt.addArray(Info, E, CAT); // We do the whole initialization in two passes, first for just one element, @@ -10856,19 +10913,26 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, for (unsigned I = OldElts; I < N; ++I) Value->getArrayInitializedElt(I) = Filler; - // Initialize the elements. - for (unsigned I = OldElts; I < N; ++I) { - if (!VisitCXXConstructExpr(E, ArrayElt, - &Value->getArrayInitializedElt(I), - CAT->getElementType()) || - !HandleLValueArrayAdjustment(Info, E, ArrayElt, - CAT->getElementType(), 1)) - return false; - // When checking for const initilization any diagnostic is considered - // an error. - if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() && - !Info.keepEvaluatingAfterFailure()) - return false; + if (HasTrivialConstructor && N == FinalSize) { + // If we have a trivial constructor, only evaluate it once and copy + // the result into all the array elements. + APValue &FirstResult = Value->getArrayInitializedElt(0); + for (unsigned I = OldElts; I < FinalSize; ++I) + Value->getArrayInitializedElt(I) = FirstResult; + } else { + for (unsigned I = OldElts; I < N; ++I) { + if (!VisitCXXConstructExpr(E, ArrayElt, + &Value->getArrayInitializedElt(I), + CAT->getElementType()) || + !HandleLValueArrayAdjustment(Info, E, ArrayElt, + CAT->getElementType(), 1)) + return false; + // When checking for const initilization any diagnostic is considered + // an error. + if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() && + !Info.keepEvaluatingAfterFailure()) + return false; + } } } @@ -10882,6 +10946,15 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, .VisitCXXConstructExpr(E, Type); } +bool ArrayExprEvaluator::VisitCXXParenListInitExpr( + const CXXParenListInitExpr *E) { + assert(dyn_cast<ConstantArrayType>(E->getType()) && + "Expression result is not a constant array type"); + + return VisitCXXParenListOrInitListExpr(E, E->getInitExprs(), + E->getArrayFiller()); +} + //===----------------------------------------------------------------------===// // Integer Evaluation // @@ -11596,15 +11669,31 @@ static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const LValue &LVal) { // conservative with the last element in structs (if it's an array), so our // current behavior is more compatible than an explicit list approach would // be. - int StrictFlexArraysLevel = Ctx.getLangOpts().StrictFlexArrays; + auto isFlexibleArrayMember = [&] { + using FAMKind = LangOptions::StrictFlexArraysLevelKind; + FAMKind StrictFlexArraysLevel = + Ctx.getLangOpts().getStrictFlexArraysLevel(); + + if (Designator.isMostDerivedAnUnsizedArray()) + return true; + + if (StrictFlexArraysLevel == FAMKind::Default) + return true; + + if (Designator.getMostDerivedArraySize() == 0 && + StrictFlexArraysLevel != FAMKind::IncompleteOnly) + return true; + + if (Designator.getMostDerivedArraySize() == 1 && + StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete) + return true; + + return false; + }; + return LVal.InvalidBase && Designator.Entries.size() == Designator.MostDerivedPathLength && - Designator.MostDerivedIsArrayElement && - (Designator.isMostDerivedAnUnsizedArray() || - Designator.getMostDerivedArraySize() == 0 || - (Designator.getMostDerivedArraySize() == 1 && - StrictFlexArraysLevel < 2) || - StrictFlexArraysLevel == 0) && + Designator.MostDerivedIsArrayElement && isFlexibleArrayMember() && isDesignatorAtObjectEnd(Ctx, LVal); } @@ -11751,10 +11840,9 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type, } bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { - if (unsigned BuiltinOp = E->getBuiltinCallee()) - return VisitBuiltinCallExpr(E, BuiltinOp); - - return ExprEvaluatorBaseTy::VisitCallExpr(E); + if (!IsConstantEvaluatedBuiltinCall(E)) + return ExprEvaluatorBaseTy::VisitCallExpr(E); + return VisitBuiltinCallExpr(E, E->getBuiltinCallee()); } static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info, @@ -11788,7 +11876,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinOp) { switch (BuiltinOp) { default: - return ExprEvaluatorBaseTy::VisitCallExpr(E); + return false; case Builtin::BI__builtin_dynamic_object_size: case Builtin::BI__builtin_object_size: { @@ -12103,11 +12191,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, // A call to strlen is not a constant expression. if (Info.getLangOpts().CPlusPlus11) Info.CCEDiag(E, diag::note_constexpr_invalid_function) - << /*isConstexpr*/0 << /*isConstructor*/0 - << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'"); + << /*isConstexpr*/ 0 << /*isConstructor*/ 0 + << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str(); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Builtin::BI__builtin_strlen: case Builtin::BI__builtin_wcslen: { // As an extension, we support __builtin_strlen() as a constant expression, @@ -12128,11 +12216,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, // A call to strlen is not a constant expression. if (Info.getLangOpts().CPlusPlus11) Info.CCEDiag(E, diag::note_constexpr_invalid_function) - << /*isConstexpr*/0 << /*isConstructor*/0 - << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'"); + << /*isConstexpr*/ 0 << /*isConstructor*/ 0 + << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str(); else Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Builtin::BI__builtin_strcmp: case Builtin::BI__builtin_wcscmp: case Builtin::BI__builtin_strncmp: @@ -12184,7 +12272,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, !(isOneByteCharacterType(CharTy1) && isOneByteCharacterType(CharTy2))) { // FIXME: Consider using our bit_cast implementation to support this. Info.FFDiag(E, diag::note_constexpr_memcmp_unsupported) - << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'") + << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str() << CharTy1 << CharTy2; return false; } @@ -12886,41 +12974,55 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, // Reject differing bases from the normal codepath; we special-case // comparisons to null. if (!HasSameBase(LHSValue, RHSValue)) { + auto DiagComparison = [&] (unsigned DiagID, bool Reversed = false) { + std::string LHS = LHSValue.toString(Info.Ctx, E->getLHS()->getType()); + std::string RHS = RHSValue.toString(Info.Ctx, E->getRHS()->getType()); + Info.FFDiag(E, DiagID) + << (Reversed ? RHS : LHS) << (Reversed ? LHS : RHS); + return false; + }; // Inequalities and subtractions between unrelated pointers have // unspecified or undefined behavior. - if (!IsEquality) { - Info.FFDiag(E, diag::note_constexpr_pointer_comparison_unspecified); - return false; - } + if (!IsEquality) + return DiagComparison( + diag::note_constexpr_pointer_comparison_unspecified); // A constant address may compare equal to the address of a symbol. // The one exception is that address of an object cannot compare equal // to a null pointer constant. + // TODO: Should we restrict this to actual null pointers, and exclude the + // case of zero cast to pointer type? if ((!LHSValue.Base && !LHSValue.Offset.isZero()) || (!RHSValue.Base && !RHSValue.Offset.isZero())) - return Error(E); + return DiagComparison(diag::note_constexpr_pointer_constant_comparison, + !RHSValue.Base); // It's implementation-defined whether distinct literals will have // distinct addresses. In clang, the result of such a comparison is // unspecified, so it is not a constant expression. However, we do know // that the address of a literal will be non-null. if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) && LHSValue.Base && RHSValue.Base) - return Error(E); + return DiagComparison(diag::note_constexpr_literal_comparison); // We can't tell whether weak symbols will end up pointing to the same // object. if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue)) - return Error(E); + return DiagComparison(diag::note_constexpr_pointer_weak_comparison, + !IsWeakLValue(LHSValue)); // We can't compare the address of the start of one object with the // past-the-end address of another object, per C++ DR1652. - if ((LHSValue.Base && LHSValue.Offset.isZero() && - isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) || - (RHSValue.Base && RHSValue.Offset.isZero() && - isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))) - return Error(E); + if (LHSValue.Base && LHSValue.Offset.isZero() && + isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) + return DiagComparison(diag::note_constexpr_pointer_comparison_past_end, + true); + if (RHSValue.Base && RHSValue.Offset.isZero() && + isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue)) + return DiagComparison(diag::note_constexpr_pointer_comparison_past_end, + false); // We can't tell whether an object is at the same address as another // zero sized object. if ((RHSValue.Base && isZeroSized(LHSValue)) || (LHSValue.Base && isZeroSized(RHSValue))) - return Error(E); + return DiagComparison( + diag::note_constexpr_pointer_comparison_zero_sized); return Success(CmpResult::Unequal, E); } @@ -13024,6 +13126,19 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, if (!EvaluateMemberPointer(E->getRHS(), RHSValue, Info) || !LHSOK) return false; + // If either operand is a pointer to a weak function, the comparison is not + // constant. + if (LHSValue.getDecl() && LHSValue.getDecl()->isWeak()) { + Info.FFDiag(E, diag::note_constexpr_mem_pointer_weak_comparison) + << LHSValue.getDecl(); + return true; + } + if (RHSValue.getDecl() && RHSValue.getDecl()->isWeak()) { + Info.FFDiag(E, diag::note_constexpr_mem_pointer_weak_comparison) + << RHSValue.getDecl(); + return true; + } + // C++11 [expr.eq]p2: // If both operands are null, they compare equal. Otherwise if only one is // null, they compare unequal. @@ -13101,6 +13216,11 @@ bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) { }); } +bool RecordExprEvaluator::VisitCXXParenListInitExpr( + const CXXParenListInitExpr *E) { + return VisitCXXParenListOrInitListExpr(E, E->getInitExprs()); +} + bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // We don't support assignment in C. C++ assignments don't get here because // assignment is an lvalue in C++. @@ -13519,12 +13639,62 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType); } + if (Info.Ctx.getLangOpts().CPlusPlus && Info.InConstantContext && + Info.EvalMode == EvalInfo::EM_ConstantExpression && + DestType->isEnumeralType()) { + + bool ConstexprVar = true; + + // We know if we are here that we are in a context that we might require + // a constant expression or a context that requires a constant + // value. But if we are initializing a value we don't know if it is a + // constexpr variable or not. We can check the EvaluatingDecl to determine + // if it constexpr or not. If not then we don't want to emit a diagnostic. + if (const auto *VD = dyn_cast_or_null<VarDecl>( + Info.EvaluatingDecl.dyn_cast<const ValueDecl *>())) + ConstexprVar = VD->isConstexpr(); + + const EnumType *ET = dyn_cast<EnumType>(DestType.getCanonicalType()); + const EnumDecl *ED = ET->getDecl(); + // Check that the value is within the range of the enumeration values. + // + // This corressponds to [expr.static.cast]p10 which says: + // A value of integral or enumeration type can be explicitly converted + // to a complete enumeration type ... If the enumeration type does not + // have a fixed underlying type, the value is unchanged if the original + // value is within the range of the enumeration values ([dcl.enum]), and + // otherwise, the behavior is undefined. + // + // This was resolved as part of DR2338 which has CD5 status. + if (!ED->isFixed()) { + llvm::APInt Min; + llvm::APInt Max; + + ED->getValueRange(Max, Min); + --Max; + + if (ED->getNumNegativeBits() && ConstexprVar && + (Max.slt(Result.getInt().getSExtValue()) || + Min.sgt(Result.getInt().getSExtValue()))) + Info.Ctx.getDiagnostics().Report( + E->getExprLoc(), diag::warn_constexpr_unscoped_enum_out_of_range) + << llvm::toString(Result.getInt(), 10) << Min.getSExtValue() + << Max.getSExtValue(); + else if (!ED->getNumNegativeBits() && ConstexprVar && + Max.ult(Result.getInt().getZExtValue())) + Info.Ctx.getDiagnostics().Report(E->getExprLoc(), + diag::warn_constexpr_unscoped_enum_out_of_range) + << llvm::toString(Result.getInt(),10) << Min.getZExtValue() << Max.getZExtValue(); + } + } + return Success(HandleIntToIntCast(Info, E, DestType, SrcType, Result.getInt()), E); } case CK_PointerToIntegral: { - CCEDiag(E, diag::note_constexpr_invalid_cast) << 2; + CCEDiag(E, diag::note_constexpr_invalid_cast) + << 2 << Info.Ctx.getLangOpts().CPlusPlus; LValue LV; if (!EvaluatePointer(SubExpr, LV, Info)) @@ -13878,9 +14048,12 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context, } bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { + if (!IsConstantEvaluatedBuiltinCall(E)) + return ExprEvaluatorBaseTy::VisitCallExpr(E); + switch (E->getBuiltinCallee()) { default: - return ExprEvaluatorBaseTy::VisitCallExpr(E); + return false; case Builtin::BI__builtin_huge_val: case Builtin::BI__builtin_huge_valf: @@ -13954,6 +14127,42 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { Result.copySign(RHS); return true; } + + case Builtin::BI__builtin_fmax: + case Builtin::BI__builtin_fmaxf: + case Builtin::BI__builtin_fmaxl: + case Builtin::BI__builtin_fmaxf16: + case Builtin::BI__builtin_fmaxf128: { + // TODO: Handle sNaN. + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + // When comparing zeroes, return +0.0 if one of the zeroes is positive. + if (Result.isZero() && RHS.isZero() && Result.isNegative()) + Result = RHS; + else if (Result.isNaN() || RHS > Result) + Result = RHS; + return true; + } + + case Builtin::BI__builtin_fmin: + case Builtin::BI__builtin_fminf: + case Builtin::BI__builtin_fminl: + case Builtin::BI__builtin_fminf16: + case Builtin::BI__builtin_fminf128: { + // TODO: Handle sNaN. + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + // When comparing zeroes, return -0.0 if one of the zeroes is negative. + if (Result.isZero() && RHS.isZero() && RHS.isNegative()) + Result = RHS; + else if (Result.isNaN() || RHS < Result) + Result = RHS; + return true; + } } } @@ -14564,6 +14773,9 @@ bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) { } bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) { + if (!IsConstantEvaluatedBuiltinCall(E)) + return ExprEvaluatorBaseTy::VisitCallExpr(E); + switch (E->getBuiltinCallee()) { case Builtin::BI__builtin_complex: Result.makeComplexFloat(); @@ -14574,10 +14786,8 @@ bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) { return true; default: - break; + return false; } - - return ExprEvaluatorBaseTy::VisitCallExpr(E); } //===----------------------------------------------------------------------===// @@ -14653,6 +14863,9 @@ public: } bool VisitCallExpr(const CallExpr *E) { + if (!IsConstantEvaluatedBuiltinCall(E)) + return ExprEvaluatorBaseTy::VisitCallExpr(E); + switch (E->getBuiltinCallee()) { case Builtin::BI__assume: case Builtin::BI__builtin_assume: @@ -14663,10 +14876,8 @@ public: return HandleOperatorDeleteCall(Info, E); default: - break; + return false; } - - return ExprEvaluatorBaseTy::VisitCallExpr(E); } bool VisitCXXDeleteExpr(const CXXDeleteExpr *E); @@ -14703,7 +14914,7 @@ bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) { return true; } - Optional<DynAlloc *> Alloc = CheckDeleteKind( + std::optional<DynAlloc *> Alloc = CheckDeleteKind( Info, E, Pointer, E->isArrayForm() ? DynAlloc::ArrayNew : DynAlloc::New); if (!Alloc) return false; @@ -14871,25 +15082,27 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This, /// lvalue-to-rvalue cast if it is an lvalue. static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { assert(!E->isValueDependent()); + + if (E->getType().isNull()) + return false; + + if (!CheckLiteralType(Info, E)) + return false; + if (Info.EnableNewConstInterp) { if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result)) return false; } else { - if (E->getType().isNull()) - return false; - - if (!CheckLiteralType(Info, E)) - return false; - if (!::Evaluate(Result, Info, E)) return false; + } - if (E->isGLValue()) { - LValue LV; - LV.setFrom(Info.Ctx, Result); - if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) - return false; - } + // Implicit lvalue-to-rvalue cast. + if (E->isGLValue()) { + LValue LV; + LV.setFrom(Info.Ctx, Result); + if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) + return false; } // Check this core constant expression is a constant expression. @@ -14909,6 +15122,12 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, return true; } + if (const auto *L = dyn_cast<CXXBoolLiteralExpr>(Exp)) { + Result.Val = APValue(APSInt(APInt(1, L->getValue()))); + IsConst = true; + return true; + } + // This case should be rare, but we need to check it before we check on // the type below. if (Exp->getType().isNull()) { @@ -14986,6 +15205,7 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsRValue"); EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); Info.InConstantContext = InConstantContext; return ::EvaluateAsRValue(this, Result, Ctx, Info); @@ -14995,6 +15215,7 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, bool InConstantContext) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsBooleanCondition"); EvalResult Scratch; return EvaluateAsRValue(Scratch, Ctx, InConstantContext) && HandleConversionToBool(Scratch.Val, Result); @@ -15005,6 +15226,7 @@ bool Expr::EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsInt"); EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); Info.InConstantContext = InConstantContext; return ::EvaluateAsInt(this, Result, Ctx, AllowSideEffects, Info); @@ -15015,6 +15237,7 @@ bool Expr::EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx, bool InConstantContext) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsFixedPoint"); EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); Info.InConstantContext = InConstantContext; return ::EvaluateAsFixedPoint(this, Result, Ctx, AllowSideEffects, Info); @@ -15029,6 +15252,7 @@ bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx, if (!getType()->isRealFloatingType()) return false; + ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsFloat"); EvalResult ExprResult; if (!EvaluateAsRValue(ExprResult, Ctx, InConstantContext) || !ExprResult.Val.isFloat() || @@ -15044,6 +15268,7 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx, assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsLValue"); EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold); Info.InConstantContext = InConstantContext; LValue LV; @@ -15087,7 +15312,11 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx, ConstantExprKind Kind) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + bool IsConst; + if (FastEvaluateAsRValue(this, Result, Ctx, IsConst) && Result.Val.hasValue()) + return true; + ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsConstantExpr"); EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression; EvalInfo Info(Ctx, Result, EM); Info.InConstantContext = true; @@ -15140,6 +15369,13 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + llvm::TimeTraceScope TimeScope("EvaluateAsInitializer", [&] { + std::string Name; + llvm::raw_string_ostream OS(Name); + VD->printQualifiedName(OS); + return Name; + }); + // FIXME: Evaluating initializers for large array and record types can cause // performance problems. Only do so in C++11 for now. if (isPRValue() && (getType()->isArrayType() || getType()->isRecordType()) && @@ -15228,6 +15464,7 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx, assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateKnownConstInt"); EvalResult EVResult; EVResult.Diag = Diag; EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects); @@ -15246,6 +15483,7 @@ APSInt Expr::EvaluateKnownConstIntCheckOverflow( assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateKnownConstIntCheckOverflow"); EvalResult EVResult; EVResult.Diag = Diag; EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects); @@ -15264,6 +15502,7 @@ void Expr::EvaluateForOverflow(const ASTContext &Ctx) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateForOverflow"); bool IsConst; EvalResult EVResult; if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) { @@ -15425,6 +15664,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::DependentCoawaitExprClass: case Expr::CoyieldExprClass: case Expr::SYCLUniqueStableNameExprClass: + case Expr::CXXParenListInitExprClass: return ICEDiag(IK_NotICE, E->getBeginLoc()); case Expr::InitListExprClass: { @@ -15755,6 +15995,8 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx, assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + ExprTimeTraceScope TimeScope(this, Ctx, "isIntegerConstantExpr"); + if (Ctx.getLangOpts().CPlusPlus11) return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc); @@ -15766,12 +16008,12 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx, return true; } -Optional<llvm::APSInt> Expr::getIntegerConstantExpr(const ASTContext &Ctx, - SourceLocation *Loc, - bool isEvaluated) const { +std::optional<llvm::APSInt> +Expr::getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc, + bool isEvaluated) const { if (isValueDependent()) { // Expression evaluator can't succeed on a dependent expression. - return None; + return std::nullopt; } APSInt Value; @@ -15779,11 +16021,11 @@ Optional<llvm::APSInt> Expr::getIntegerConstantExpr(const ASTContext &Ctx, if (Ctx.getLangOpts().CPlusPlus11) { if (EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc)) return Value; - return None; + return std::nullopt; } if (!isIntegerConstantExpr(Ctx, Loc)) - return None; + return std::nullopt; // The only possible side-effects here are due to UB discovered in the // evaluation (for instance, INT_MAX + 1). In such a case, we are still @@ -15847,6 +16089,14 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx, assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); + llvm::TimeTraceScope TimeScope("EvaluateWithSubstitution", [&] { + std::string Name; + llvm::raw_string_ostream OS(Name); + Callee->getNameForDiagnostic(OS, Ctx.getPrintingPolicy(), + /*Qualified=*/true); + return Name; + }); + Expr::EvalStatus Status; EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpressionUnevaluated); Info.InConstantContext = true; @@ -15911,6 +16161,14 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, if (FD->isDependentContext()) return true; + llvm::TimeTraceScope TimeScope("isPotentialConstantExpr", [&] { + std::string Name; + llvm::raw_string_ostream OS(Name); + FD->getNameForDiagnostic(OS, FD->getASTContext().getPrintingPolicy(), + /*Qualified=*/true); + return Name; + }); + Expr::EvalStatus Status; Status.Diag = &Diags; |