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