diff options
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
| -rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 189 |
1 files changed, 152 insertions, 37 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9e4088f94015..beeb775371c3 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1978,7 +1978,8 @@ static bool IsGlobalLValue(APValue::LValueBase B) { return true; // ... the address of a function, // ... the address of a GUID [MS extension], - return isa<FunctionDecl>(D) || isa<MSGuidDecl>(D); + // ... the address of an unnamed global constant + return isa<FunctionDecl, MSGuidDecl, UnnamedGlobalConstantDecl>(D); } if (B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>()) @@ -2013,6 +2014,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) { // Block variables at global or local static scope. case Expr::BlockExprClass: return !cast<BlockExpr>(E)->getBlockDecl()->hasCaptures(); + // The APValue generated from a __builtin_source_location will be emitted as a + // literal. + case Expr::SourceLocExprClass: + return true; case Expr::ImplicitValueInitExprClass: // FIXME: // We can never form an lvalue with an implicit value initialization as its @@ -2547,18 +2552,15 @@ static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E, return true; } -/// Get rounding mode used for evaluation of the specified expression. -/// \param[out] DynamicRM Is set to true is the requested rounding mode is -/// dynamic. +/// Get rounding mode to use in evaluation of the specified expression. +/// /// If rounding mode is unknown at compile time, still try to evaluate the /// expression. If the result is exact, it does not depend on rounding mode. /// So return "tonearest" mode instead of "dynamic". -static llvm::RoundingMode getActiveRoundingMode(EvalInfo &Info, const Expr *E, - bool &DynamicRM) { +static llvm::RoundingMode getActiveRoundingMode(EvalInfo &Info, const Expr *E) { llvm::RoundingMode RM = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).getRoundingMode(); - DynamicRM = (RM == llvm::RoundingMode::Dynamic); - if (DynamicRM) + if (RM == llvm::RoundingMode::Dynamic) RM = llvm::RoundingMode::NearestTiesToEven; return RM; } @@ -2582,14 +2584,14 @@ static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E, if ((St != APFloat::opOK) && (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic || - FPO.getFPExceptionMode() != LangOptions::FPE_Ignore || + FPO.getExceptionMode() != LangOptions::FPE_Ignore || FPO.getAllowFEnvAccess())) { Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict); return false; } if ((St & APFloat::opStatus::opInvalidOp) && - FPO.getFPExceptionMode() != LangOptions::FPE_Ignore) { + FPO.getExceptionMode() != LangOptions::FPE_Ignore) { // There is no usefully definable result. Info.FFDiag(E); return false; @@ -2608,8 +2610,7 @@ static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E, QualType SrcType, QualType DestType, APFloat &Result) { assert(isa<CastExpr>(E) || isa<CompoundAssignOperator>(E)); - bool DynamicRM; - llvm::RoundingMode RM = getActiveRoundingMode(Info, E, DynamicRM); + llvm::RoundingMode RM = getActiveRoundingMode(Info, E); APFloat::opStatus St; APFloat Value = Result; bool ignored; @@ -2844,8 +2845,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, static bool handleFloatFloatBinOp(EvalInfo &Info, const BinaryOperator *E, APFloat &LHS, BinaryOperatorKind Opcode, const APFloat &RHS) { - bool DynamicRM; - llvm::RoundingMode RM = getActiveRoundingMode(Info, E, DynamicRM); + llvm::RoundingMode RM = getActiveRoundingMode(Info, E); APFloat::opStatus St; switch (Opcode) { default: @@ -4024,6 +4024,16 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, return CompleteObject(LVal.Base, &V, GD->getType()); } + // Allow reading the APValue from an UnnamedGlobalConstantDecl. + if (auto *GCD = dyn_cast<UnnamedGlobalConstantDecl>(D)) { + if (isModification(AK)) { + Info.FFDiag(E, diag::note_constexpr_modify_global); + return CompleteObject(); + } + return CompleteObject(LVal.Base, const_cast<APValue *>(&GCD->getValue()), + GCD->getType()); + } + // Allow reading from template parameter objects. if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(D)) { if (isModification(AK)) { @@ -4244,9 +4254,33 @@ handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type, Info.FFDiag(Conv); return false; } + APValue Lit; if (!Evaluate(Lit, Info, CLE->getInitializer())) return false; + + // According to GCC info page: + // + // 6.28 Compound Literals + // + // As an optimization, G++ sometimes gives array compound literals longer + // lifetimes: when the array either appears outside a function or has a + // const-qualified type. If foo and its initializer had elements of type + // char *const rather than char *, or if foo were a global variable, the + // array would have static storage duration. But it is probably safest + // just to avoid the use of array compound literals in C++ code. + // + // Obey that rule by checking constness for converted array types. + + QualType CLETy = CLE->getType(); + if (CLETy->isArrayType() && !Type->isArrayType()) { + if (!CLETy.isConstant(Info.Ctx)) { + Info.FFDiag(Conv); + Info.Note(CLE->getExprLoc(), diag::note_declared_at); + return false; + } + } + CompleteObject LitObj(LVal.Base, &Lit, Base->getType()); return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal, AK); } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) { @@ -5003,6 +5037,18 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info, llvm_unreachable("Invalid EvalStmtResult!"); } +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()) { + Info.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local) + << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD; + return false; + } + return true; +} + // Evaluate a statement. static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, const Stmt *S, const SwitchCase *Case) { @@ -5113,6 +5159,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, const DeclStmt *DS = cast<DeclStmt>(S); for (const auto *D : DS->decls()) { if (const auto *VD = dyn_cast<VarDecl>(D)) { + if (!CheckLocalVariableDeclaration(Info, VD)) + return ESR_Failed; if (VD->hasLocalStorage() && !VD->getInit()) if (!EvaluateVarDecl(Info, VD)) return ESR_Failed; @@ -5156,6 +5204,9 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, case Stmt::DeclStmtClass: { const DeclStmt *DS = cast<DeclStmt>(S); for (const auto *D : DS->decls()) { + const VarDecl *VD = dyn_cast_or_null<VarDecl>(D); + if (VD && !CheckLocalVariableDeclaration(Info, VD)) + return ESR_Failed; // Each declaration initialization is its own full-expression. FullExpressionRAII Scope(Info); if (!EvaluateDecl(Info, D) && !Info.noteFailure()) @@ -6124,9 +6175,6 @@ static bool HandleFunctionCall(SourceLocation CallLoc, if (!handleTrivialCopy(Info, MD->getParamDecl(0), Args[0], RHSValue, MD->getParent()->isUnion())) return false; - if (Info.getLangOpts().CPlusPlus20 && MD->isTrivial() && - !HandleUnionActiveMemberChange(Info, Args[0], *This)) - return false; if (!handleAssignment(Info, Args[0], *This, MD->getThisType(), RHSValue)) return false; @@ -6507,7 +6555,7 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceLocation CallLoc, // We don't have a good way to iterate fields in reverse, so collect all the // fields first and then walk them backwards. - SmallVector<FieldDecl*, 16> Fields(RD->field_begin(), RD->field_end()); + SmallVector<FieldDecl*, 16> Fields(RD->fields()); for (const FieldDecl *FD : llvm::reverse(Fields)) { if (FD->isUnnamedBitfield()) continue; @@ -7638,6 +7686,15 @@ public: if (!EvaluateObjectArgument(Info, Args[0], ThisVal)) return false; This = &ThisVal; + + // If this is syntactically a simple assignment using a trivial + // assignment operator, start the lifetimes of union members as needed, + // per C++20 [class.union]5. + if (Info.getLangOpts().CPlusPlus20 && OCE && + OCE->getOperator() == OO_Equal && MD->isTrivial() && + !HandleUnionActiveMemberChange(Info, Args[0], ThisVal)) + return false; + Args = Args.slice(1); } else if (MD && MD->isLambdaStaticInvoker()) { // Map the static invoker for the lambda back to the call operator. @@ -8089,6 +8146,7 @@ public: bool VisitVarDecl(const Expr *E, const VarDecl *VD); bool VisitUnaryPreIncDec(const UnaryOperator *UO); + bool VisitCallExpr(const CallExpr *E); bool VisitDeclRefExpr(const DeclRefExpr *E); bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); } bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); @@ -8152,7 +8210,8 @@ static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info, bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { const NamedDecl *D = E->getDecl(); - if (isa<FunctionDecl, MSGuidDecl, TemplateParamObjectDecl>(D)) + if (isa<FunctionDecl, MSGuidDecl, TemplateParamObjectDecl, + UnnamedGlobalConstantDecl>(D)) return Success(cast<ValueDecl>(D)); if (const VarDecl *VD = dyn_cast<VarDecl>(D)) return VisitVarDecl(E, VD); @@ -8253,6 +8312,20 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { return Success(*V, E); } +bool LValueExprEvaluator::VisitCallExpr(const CallExpr *E) { + switch (E->getBuiltinCallee()) { + case Builtin::BIas_const: + case Builtin::BIforward: + case Builtin::BImove: + case Builtin::BImove_if_noexcept: + if (cast<FunctionDecl>(E->getCalleeDecl())->isConstexpr()) + return Visit(E->getArg(0)); + break; + } + + return ExprEvaluatorBaseTy::VisitCallExpr(E); +} + bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *E) { // Walk through the expression to find the materialized temporary itself. @@ -8384,7 +8457,8 @@ bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { // FIXME: Deal with vectors as array subscript bases. - if (E->getBase()->getType()->isVectorType()) + if (E->getBase()->getType()->isVectorType() || + E->getBase()->getType()->isVLSTBuiltinType()) return Error(E); APSInt Index; @@ -8517,7 +8591,7 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, Into = ExprResult.Val.getInt(); if (Into.isNegative() || !Into.isIntN(BitsInSizeT)) return false; - Into = Into.zextOrSelf(BitsInSizeT); + Into = Into.zext(BitsInSizeT); return true; }; @@ -8576,7 +8650,7 @@ static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base, return false; const Expr *Init = VD->getAnyInitializer(); - if (!Init) + if (!Init || Init->getType().isNull()) return false; const Expr *E = Init->IgnoreParens(); @@ -8692,7 +8766,7 @@ public: bool VisitCXXNewExpr(const CXXNewExpr *E); bool VisitSourceLocExpr(const SourceLocExpr *E) { - assert(E->isStringType() && "SourceLocExpr isn't a pointer type?"); + assert(!E->isIntType() && "SourceLocExpr isn't a pointer type?"); APValue LValResult = E->EvaluateInContext( Info.Ctx, Info.CurrentCall->CurSourceLocExprScope.getDefaultExpr()); Result.setFrom(Info.Ctx, LValResult); @@ -8709,7 +8783,7 @@ public: ArrayType::Normal, 0); StringLiteral *SL = - StringLiteral::Create(Info.Ctx, ResultStr, StringLiteral::Ascii, + StringLiteral::Create(Info.Ctx, ResultStr, StringLiteral::Ordinary, /*Pascal*/ false, ArrayTy, E->getLocation()); evaluateLValue(SL, Result); @@ -8757,6 +8831,22 @@ bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { return evaluateLValue(E->getSubExpr(), Result); } +// Is the provided decl 'std::source_location::current'? +static bool IsDeclSourceLocationCurrent(const FunctionDecl *FD) { + if (!FD) + return false; + const IdentifierInfo *FnII = FD->getIdentifier(); + if (!FnII || !FnII->isStr("current")) + return false; + + const auto *RD = dyn_cast<RecordDecl>(FD->getParent()); + if (!RD) + return false; + + const IdentifierInfo *ClassII = RD->getIdentifier(); + return RD->isInStdNamespace() && ClassII && ClassII->isStr("source_location"); +} + bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { const Expr *SubExpr = E->getSubExpr(); @@ -8774,14 +8864,24 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) { // permitted in constant expressions in C++11. Bitcasts from cv void* are // also static_casts, but we disallow them as a resolution to DR1312. if (!E->getType()->isVoidPointerType()) { - if (!Result.InvalidBase && !Result.Designator.Invalid && + // In some circumstances, we permit casting from void* to cv1 T*, when the + // actual pointee object is actually a cv2 T. + bool VoidPtrCastMaybeOK = + !Result.InvalidBase && !Result.Designator.Invalid && !Result.IsNullPtr && Info.Ctx.hasSameUnqualifiedType(Result.Designator.getType(Info.Ctx), - E->getType()->getPointeeType()) && - Info.getStdAllocatorCaller("allocate")) { - // Inside a call to std::allocator::allocate and friends, we permit - // casting from void* back to cv1 T* for a pointer that points to a - // cv2 T. + E->getType()->getPointeeType()); + // 1. We'll allow it in std::allocator::allocate, and anything which that + // calls. + // 2. HACK 2022-03-28: Work around an issue with libstdc++'s + // <source_location> header. Fixed in GCC 12 and later (2022-04-??). + // We'll allow it in the body of std::source_location::current. GCC's + // implementation had a parameter of type `void*`, and casts from + // that back to `const __impl*` in its body. + if (VoidPtrCastMaybeOK && + (Info.getStdAllocatorCaller("allocate") || + IsDeclSourceLocationCurrent(Info.CurrentCall->Callee))) { + // Permitted. } else { Result.Designator.setInvalid(); if (SubExpr->getType()->isVoidPointerType()) @@ -9004,6 +9104,8 @@ static bool isOneByteCharacterType(QualType T) { bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinOp) { switch (BuiltinOp) { + case Builtin::BIaddressof: + case Builtin::BI__addressof: case Builtin::BI__builtin_addressof: return evaluateLValue(E->getArg(0), Result); case Builtin::BI__builtin_assume_aligned: { @@ -9421,7 +9523,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { bool ValueInit = false; QualType AllocType = E->getAllocatedType(); - if (Optional<const Expr*> ArraySize = E->getArraySize()) { + if (Optional<const Expr *> ArraySize = E->getArraySize()) { const Expr *Stripped = *ArraySize; for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped); Stripped = ICE->getSubExpr()) @@ -9475,8 +9577,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { unsigned Bits = std::max(CAT->getSize().getBitWidth(), ArrayBound.getBitWidth()); - llvm::APInt InitBound = CAT->getSize().zextOrSelf(Bits); - llvm::APInt AllocBound = ArrayBound.zextOrSelf(Bits); + llvm::APInt InitBound = CAT->getSize().zext(Bits); + llvm::APInt AllocBound = ArrayBound.zext(Bits); if (InitBound.ugt(AllocBound)) { if (IsNothrow) return ZeroInitialization(E); @@ -9914,6 +10016,17 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType()); const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE; + if (Field->getType()->isIncompleteArrayType()) { + if (auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType())) { + if (!CAT->getSize().isZero()) { + // Bail out for now. This might sort of "work", but the rest of the + // code isn't really prepared to handle it. + Info.FFDiag(Init, diag::note_constexpr_unsupported_flexible_array); + return false; + } + } + } + // Temporarily override This, in case there's a CXXDefaultInitExpr in here. ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This, isa<CXXDefaultInitExpr>(Init)); @@ -10079,7 +10192,6 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) { // Iterate through all the lambda's closure object's fields and initialize // them. auto *CaptureInitIt = E->capture_init_begin(); - const LambdaCapture *CaptureIt = ClosureClass->captures_begin(); bool Success = true; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(ClosureClass); for (const auto *Field : ClosureClass->fields()) { @@ -10103,7 +10215,6 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) { return false; Success = false; } - ++CaptureIt; } return Success; } @@ -10261,9 +10372,9 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) { for (unsigned i = 0; i < NElts; i++) { llvm::APInt Elt; if (BigEndian) - Elt = SValInt.rotl(i*EltSize+FloatEltSize).trunc(FloatEltSize); + Elt = SValInt.rotl(i * EltSize + FloatEltSize).trunc(FloatEltSize); else - Elt = SValInt.rotr(i*EltSize).trunc(FloatEltSize); + Elt = SValInt.rotr(i * EltSize).trunc(FloatEltSize); Elts.push_back(APValue(APFloat(Sem, Elt))); } } else if (EltTy->isIntegerType()) { @@ -13764,10 +13875,12 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_huge_val: case Builtin::BI__builtin_huge_valf: case Builtin::BI__builtin_huge_vall: + case Builtin::BI__builtin_huge_valf16: case Builtin::BI__builtin_huge_valf128: case Builtin::BI__builtin_inf: case Builtin::BI__builtin_inff: case Builtin::BI__builtin_infl: + case Builtin::BI__builtin_inff16: case Builtin::BI__builtin_inff128: { const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType()); @@ -13778,6 +13891,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_nans: case Builtin::BI__builtin_nansf: case Builtin::BI__builtin_nansl: + case Builtin::BI__builtin_nansf16: case Builtin::BI__builtin_nansf128: if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), true, Result)) @@ -13787,6 +13901,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { case Builtin::BI__builtin_nan: case Builtin::BI__builtin_nanf: case Builtin::BI__builtin_nanl: + case Builtin::BI__builtin_nanf16: case Builtin::BI__builtin_nanf128: // If this is __builtin_nan() turn this into a nan, otherwise we // can't constant fold it. |
