summaryrefslogtreecommitdiff
path: root/clang/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST/ExprConstant.cpp')
-rw-r--r--clang/lib/AST/ExprConstant.cpp813
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());