diff options
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
| -rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 813 |
1 files changed, 522 insertions, 291 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index a71cb8b0143b..2376e482a19f 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -114,15 +114,6 @@ namespace { return Ctx.getLValueReferenceType(E->getType()); } - /// Given a CallExpr, try to get the alloc_size attribute. May return null. - static const AllocSizeAttr *getAllocSizeAttr(const CallExpr *CE) { - if (const FunctionDecl *DirectCallee = CE->getDirectCallee()) - return DirectCallee->getAttr<AllocSizeAttr>(); - if (const Decl *IndirectCallee = CE->getCalleeDecl()) - return IndirectCallee->getAttr<AllocSizeAttr>(); - return nullptr; - } - /// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr. /// This will look through a single cast. /// @@ -142,7 +133,7 @@ namespace { E = Cast->getSubExpr()->IgnoreParens(); if (const auto *CE = dyn_cast<CallExpr>(E)) - return getAllocSizeAttr(CE) ? CE : nullptr; + return CE->getCalleeAllocSizeAttr() ? CE : nullptr; return nullptr; } @@ -465,49 +456,7 @@ namespace { void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, const APSInt &N); /// Add N to the address of this subobject. - void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) { - if (Invalid || !N) return; - uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(); - if (isMostDerivedAnUnsizedArray()) { - diagnoseUnsizedArrayPointerArithmetic(Info, E); - // Can't verify -- trust that the user is doing the right thing (or if - // not, trust that the caller will catch the bad behavior). - // FIXME: Should we reject if this overflows, at least? - Entries.back() = PathEntry::ArrayIndex( - Entries.back().getAsArrayIndex() + TruncatedN); - return; - } - - // [expr.add]p4: For the purposes of these operators, a pointer to a - // nonarray object behaves the same as a pointer to the first element of - // an array of length one with the type of the object as its element type. - bool IsArray = MostDerivedPathLength == Entries.size() && - MostDerivedIsArrayElement; - uint64_t ArrayIndex = IsArray ? Entries.back().getAsArrayIndex() - : (uint64_t)IsOnePastTheEnd; - uint64_t ArraySize = - IsArray ? getMostDerivedArraySize() : (uint64_t)1; - - if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) { - // Calculate the actual index in a wide enough type, so we can include - // it in the note. - N = N.extend(std::max<unsigned>(N.getBitWidth() + 1, 65)); - (llvm::APInt&)N += ArrayIndex; - assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index"); - diagnosePointerArithmetic(Info, E, N); - setInvalid(); - return; - } - - ArrayIndex += TruncatedN; - assert(ArrayIndex <= ArraySize && - "bounds check succeeded for out-of-bounds index"); - - if (IsArray) - Entries.back() = PathEntry::ArrayIndex(ArrayIndex); - else - IsOnePastTheEnd = (ArrayIndex != 0); - } + void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N, const LValue &LV); }; /// A scope at the end of which an object can need to be destroyed. @@ -894,6 +843,11 @@ namespace { /// declaration whose initializer is being evaluated, if any. APValue *EvaluatingDeclValue; + /// Stack of loops and 'switch' statements which we're currently + /// breaking/continuing; null entries are used to mark unlabeled + /// break/continue. + SmallVector<const Stmt *> BreakContinueStack; + /// Set of objects that are currently being constructed. llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase> ObjectsUnderConstruction; @@ -972,19 +926,6 @@ namespace { /// fold (not just why it's not strictly a constant expression)? bool HasFoldFailureDiagnostic; - /// 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). - bool CheckingPotentialConstantExpression = false; - - /// Whether we're checking for an expression that has undefined behavior. - /// If so, we will produce warnings if we encounter an operation that is - /// always undefined. - /// - /// Note that we still need to evaluate the expression normally when this - /// is set; this is used when evaluating ICEs in C. - bool CheckingForUndefinedBehavior = false; - enum EvaluationMode { /// Evaluate as a constant expression. Stop if we find that the expression /// is not a constant expression. @@ -1006,19 +947,6 @@ namespace { EM_IgnoreSideEffects, } EvalMode; - /// Are we checking whether the expression is a potential constant - /// expression? - bool checkingPotentialConstantExpression() const override { - return CheckingPotentialConstantExpression; - } - - /// Are we checking an expression for overflow? - // FIXME: We should check for any kind of undefined or suspicious behavior - // in such constructs, not just overflow. - bool checkingForUndefinedBehavior() const override { - return CheckingForUndefinedBehavior; - } - EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode) : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr), CallStackDepth(0), NextCallIndex(1), @@ -1799,7 +1727,7 @@ namespace { Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64); if (checkNullPointer(Info, E, CSK_ArrayIndex)) - Designator.adjustIndex(Info, E, Index); + Designator.adjustIndex(Info, E, Index, *this); clearIsNullPointer(); } void adjustOffset(CharUnits N) { @@ -1907,6 +1835,54 @@ namespace { } } +void SubobjectDesignator::adjustIndex(EvalInfo &Info, const Expr *E, APSInt N, + const LValue &LV) { + if (Invalid || !N) + return; + uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(); + if (isMostDerivedAnUnsizedArray()) { + diagnoseUnsizedArrayPointerArithmetic(Info, E); + // Can't verify -- trust that the user is doing the right thing (or if + // not, trust that the caller will catch the bad behavior). + // FIXME: Should we reject if this overflows, at least? + Entries.back() = + PathEntry::ArrayIndex(Entries.back().getAsArrayIndex() + TruncatedN); + return; + } + + // [expr.add]p4: For the purposes of these operators, a pointer to a + // nonarray object behaves the same as a pointer to the first element of + // an array of length one with the type of the object as its element type. + bool IsArray = + MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement; + uint64_t ArrayIndex = + IsArray ? Entries.back().getAsArrayIndex() : (uint64_t)IsOnePastTheEnd; + uint64_t ArraySize = IsArray ? getMostDerivedArraySize() : (uint64_t)1; + + if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) { + if (!Info.checkingPotentialConstantExpression() || + !LV.AllowConstexprUnknown) { + // Calculate the actual index in a wide enough type, so we can include + // it in the note. + N = N.extend(std::max<unsigned>(N.getBitWidth() + 1, 65)); + (llvm::APInt &)N += ArrayIndex; + assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index"); + diagnosePointerArithmetic(Info, E, N); + } + setInvalid(); + return; + } + + ArrayIndex += TruncatedN; + assert(ArrayIndex <= ArraySize && + "bounds check succeeded for out-of-bounds index"); + + if (IsArray) + Entries.back() = PathEntry::ArrayIndex(ArrayIndex); + else + IsOnePastTheEnd = (ArrayIndex != 0); +} + static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E); static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This, const Expr *E, @@ -2623,8 +2599,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK, Value.getUnionValue(), Kind, Value.getUnionField(), CheckedTemps); } if (Value.isStruct()) { - RecordDecl *RD = - Type->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); + auto *RD = Type->castAsRecordDecl(); if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) { unsigned BaseIndex = 0; for (const CXXBaseSpecifier &BS : CD->bases()) { @@ -4029,10 +4004,12 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, LastField = nullptr; if (ObjType->isArrayType()) { // Next subobject is an array element. - const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType); - assert(CAT && "vla in literal type?"); + const ArrayType *AT = Info.Ctx.getAsArrayType(ObjType); + assert((isa<ConstantArrayType>(AT) || isa<IncompleteArrayType>(AT)) && + "vla in literal type?"); uint64_t Index = Sub.Entries[I].getAsArrayIndex(); - if (CAT->getSize().ule(Index)) { + if (const auto *CAT = dyn_cast<ConstantArrayType>(AT); + CAT && CAT->getSize().ule(Index)) { // Note, it should not be possible to form a pointer with a valid // designator which points more than one past the end of the array. if (Info.getLangOpts().CPlusPlus11) @@ -4043,12 +4020,13 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, return handler.failed(); } - ObjType = CAT->getElementType(); + ObjType = AT->getElementType(); if (O->getArrayInitializedElts() > Index) O = &O->getArrayInitializedElt(Index); else if (!isRead(handler.AccessKind)) { - if (!CheckArraySize(Info, CAT, E->getExprLoc())) + if (const auto *CAT = dyn_cast<ConstantArrayType>(AT); + CAT && !CheckArraySize(Info, CAT, E->getExprLoc())) return handler.failed(); expandArray(*O, Index); @@ -4110,7 +4088,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, } // Next subobject is a class, struct or union field. - RecordDecl *RD = ObjType->castAs<RecordType>()->getOriginalDecl(); + RecordDecl *RD = + ObjType->castAsCanonical<RecordType>()->getOriginalDecl(); if (RD->isUnion()) { const FieldDecl *UnionField = O->getUnionField(); if (!UnionField || @@ -5148,12 +5127,18 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E, if (const PointerType *PT = TargetQT->getAs<PointerType>()) TargetQT = PT->getPointeeType(); - // Check this cast lands within the final derived-to-base subobject path. - if (D.MostDerivedPathLength + E->path_size() > D.Entries.size()) { - Info.CCEDiag(E, diag::note_constexpr_invalid_downcast) - << D.MostDerivedType << TargetQT; + auto InvalidCast = [&]() { + if (!Info.checkingPotentialConstantExpression() || + !Result.AllowConstexprUnknown) { + Info.CCEDiag(E, diag::note_constexpr_invalid_downcast) + << D.MostDerivedType << TargetQT; + } return false; - } + }; + + // Check this cast lands within the final derived-to-base subobject path. + if (D.MostDerivedPathLength + E->path_size() > D.Entries.size()) + return InvalidCast(); // Check the type of the final cast. We don't need to check the path, // since a cast can only be formed if the path is unique. @@ -5164,11 +5149,8 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E, FinalType = D.MostDerivedType->getAsCXXRecordDecl(); else FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]); - if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) { - Info.CCEDiag(E, diag::note_constexpr_invalid_downcast) - << D.MostDerivedType << TargetQT; - return false; - } + if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) + return InvalidCast(); // Truncate the lvalue to the appropriate derived class. return CastToDerivedClass(Info, E, Result, TargetType, NewEntriesSize); @@ -5386,6 +5368,44 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, const Stmt *S, const SwitchCase *SC = nullptr); +/// Helper to implement named break/continue. Returns 'true' if the evaluation +/// result should be propagated up. Otherwise, it sets the evaluation result +/// to either Continue to continue the current loop, or Succeeded to break it. +static bool ShouldPropagateBreakContinue(EvalInfo &Info, + const Stmt *LoopOrSwitch, + ArrayRef<BlockScopeRAII *> Scopes, + EvalStmtResult &ESR) { + bool IsSwitch = isa<SwitchStmt>(LoopOrSwitch); + + // For loops, map Succeeded to Continue so we don't have to check for both. + if (!IsSwitch && ESR == ESR_Succeeded) { + ESR = ESR_Continue; + return false; + } + + if (ESR != ESR_Break && ESR != ESR_Continue) + return false; + + // Are we breaking out of or continuing this statement? + bool CanBreakOrContinue = !IsSwitch || ESR == ESR_Break; + const Stmt *StackTop = Info.BreakContinueStack.back(); + if (CanBreakOrContinue && (StackTop == nullptr || StackTop == LoopOrSwitch)) { + Info.BreakContinueStack.pop_back(); + if (ESR == ESR_Break) + ESR = ESR_Succeeded; + return false; + } + + // We're not. Propagate the result up. + for (BlockScopeRAII *S : Scopes) { + if (!S->destroy()) { + ESR = ESR_Failed; + break; + } + } + return true; +} + /// Evaluate the body of a loop, and translate the result as appropriate. static EvalStmtResult EvaluateLoopBody(StmtResult &Result, EvalInfo &Info, const Stmt *Body, @@ -5396,18 +5416,7 @@ static EvalStmtResult EvaluateLoopBody(StmtResult &Result, EvalInfo &Info, if (ESR != ESR_Failed && ESR != ESR_CaseNotFound && !Scope.destroy()) ESR = ESR_Failed; - switch (ESR) { - case ESR_Break: - return ESR_Succeeded; - case ESR_Succeeded: - case ESR_Continue: - return ESR_Continue; - case ESR_Failed: - case ESR_Returned: - case ESR_CaseNotFound: - return ESR; - } - llvm_unreachable("Invalid EvalStmtResult!"); + return ESR; } /// Evaluate a switch statement. @@ -5473,10 +5482,12 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info, EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found); if (ESR != ESR_Failed && ESR != ESR_CaseNotFound && !Scope.destroy()) return ESR_Failed; + if (ShouldPropagateBreakContinue(Info, SS, /*Scopes=*/{}, ESR)) + return ESR; switch (ESR) { case ESR_Break: - return ESR_Succeeded; + llvm_unreachable("Should have been converted to Succeeded"); case ESR_Succeeded: case ESR_Continue: case ESR_Failed: @@ -5574,6 +5585,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, case Stmt::WhileStmtClass: { EvalStmtResult ESR = EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(), Case); + if (ShouldPropagateBreakContinue(Info, S, /*Scopes=*/{}, ESR)) + return ESR; if (ESR != ESR_Continue) return ESR; break; @@ -5595,6 +5608,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody(), Case); + if (ShouldPropagateBreakContinue(Info, FS, /*Scopes=*/{}, ESR)) + return ESR; if (ESR != ESR_Continue) return ESR; if (const auto *Inc = FS->getInc()) { @@ -5757,6 +5772,9 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, break; EvalStmtResult ESR = EvaluateLoopBody(Result, Info, WS->getBody()); + if (ShouldPropagateBreakContinue(Info, WS, &Scope, ESR)) + return ESR; + if (ESR != ESR_Continue) { if (ESR != ESR_Failed && !Scope.destroy()) return ESR_Failed; @@ -5773,6 +5791,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, bool Continue; do { EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case); + if (ShouldPropagateBreakContinue(Info, DS, /*Scopes=*/{}, ESR)) + return ESR; if (ESR != ESR_Continue) return ESR; Case = nullptr; @@ -5815,6 +5835,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, } EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody()); + if (ShouldPropagateBreakContinue(Info, FS, {&IterScope, &ForScope}, ESR)) + return ESR; if (ESR != ESR_Continue) { if (ESR != ESR_Failed && (!IterScope.destroy() || !ForScope.destroy())) return ESR_Failed; @@ -5906,6 +5928,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, // Loop body. ESR = EvaluateLoopBody(Result, Info, FS->getBody()); + if (ShouldPropagateBreakContinue(Info, FS, {&InnerScope, &Scope}, ESR)) + return ESR; if (ESR != ESR_Continue) { if (ESR != ESR_Failed && (!InnerScope.destroy() || !Scope.destroy())) return ESR_Failed; @@ -5931,10 +5955,11 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S)); case Stmt::ContinueStmtClass: - return ESR_Continue; - - case Stmt::BreakStmtClass: - return ESR_Break; + case Stmt::BreakStmtClass: { + auto *B = cast<LoopControlStmt>(S); + Info.BreakContinueStack.push_back(B->getNamedLoopOrSwitch()); + return isa<ContinueStmt>(S) ? ESR_Continue : ESR_Break; + } case Stmt::LabelStmtClass: return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(), Case); @@ -6126,12 +6151,15 @@ static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This, } else if (Polymorphic) { // Conservatively refuse to perform a polymorphic operation if we would // not be able to read a notional 'vptr' value. - APValue Val; - This.moveInto(Val); - QualType StarThisType = - Info.Ctx.getLValueReferenceType(This.Designator.getType(Info.Ctx)); - Info.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type) - << AK << Val.getAsString(Info.Ctx, StarThisType); + if (!Info.checkingPotentialConstantExpression() || + !This.AllowConstexprUnknown) { + APValue Val; + This.moveInto(Val); + QualType StarThisType = + Info.Ctx.getLValueReferenceType(This.Designator.getType(Info.Ctx)); + Info.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type) + << AK << Val.getAsString(Info.Ctx, StarThisType); + } return false; } return true; @@ -7984,8 +8012,9 @@ static bool checkBitCastConstexprEligibilityType(SourceLocation Loc, // so its layout is unspecified. For now, we'll simply treat these cases // as unsupported (this should only be possible with OpenCL bool vectors // whose element count isn't a multiple of the byte size). - Info->FFDiag(Loc, diag::note_constexpr_bit_cast_invalid_vector) - << QualType(VTy, 0) << EltSize << NElts << Ctx.getCharWidth(); + if (Info) + Info->FFDiag(Loc, diag::note_constexpr_bit_cast_invalid_vector) + << QualType(VTy, 0) << EltSize << NElts << Ctx.getCharWidth(); return false; } @@ -7994,8 +8023,9 @@ static bool checkBitCastConstexprEligibilityType(SourceLocation Loc, // The layout for x86_fp80 vectors seems to be handled very inconsistently // by both clang and LLVM, so for now we won't allow bit_casts involving // it in a constexpr context. - Info->FFDiag(Loc, diag::note_constexpr_bit_cast_unsupported_type) - << EltTy; + if (Info) + Info->FFDiag(Loc, diag::note_constexpr_bit_cast_unsupported_type) + << EltTy; return false; } } @@ -8591,10 +8621,9 @@ public: const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); if (!FD) return Error(E); assert(!FD->getType()->isReferenceType() && "prvalue reference?"); - assert( - BaseTy->castAs<RecordType>()->getOriginalDecl()->getCanonicalDecl() == - FD->getParent()->getCanonicalDecl() && - "record / field mismatch"); + assert(BaseTy->castAsCanonical<RecordType>()->getOriginalDecl() == + FD->getParent()->getCanonicalDecl() && + "record / field mismatch"); // Note: there is no lvalue base here. But this case should only ever // happen in C or in C++98, where we cannot be evaluating a constexpr @@ -8821,10 +8850,9 @@ public: const ValueDecl *MD = E->getMemberDecl(); if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) { - assert( - BaseTy->castAs<RecordType>()->getOriginalDecl()->getCanonicalDecl() == - FD->getParent()->getCanonicalDecl() && - "record / field mismatch"); + assert(BaseTy->castAsCanonical<RecordType>()->getOriginalDecl() == + FD->getParent()->getCanonicalDecl() && + "record / field mismatch"); (void)BaseTy; if (!HandleLValueMember(this->Info, E, Result, FD)) return false; @@ -9466,57 +9494,6 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { // Pointer Evaluation //===----------------------------------------------------------------------===// -/// Attempts to compute the number of bytes available at the pointer -/// returned by a function with the alloc_size attribute. Returns true if we -/// were successful. Places an unsigned number into `Result`. -/// -/// This expects the given CallExpr to be a call to a function with an -/// alloc_size attribute. -static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, - const CallExpr *Call, - llvm::APInt &Result) { - const AllocSizeAttr *AllocSize = getAllocSizeAttr(Call); - - assert(AllocSize && AllocSize->getElemSizeParam().isValid()); - unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex(); - unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType()); - if (Call->getNumArgs() <= SizeArgNo) - return false; - - auto EvaluateAsSizeT = [&](const Expr *E, APSInt &Into) { - Expr::EvalResult ExprResult; - if (!E->EvaluateAsInt(ExprResult, Ctx, Expr::SE_AllowSideEffects)) - return false; - Into = ExprResult.Val.getInt(); - if (Into.isNegative() || !Into.isIntN(BitsInSizeT)) - return false; - Into = Into.zext(BitsInSizeT); - return true; - }; - - APSInt SizeOfElem; - if (!EvaluateAsSizeT(Call->getArg(SizeArgNo), SizeOfElem)) - return false; - - if (!AllocSize->getNumElemsParam().isValid()) { - Result = std::move(SizeOfElem); - return true; - } - - APSInt NumberOfElems; - unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex(); - if (!EvaluateAsSizeT(Call->getArg(NumArgNo), NumberOfElems)) - return false; - - bool Overflow; - llvm::APInt BytesAvailable = SizeOfElem.umul_ov(NumberOfElems, Overflow); - if (Overflow) - return false; - - Result = std::move(BytesAvailable); - return true; -} - /// Convenience function. LVal's base must be a call to an alloc_size /// function. static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, @@ -9526,7 +9503,13 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx, "Can't get the size of a non alloc_size function"); const auto *Base = LVal.getLValueBase().get<const Expr *>(); const CallExpr *CE = tryUnwrapAllocSizeCall(Base); - return getBytesReturnedByAllocSizeCall(Ctx, CE, Result); + std::optional<llvm::APInt> Size = + CE->evaluateBytesReturnedByAllocSizeCall(Ctx); + if (!Size) + return false; + + Result = std::move(*Size); + return true; } /// Attempts to evaluate the given LValueBase as the result of a call to @@ -10017,7 +10000,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) { if (ExprEvaluatorBaseTy::VisitCallExpr(E)) return true; - if (!(InvalidBaseOK && getAllocSizeAttr(E))) + if (!(InvalidBaseOK && E->getCalleeAllocSizeAttr())) return false; Result.setInvalid(E); @@ -10824,8 +10807,7 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E, } bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) { - const RecordDecl *RD = - T->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = T->castAsRecordDecl(); if (RD->isInvalidDecl()) return false; if (RD->isUnion()) { // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the @@ -10894,10 +10876,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) { bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr( const Expr *ExprToVisit, ArrayRef<Expr *> Args) { - const RecordDecl *RD = ExprToVisit->getType() - ->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + const auto *RD = ExprToVisit->getType()->castAsRecordDecl(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD); auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); @@ -11121,10 +11100,7 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr( Result = APValue(APValue::UninitStruct(), 0, 2); Array.moveInto(Result.getStructField(0)); - RecordDecl *Record = E->getType() - ->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *Record = E->getType()->castAsRecordDecl(); RecordDecl::field_iterator Field = Record->field_begin(); assert(Field != Record->field_end() && Info.Ctx.hasSameType(Field->getType()->getPointeeType(), @@ -11310,6 +11286,24 @@ static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) { return VectorExprEvaluator(Info, Result).Visit(E); } +static llvm::APInt ConvertBoolVectorToInt(const APValue &Val) { + assert(Val.isVector() && "expected vector APValue"); + unsigned NumElts = Val.getVectorLength(); + + // Each element is one bit, so create an integer with NumElts bits. + llvm::APInt Result(NumElts, 0); + + for (unsigned I = 0; I < NumElts; ++I) { + const APValue &Elt = Val.getVectorElt(I); + assert(Elt.isInt() && "expected integer element in bool vector"); + + if (Elt.getInt().getBoolValue()) + Result.setBit(I); + } + + return Result; +} + bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) { const VectorType *VTy = E->getType()->castAs<VectorType>(); unsigned NElts = VTy->getNumElements(); @@ -11603,6 +11597,38 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { if (!IsConstantEvaluatedBuiltinCall(E)) return ExprEvaluatorBaseTy::VisitCallExpr(E); + auto EvaluateBinOpExpr = + [&](llvm::function_ref<APInt(const APSInt &, const APSInt &)> Fn) { + APValue SourceLHS, SourceRHS; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || + !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) + return false; + + auto *DestTy = E->getType()->castAs<VectorType>(); + QualType DestEltTy = DestTy->getElementType(); + bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType(); + unsigned SourceLen = SourceLHS.getVectorLength(); + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(SourceLen); + + if (SourceRHS.isInt()) { + const APSInt &RHS = SourceRHS.getInt(); + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt(); + ResultElements.push_back( + APValue(APSInt(Fn(LHS, RHS), DestUnsigned))); + } + } else { + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt(); + const APSInt &RHS = SourceRHS.getVectorElt(EltNum).getInt(); + ResultElements.push_back( + APValue(APSInt(Fn(LHS, RHS), DestUnsigned))); + } + } + return Success(APValue(ResultElements.data(), SourceLen), E); + }; + switch (E->getBuiltinCallee()) { default: return false; @@ -11659,99 +11685,108 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { } case Builtin::BI__builtin_elementwise_add_sat: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + return LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS); + }); + case Builtin::BI__builtin_elementwise_sub_sat: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS); + }); + + case clang::X86::BI__builtin_ia32_pavgb128: + case clang::X86::BI__builtin_ia32_pavgw128: + case clang::X86::BI__builtin_ia32_pavgb256: + case clang::X86::BI__builtin_ia32_pavgw256: + case clang::X86::BI__builtin_ia32_pavgb512: + case clang::X86::BI__builtin_ia32_pavgw512: + return EvaluateBinOpExpr(llvm::APIntOps::avgCeilU); + case clang::X86::BI__builtin_ia32_pmulhuw128: case clang::X86::BI__builtin_ia32_pmulhuw256: case clang::X86::BI__builtin_ia32_pmulhuw512: + return EvaluateBinOpExpr(llvm::APIntOps::mulhu); + case clang::X86::BI__builtin_ia32_pmulhw128: case clang::X86::BI__builtin_ia32_pmulhw256: case clang::X86::BI__builtin_ia32_pmulhw512: + return EvaluateBinOpExpr(llvm::APIntOps::mulhs); + case clang::X86::BI__builtin_ia32_psllv2di: case clang::X86::BI__builtin_ia32_psllv4di: case clang::X86::BI__builtin_ia32_psllv4si: + case clang::X86::BI__builtin_ia32_psllv8di: + case clang::X86::BI__builtin_ia32_psllv8hi: case clang::X86::BI__builtin_ia32_psllv8si: + case clang::X86::BI__builtin_ia32_psllv16hi: + case clang::X86::BI__builtin_ia32_psllv16si: + case clang::X86::BI__builtin_ia32_psllv32hi: + case clang::X86::BI__builtin_ia32_psllwi128: + case clang::X86::BI__builtin_ia32_pslldi128: + case clang::X86::BI__builtin_ia32_psllqi128: + case clang::X86::BI__builtin_ia32_psllwi256: + case clang::X86::BI__builtin_ia32_pslldi256: + case clang::X86::BI__builtin_ia32_psllqi256: + case clang::X86::BI__builtin_ia32_psllwi512: + case clang::X86::BI__builtin_ia32_pslldi512: + case clang::X86::BI__builtin_ia32_psllqi512: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + if (RHS.uge(LHS.getBitWidth())) { + return APInt::getZero(LHS.getBitWidth()); + } + return LHS.shl(RHS.getZExtValue()); + }); + case clang::X86::BI__builtin_ia32_psrav4si: + case clang::X86::BI__builtin_ia32_psrav8di: + case clang::X86::BI__builtin_ia32_psrav8hi: case clang::X86::BI__builtin_ia32_psrav8si: + case clang::X86::BI__builtin_ia32_psrav16hi: + case clang::X86::BI__builtin_ia32_psrav16si: + case clang::X86::BI__builtin_ia32_psrav32hi: + case clang::X86::BI__builtin_ia32_psravq128: + case clang::X86::BI__builtin_ia32_psravq256: + case clang::X86::BI__builtin_ia32_psrawi128: + case clang::X86::BI__builtin_ia32_psradi128: + case clang::X86::BI__builtin_ia32_psraqi128: + case clang::X86::BI__builtin_ia32_psrawi256: + case clang::X86::BI__builtin_ia32_psradi256: + case clang::X86::BI__builtin_ia32_psraqi256: + case clang::X86::BI__builtin_ia32_psrawi512: + case clang::X86::BI__builtin_ia32_psradi512: + case clang::X86::BI__builtin_ia32_psraqi512: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + if (RHS.uge(LHS.getBitWidth())) { + return LHS.ashr(LHS.getBitWidth() - 1); + } + return LHS.ashr(RHS.getZExtValue()); + }); + case clang::X86::BI__builtin_ia32_psrlv2di: case clang::X86::BI__builtin_ia32_psrlv4di: case clang::X86::BI__builtin_ia32_psrlv4si: - case clang::X86::BI__builtin_ia32_psrlv8si:{ - APValue SourceLHS, SourceRHS; - if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) || - !EvaluateAsRValue(Info, E->getArg(1), SourceRHS)) - return false; - - QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); - bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType(); - unsigned SourceLen = SourceLHS.getVectorLength(); - SmallVector<APValue, 4> ResultElements; - ResultElements.reserve(SourceLen); - - for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { - APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt(); - APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt(); - switch (E->getBuiltinCallee()) { - case Builtin::BI__builtin_elementwise_add_sat: - ResultElements.push_back(APValue( - APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS), - DestUnsigned))); - break; - case Builtin::BI__builtin_elementwise_sub_sat: - ResultElements.push_back(APValue( - APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS), - DestUnsigned))); - break; - case clang::X86::BI__builtin_ia32_pmulhuw128: - case clang::X86::BI__builtin_ia32_pmulhuw256: - case clang::X86::BI__builtin_ia32_pmulhuw512: - ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhu(LHS, RHS), - /*isUnsigned=*/true))); - break; - case clang::X86::BI__builtin_ia32_pmulhw128: - case clang::X86::BI__builtin_ia32_pmulhw256: - case clang::X86::BI__builtin_ia32_pmulhw512: - ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhs(LHS, RHS), - /*isUnsigned=*/false))); - break; - case clang::X86::BI__builtin_ia32_psllv2di: - case clang::X86::BI__builtin_ia32_psllv4di: - case clang::X86::BI__builtin_ia32_psllv4si: - case clang::X86::BI__builtin_ia32_psllv8si: - if (RHS.uge(RHS.getBitWidth())) { - ResultElements.push_back( - APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned))); - break; - } - ResultElements.push_back( - APValue(APSInt(LHS.shl(RHS.getZExtValue()), DestUnsigned))); - break; - case clang::X86::BI__builtin_ia32_psrav4si: - case clang::X86::BI__builtin_ia32_psrav8si: - if (RHS.uge(RHS.getBitWidth())) { - ResultElements.push_back( - APValue(APSInt(LHS.ashr(RHS.getBitWidth() - 1), DestUnsigned))); - break; - } - ResultElements.push_back( - APValue(APSInt(LHS.ashr(RHS.getZExtValue()), DestUnsigned))); - break; - case clang::X86::BI__builtin_ia32_psrlv2di: - case clang::X86::BI__builtin_ia32_psrlv4di: - case clang::X86::BI__builtin_ia32_psrlv4si: - case clang::X86::BI__builtin_ia32_psrlv8si: - if (RHS.uge(RHS.getBitWidth())) { - ResultElements.push_back( - APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned))); - break; - } - ResultElements.push_back( - APValue(APSInt(LHS.lshr(RHS.getZExtValue()), DestUnsigned))); - break; + case clang::X86::BI__builtin_ia32_psrlv8di: + case clang::X86::BI__builtin_ia32_psrlv8hi: + case clang::X86::BI__builtin_ia32_psrlv8si: + case clang::X86::BI__builtin_ia32_psrlv16hi: + case clang::X86::BI__builtin_ia32_psrlv16si: + case clang::X86::BI__builtin_ia32_psrlv32hi: + case clang::X86::BI__builtin_ia32_psrlwi128: + case clang::X86::BI__builtin_ia32_psrldi128: + case clang::X86::BI__builtin_ia32_psrlqi128: + case clang::X86::BI__builtin_ia32_psrlwi256: + case clang::X86::BI__builtin_ia32_psrldi256: + case clang::X86::BI__builtin_ia32_psrlqi256: + case clang::X86::BI__builtin_ia32_psrlwi512: + case clang::X86::BI__builtin_ia32_psrldi512: + case clang::X86::BI__builtin_ia32_psrlqi512: + return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) { + if (RHS.uge(LHS.getBitWidth())) { + return APInt::getZero(LHS.getBitWidth()); } - } + return LHS.lshr(RHS.getZExtValue()); + }); - return Success(APValue(ResultElements.data(), ResultElements.size()), E); - } case clang::X86::BI__builtin_ia32_pmuldq128: case clang::X86::BI__builtin_ia32_pmuldq256: case clang::X86::BI__builtin_ia32_pmuldq512: @@ -11789,6 +11824,29 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(APValue(ResultElements.data(), ResultElements.size()), E); } + + case clang::X86::BI__builtin_ia32_vprotbi: + case clang::X86::BI__builtin_ia32_vprotdi: + case clang::X86::BI__builtin_ia32_vprotqi: + case clang::X86::BI__builtin_ia32_vprotwi: + case clang::X86::BI__builtin_ia32_prold128: + case clang::X86::BI__builtin_ia32_prold256: + case clang::X86::BI__builtin_ia32_prold512: + case clang::X86::BI__builtin_ia32_prolq128: + case clang::X86::BI__builtin_ia32_prolq256: + case clang::X86::BI__builtin_ia32_prolq512: + return EvaluateBinOpExpr( + [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotl(RHS); }); + + case clang::X86::BI__builtin_ia32_prord128: + case clang::X86::BI__builtin_ia32_prord256: + case clang::X86::BI__builtin_ia32_prord512: + case clang::X86::BI__builtin_ia32_prorq128: + case clang::X86::BI__builtin_ia32_prorq256: + case clang::X86::BI__builtin_ia32_prorq512: + return EvaluateBinOpExpr( + [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotr(RHS); }); + case Builtin::BI__builtin_elementwise_max: case Builtin::BI__builtin_elementwise_min: { APValue SourceLHS, SourceRHS; @@ -11824,6 +11882,96 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(APValue(ResultElements.data(), ResultElements.size()), E); } + case X86::BI__builtin_ia32_vpshldd128: + case X86::BI__builtin_ia32_vpshldd256: + case X86::BI__builtin_ia32_vpshldd512: + case X86::BI__builtin_ia32_vpshldq128: + case X86::BI__builtin_ia32_vpshldq256: + case X86::BI__builtin_ia32_vpshldq512: + case X86::BI__builtin_ia32_vpshldw128: + case X86::BI__builtin_ia32_vpshldw256: + case X86::BI__builtin_ia32_vpshldw512: { + APValue SourceHi, SourceLo, SourceAmt; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceHi) || + !EvaluateAsRValue(Info, E->getArg(1), SourceLo) || + !EvaluateAsRValue(Info, E->getArg(2), SourceAmt)) + return false; + + QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + unsigned SourceLen = SourceHi.getVectorLength(); + SmallVector<APValue, 32> ResultElements; + ResultElements.reserve(SourceLen); + + APInt Amt = SourceAmt.getInt(); + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + APInt Hi = SourceHi.getVectorElt(EltNum).getInt(); + APInt Lo = SourceLo.getVectorElt(EltNum).getInt(); + APInt R = llvm::APIntOps::fshl(Hi, Lo, Amt); + ResultElements.push_back( + APValue(APSInt(R, DestEltTy->isUnsignedIntegerOrEnumerationType()))); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } + case X86::BI__builtin_ia32_vpshrdd128: + case X86::BI__builtin_ia32_vpshrdd256: + case X86::BI__builtin_ia32_vpshrdd512: + case X86::BI__builtin_ia32_vpshrdq128: + case X86::BI__builtin_ia32_vpshrdq256: + case X86::BI__builtin_ia32_vpshrdq512: + case X86::BI__builtin_ia32_vpshrdw128: + case X86::BI__builtin_ia32_vpshrdw256: + case X86::BI__builtin_ia32_vpshrdw512: { + // NOTE: Reversed Hi/Lo operands. + APValue SourceHi, SourceLo, SourceAmt; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceLo) || + !EvaluateAsRValue(Info, E->getArg(1), SourceHi) || + !EvaluateAsRValue(Info, E->getArg(2), SourceAmt)) + return false; + + QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + unsigned SourceLen = SourceHi.getVectorLength(); + SmallVector<APValue, 32> ResultElements; + ResultElements.reserve(SourceLen); + + APInt Amt = SourceAmt.getInt(); + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + APInt Hi = SourceHi.getVectorElt(EltNum).getInt(); + APInt Lo = SourceLo.getVectorElt(EltNum).getInt(); + APInt R = llvm::APIntOps::fshr(Hi, Lo, Amt); + ResultElements.push_back( + APValue(APSInt(R, DestEltTy->isUnsignedIntegerOrEnumerationType()))); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } + case X86::BI__builtin_ia32_blendvpd: + case X86::BI__builtin_ia32_blendvpd256: + case X86::BI__builtin_ia32_blendvps: + case X86::BI__builtin_ia32_blendvps256: + case X86::BI__builtin_ia32_pblendvb128: + case X86::BI__builtin_ia32_pblendvb256: { + // SSE blendv by mask signbit: "Result = C[] < 0 ? T[] : F[]". + APValue SourceF, SourceT, SourceC; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceF) || + !EvaluateAsRValue(Info, E->getArg(1), SourceT) || + !EvaluateAsRValue(Info, E->getArg(2), SourceC)) + return false; + + unsigned SourceLen = SourceF.getVectorLength(); + SmallVector<APValue, 32> ResultElements; + ResultElements.reserve(SourceLen); + + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + const APValue &F = SourceF.getVectorElt(EltNum); + const APValue &T = SourceT.getVectorElt(EltNum); + const APValue &C = SourceC.getVectorElt(EltNum); + APInt M = C.isInt() ? (APInt)C.getInt() : C.getFloat().bitcastToAPInt(); + ResultElements.push_back(M.isNegative() ? T : F); + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } case X86::BI__builtin_ia32_selectb_128: case X86::BI__builtin_ia32_selectb_256: case X86::BI__builtin_ia32_selectb_512: @@ -11937,6 +12085,40 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { } return Success(APValue(ResultElements.data(), ResultElements.size()), E); } + + case Builtin::BI__builtin_elementwise_fshl: + case Builtin::BI__builtin_elementwise_fshr: { + APValue SourceHi, SourceLo, SourceShift; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceHi) || + !EvaluateAsRValue(Info, E->getArg(1), SourceLo) || + !EvaluateAsRValue(Info, E->getArg(2), SourceShift)) + return false; + + QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + if (!DestEltTy->isIntegerType()) + return false; + + unsigned SourceLen = SourceHi.getVectorLength(); + SmallVector<APValue> ResultElements; + ResultElements.reserve(SourceLen); + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + const APSInt &Hi = SourceHi.getVectorElt(EltNum).getInt(); + const APSInt &Lo = SourceLo.getVectorElt(EltNum).getInt(); + const APSInt &Shift = SourceShift.getVectorElt(EltNum).getInt(); + switch (E->getBuiltinCallee()) { + case Builtin::BI__builtin_elementwise_fshl: + ResultElements.push_back(APValue( + APSInt(llvm::APIntOps::fshl(Hi, Lo, Shift), Hi.isUnsigned()))); + break; + case Builtin::BI__builtin_elementwise_fshr: + ResultElements.push_back(APValue( + APSInt(llvm::APIntOps::fshr(Hi, Lo, Shift), Hi.isUnsigned()))); + break; + } + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } } } @@ -13168,10 +13350,7 @@ static bool convertUnsignedAPIntToCharUnits(const llvm::APInt &Int, static void addFlexibleArrayMemberInitSize(EvalInfo &Info, const QualType &T, const LValue &LV, CharUnits &Size) { if (!T.isNull() && T->isStructureType() && - T->getAsStructureType() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) + T->castAsRecordDecl()->hasFlexibleArrayMember()) if (const auto *V = LV.getLValueBase().dyn_cast<const ValueDecl *>()) if (const auto *VD = dyn_cast<VarDecl>(V)) if (VD->hasInit()) @@ -13497,8 +13676,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__lzcnt: case Builtin::BI__lzcnt64: { APSInt Val; - if (!EvaluateInteger(E->getArg(0), Val, Info)) + if (E->getArg(0)->getType()->isExtVectorBoolType()) { + APValue Vec; + if (!EvaluateVector(E->getArg(0), Vec, Info)) + return false; + Val = ConvertBoolVectorToInt(Vec); + } else if (!EvaluateInteger(E->getArg(0), Val, Info)) { return false; + } std::optional<APSInt> Fallback; if ((BuiltinOp == Builtin::BI__builtin_clzg || @@ -13583,8 +13768,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_ctzg: case Builtin::BI__builtin_elementwise_cttz: { APSInt Val; - if (!EvaluateInteger(E->getArg(0), Val, Info)) + if (E->getArg(0)->getType()->isExtVectorBoolType()) { + APValue Vec; + if (!EvaluateVector(E->getArg(0), Vec, Info)) + return false; + Val = ConvertBoolVectorToInt(Vec); + } else if (!EvaluateInteger(E->getArg(0), Val, Info)) { return false; + } std::optional<APSInt> Fallback; if ((BuiltinOp == Builtin::BI__builtin_ctzg || @@ -13799,8 +13990,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__popcnt: case Builtin::BI__popcnt64: { APSInt Val; - if (!EvaluateInteger(E->getArg(0), Val, Info)) + if (E->getArg(0)->getType()->isExtVectorBoolType()) { + APValue Vec; + if (!EvaluateVector(E->getArg(0), Vec, Info)) + return false; + Val = ConvertBoolVectorToInt(Vec); + } else if (!EvaluateInteger(E->getArg(0), Val, Info)) { return false; + } return Success(Val.popcount(), E); } @@ -13875,6 +14072,25 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, APInt Result = std::min(LHS, RHS); return Success(APSInt(Result, !LHS.isSigned()), E); } + case Builtin::BI__builtin_elementwise_fshl: + case Builtin::BI__builtin_elementwise_fshr: { + APSInt Hi, Lo, Shift; + if (!EvaluateInteger(E->getArg(0), Hi, Info) || + !EvaluateInteger(E->getArg(1), Lo, Info) || + !EvaluateInteger(E->getArg(2), Shift, Info)) + return false; + + switch (BuiltinOp) { + case Builtin::BI__builtin_elementwise_fshl: { + APSInt Result(llvm::APIntOps::fshl(Hi, Lo, Shift), Hi.isUnsigned()); + return Success(Result, E); + } + case Builtin::BI__builtin_elementwise_fshr: { + APSInt Result(llvm::APIntOps::fshr(Hi, Lo, Shift), Hi.isUnsigned()); + return Success(Result, E); + } + } + } case Builtin::BIstrlen: case Builtin::BIwcslen: // A call to strlen is not a constant expression. @@ -14910,6 +15126,11 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, // Reject differing bases from the normal codepath; we special-case // comparisons to null. if (!HasSameBase(LHSValue, RHSValue)) { + // Bail out early if we're checking potential constant expression. + // Otherwise, prefer to diagnose other issues. + if (Info.checkingPotentialConstantExpression() && + (LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown)) + return false; 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()); @@ -15230,6 +15451,10 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // Reject differing bases from the normal codepath; we special-case // comparisons to null. if (!HasSameBase(LHSValue, RHSValue)) { + if (Info.checkingPotentialConstantExpression() && + (LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown)) + return false; + const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr *>(); const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr *>(); @@ -15408,6 +15633,13 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( const auto *VAT = Info.Ctx.getAsVariableArrayType(Ty); assert(VAT); if (VAT->getElementType()->isArrayType()) { + // Variable array size expression could be missing (e.g. int a[*][10]) In + // that case, it can't be a constant expression. + if (!VAT->getSizeExpr()) { + Info.FFDiag(E->getBeginLoc()); + return false; + } + std::optional<APSInt> Res = VAT->getSizeExpr()->getIntegerConstantExpr(Info.Ctx); if (Res) { @@ -15455,10 +15687,9 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { case OffsetOfNode::Field: { FieldDecl *MemberDecl = ON.getField(); - const RecordType *RT = CurrentType->getAs<RecordType>(); - if (!RT) + const auto *RD = CurrentType->getAsRecordDecl(); + if (!RD) return Error(OOE); - RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); unsigned i = MemberDecl->getFieldIndex(); @@ -15477,22 +15708,20 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { return Error(OOE); // Find the layout of the class whose base we are looking into. - const RecordType *RT = CurrentType->getAs<RecordType>(); - if (!RT) + const auto *RD = CurrentType->getAsCXXRecordDecl(); + if (!RD) return Error(OOE); - RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if (RD->isInvalidDecl()) return false; const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); // Find the base class itself. CurrentType = BaseSpec->getType(); - const RecordType *BaseRT = CurrentType->getAs<RecordType>(); - if (!BaseRT) + const auto *BaseRD = CurrentType->getAsCXXRecordDecl(); + if (!BaseRD) return Error(OOE); // Add the offset to the base. - Result += RL.getBaseClassOffset(cast<CXXRecordDecl>( - BaseRT->getOriginalDecl()->getDefinitionOrSelf())); + Result += RL.getBaseClassOffset(BaseRD); break; } } @@ -15670,8 +15899,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { } if (Info.Ctx.getLangOpts().CPlusPlus && DestType->isEnumeralType()) { - const EnumType *ET = dyn_cast<EnumType>(DestType.getCanonicalType()); - const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + const auto *ED = DestType->getAsEnumDecl(); // Check that the value is within the range of the enumeration values. // // This corressponds to [expr.static.cast]p10 which says: @@ -17945,7 +18173,10 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { // it is an ICE or not. const auto *VAT = Ctx.getAsVariableArrayType(ArgTy); if (VAT->getElementType()->isArrayType()) - return CheckICE(VAT->getSizeExpr(), Ctx); + // Variable array size expression could be missing (e.g. int a[*][10]) + // In that case, it can't be a constant expression. + return VAT->getSizeExpr() ? CheckICE(VAT->getSizeExpr(), Ctx) + : ICEDiag(IK_NotICE, E->getBeginLoc()); // Otherwise, this is a regular VLA, which is definitely not an ICE. return ICEDiag(IK_NotICE, E->getBeginLoc()); |
