[clang] [Clang][Diagnostics] Update select uses in DiagnosticXKinds.td to use enum_select (PR #130868)
Ayokunle Amodu via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 18 23:19:38 PDT 2025
https://github.com/ayokunle321 updated https://github.com/llvm/llvm-project/pull/130868
>From dfc517be06531af965dc51b09a0f1ae7965e3e20 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <121697771+ayokunle321 at users.noreply.github.com>
Date: Fri, 14 Mar 2025 15:13:05 -0600
Subject: [PATCH 1/3] revert changes in ASTKinds.td file
---
clang/include/clang/Basic/DiagnosticASTKinds.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index ac53778339a20..9faa8eec56b40 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -1041,4 +1041,4 @@ def warn_unpacked_field
def warn_unaligned_access : Warning<
"field %1 within %0 is less aligned than %2 and is usually due to %0 being "
"packed, which can lead to unaligned accesses">, InGroup<UnalignedAccess>, DefaultIgnore;
-}
+}
\ No newline at end of file
>From 9e08ddfb5931d06fa0e725ae7dea8de781489ab7 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <121697771+ayokunle321 at users.noreply.github.com>
Date: Wed, 19 Mar 2025 00:12:11 -0600
Subject: [PATCH 2/3] refactor select in note_constexpr_invalid_cast
---
clang/include/clang/Basic/DiagnosticASTKinds.td | 5 +++--
clang/lib/AST/ByteCode/Interp.h | 6 +++---
clang/lib/AST/ExprConstant.cpp | 16 ++++++++--------
3 files changed, 14 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 9faa8eec56b40..7167f95e88296 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -11,8 +11,9 @@ let Component = "AST" in {
// Constant expression diagnostics. These (and their users) belong in Sema.
def note_expr_divide_by_zero : Note<"division by zero">;
def note_constexpr_invalid_cast : Note<
- "%select{reinterpret_cast|dynamic_cast|%select{this conversion|cast that"
- " performs the conversions of a reinterpret_cast}1|cast from %1}0"
+ "%enum_select<CastKind>{%Reinterpret{reinterpret_cast}|%Dynamic{dynamic_cast}|"
+ "%ThisCastOrReinterpret{%select{this conversion|cast that performs the conversions "
+ "of a reinterpret_cast}1}|%CastFrom{cast from %1}}0"
" is not allowed in a constant expression"
"%select{| in C++ standards before C++20||}0">;
def note_constexpr_invalid_void_star_cast : Note<
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index f2ddeac99cd7e..8956a69c7124c 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2366,12 +2366,12 @@ static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
} else if (!S.getLangOpts().CPlusPlus26) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
- << 3 << "'void *'" << S.Current->getRange(OpPC);
+ << diag::CastKind::CastFrom << "'void *'" << S.Current->getRange(OpPC);
}
} else {
const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
- << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
+ << diag::CastKind::ThisCastOrReinterpret << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
}
return true;
@@ -2736,7 +2736,7 @@ inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
if (Desc)
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)
- << 2 << S.getLangOpts().CPlusPlus;
+ << diag::CastKind::ThisCastOrReinterpret << S.getLangOpts().CPlusPlus;
S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
return true;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f8e8aaddbfdbd..9eb8c6717900b 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -8103,12 +8103,12 @@ class ExprEvaluatorBase
}
bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
- CCEDiag(E, diag::note_constexpr_invalid_cast) << 0;
+ CCEDiag(E, diag::note_constexpr_invalid_cast) << diag::CastKind::Reinterpret;
return static_cast<Derived*>(this)->VisitCastExpr(E);
}
bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
if (!Info.Ctx.getLangOpts().CPlusPlus20)
- CCEDiag(E, diag::note_constexpr_invalid_cast) << 1;
+ CCEDiag(E, diag::note_constexpr_invalid_cast) << diag::CastKind::Dynamic;
return static_cast<Derived*>(this)->VisitCastExpr(E);
}
bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E) {
@@ -8833,7 +8833,7 @@ class LValueExprEvaluator
case CK_LValueBitCast:
this->CCEDiag(E, diag::note_constexpr_invalid_cast)
- << 2 << Info.Ctx.getLangOpts().CPlusPlus;
+ << diag::CastKind::ThisCastOrReinterpret << Info.Ctx.getLangOpts().CPlusPlus;
if (!Visit(E->getSubExpr()))
return false;
Result.Designator.setInvalid();
@@ -9670,10 +9670,10 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
<< E->getType()->getPointeeType();
else
CCEDiag(E, diag::note_constexpr_invalid_cast)
- << 3 << SubExpr->getType();
+ << diag::CastKind::CastFrom << SubExpr->getType();
} else
CCEDiag(E, diag::note_constexpr_invalid_cast)
- << 2 << Info.Ctx.getLangOpts().CPlusPlus;
+ << diag::CastKind::ThisCastOrReinterpret << Info.Ctx.getLangOpts().CPlusPlus;
Result.Designator.setInvalid();
}
}
@@ -9712,7 +9712,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralToPointer: {
CCEDiag(E, diag::note_constexpr_invalid_cast)
- << 2 << Info.Ctx.getLangOpts().CPlusPlus;
+ << diag::CastKind::ThisCastOrReinterpret << Info.Ctx.getLangOpts().CPlusPlus;
APValue Value;
if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
@@ -11177,7 +11177,7 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
// Give up if the input isn't an int, float, or vector. For example, we
// reject "(v4i16)(intptr_t)&a".
Info.FFDiag(E, diag::note_constexpr_invalid_cast)
- << 2 << Info.Ctx.getLangOpts().CPlusPlus;
+ << diag::CastKind::ThisCastOrReinterpret << Info.Ctx.getLangOpts().CPlusPlus;
return false;
}
@@ -15196,7 +15196,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_PointerToIntegral: {
CCEDiag(E, diag::note_constexpr_invalid_cast)
- << 2 << Info.Ctx.getLangOpts().CPlusPlus << E->getSourceRange();
+ << diag::CastKind::ThisCastOrReinterpret << Info.Ctx.getLangOpts().CPlusPlus << E->getSourceRange();
LValue LV;
if (!EvaluatePointer(SubExpr, LV, Info))
>From 73fc2376546a9ec03fc9dd16b9523aae0d326c4b Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <121697771+ayokunle321 at users.noreply.github.com>
Date: Wed, 19 Mar 2025 00:19:10 -0600
Subject: [PATCH 3/3] format style
---
clang/lib/AST/ByteCode/Interp.h | 12 +-
clang/lib/AST/ExprConstant.cpp | 4325 +++++++++++++++----------------
2 files changed, 2164 insertions(+), 2173 deletions(-)
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 8956a69c7124c..65e37a426c42e 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -2366,12 +2366,14 @@ static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {
} else if (!S.getLangOpts().CPlusPlus26) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
- << diag::CastKind::CastFrom << "'void *'" << S.Current->getRange(OpPC);
+ << diag::CastKind::CastFrom << "'void *'"
+ << S.Current->getRange(OpPC);
}
} else {
const SourceInfo &E = S.Current->getSource(OpPC);
S.CCEDiag(E, diag::note_constexpr_invalid_cast)
- << diag::CastKind::ThisCastOrReinterpret << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
+ << diag::CastKind::ThisCastOrReinterpret << S.getLangOpts().CPlusPlus
+ << S.Current->getRange(OpPC);
}
return true;
@@ -2474,9 +2476,9 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
if (!S.noteUndefinedBehavior())
return false;
RHS = -RHS;
- return DoShift<LT, RT,
- Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(
- S, OpPC, LHS, RHS);
+ return DoShift < LT, RT,
+ Dir == ShiftDir::Left ? ShiftDir::Right
+ : ShiftDir::Left > (S, OpPC, LHS, RHS);
}
if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 9eb8c6717900b..34680417de948 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -71,721 +71,704 @@
using namespace clang;
using llvm::APFixedPoint;
+using llvm::APFloat;
using llvm::APInt;
using llvm::APSInt;
-using llvm::APFloat;
using llvm::FixedPointSemantics;
namespace {
- struct LValue;
- class CallStackFrame;
- class EvalInfo;
+struct LValue;
+class CallStackFrame;
+class EvalInfo;
- using SourceLocExprScopeGuard =
- CurrentSourceLocExprScope::SourceLocExprScopeGuard;
+using SourceLocExprScopeGuard =
+ CurrentSourceLocExprScope::SourceLocExprScopeGuard;
- static QualType getType(APValue::LValueBase B) {
- return B.getType();
- }
+static QualType getType(APValue::LValueBase B) { return B.getType(); }
- /// Get an LValue path entry, which is known to not be an array index, as a
- /// field declaration.
- static const FieldDecl *getAsField(APValue::LValuePathEntry E) {
- return dyn_cast_or_null<FieldDecl>(E.getAsBaseOrMember().getPointer());
- }
- /// Get an LValue path entry, which is known to not be an array index, as a
- /// base class declaration.
- static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
- return dyn_cast_or_null<CXXRecordDecl>(E.getAsBaseOrMember().getPointer());
- }
- /// Determine whether this LValue path entry for a base class names a virtual
- /// base class.
- static bool isVirtualBaseClass(APValue::LValuePathEntry E) {
- return E.getAsBaseOrMember().getInt();
- }
+/// Get an LValue path entry, which is known to not be an array index, as a
+/// field declaration.
+static const FieldDecl *getAsField(APValue::LValuePathEntry E) {
+ return dyn_cast_or_null<FieldDecl>(E.getAsBaseOrMember().getPointer());
+}
+/// Get an LValue path entry, which is known to not be an array index, as a
+/// base class declaration.
+static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
+ return dyn_cast_or_null<CXXRecordDecl>(E.getAsBaseOrMember().getPointer());
+}
+/// Determine whether this LValue path entry for a base class names a virtual
+/// base class.
+static bool isVirtualBaseClass(APValue::LValuePathEntry E) {
+ return E.getAsBaseOrMember().getInt();
+}
- /// Given an expression, determine the type used to store the result of
- /// evaluating that expression.
- static QualType getStorageType(const ASTContext &Ctx, const Expr *E) {
- if (E->isPRValue())
- return E->getType();
- return Ctx.getLValueReferenceType(E->getType());
- }
+/// Given an expression, determine the type used to store the result of
+/// evaluating that expression.
+static QualType getStorageType(const ASTContext &Ctx, const Expr *E) {
+ if (E->isPRValue())
+ return E->getType();
+ 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;
- }
+/// 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.
- ///
- /// Returns null if we couldn't unwrap a function with alloc_size.
- static const CallExpr *tryUnwrapAllocSizeCall(const Expr *E) {
- if (!E->getType()->isPointerType())
- return nullptr;
+/// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr.
+/// This will look through a single cast.
+///
+/// Returns null if we couldn't unwrap a function with alloc_size.
+static const CallExpr *tryUnwrapAllocSizeCall(const Expr *E) {
+ if (!E->getType()->isPointerType())
+ return nullptr;
- E = E->IgnoreParens();
- // If we're doing a variable assignment from e.g. malloc(N), there will
- // probably be a cast of some kind. In exotic cases, we might also see a
- // top-level ExprWithCleanups. Ignore them either way.
- if (const auto *FE = dyn_cast<FullExpr>(E))
- E = FE->getSubExpr()->IgnoreParens();
+ E = E->IgnoreParens();
+ // If we're doing a variable assignment from e.g. malloc(N), there will
+ // probably be a cast of some kind. In exotic cases, we might also see a
+ // top-level ExprWithCleanups. Ignore them either way.
+ if (const auto *FE = dyn_cast<FullExpr>(E))
+ E = FE->getSubExpr()->IgnoreParens();
- if (const auto *Cast = dyn_cast<CastExpr>(E))
- E = Cast->getSubExpr()->IgnoreParens();
+ if (const auto *Cast = dyn_cast<CastExpr>(E))
+ E = Cast->getSubExpr()->IgnoreParens();
- if (const auto *CE = dyn_cast<CallExpr>(E))
- return getAllocSizeAttr(CE) ? CE : nullptr;
- return nullptr;
- }
+ if (const auto *CE = dyn_cast<CallExpr>(E))
+ return getAllocSizeAttr(CE) ? CE : nullptr;
+ return nullptr;
+}
- /// Determines whether or not the given Base contains a call to a function
- /// with the alloc_size attribute.
- static bool isBaseAnAllocSizeCall(APValue::LValueBase Base) {
- const auto *E = Base.dyn_cast<const Expr *>();
- return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E);
- }
+/// Determines whether or not the given Base contains a call to a function
+/// with the alloc_size attribute.
+static bool isBaseAnAllocSizeCall(APValue::LValueBase Base) {
+ const auto *E = Base.dyn_cast<const Expr *>();
+ return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E);
+}
- /// Determines whether the given kind of constant expression is only ever
- /// used for name mangling. If so, it's permitted to reference things that we
- /// can't generate code for (in particular, dllimported functions).
- static bool isForManglingOnly(ConstantExprKind Kind) {
- switch (Kind) {
- case ConstantExprKind::Normal:
- case ConstantExprKind::ClassTemplateArgument:
- case ConstantExprKind::ImmediateInvocation:
- // Note that non-type template arguments of class type are emitted as
- // template parameter objects.
- return false;
+/// Determines whether the given kind of constant expression is only ever
+/// used for name mangling. If so, it's permitted to reference things that we
+/// can't generate code for (in particular, dllimported functions).
+static bool isForManglingOnly(ConstantExprKind Kind) {
+ switch (Kind) {
+ case ConstantExprKind::Normal:
+ case ConstantExprKind::ClassTemplateArgument:
+ case ConstantExprKind::ImmediateInvocation:
+ // Note that non-type template arguments of class type are emitted as
+ // template parameter objects.
+ return false;
- case ConstantExprKind::NonClassTemplateArgument:
- return true;
- }
- llvm_unreachable("unknown ConstantExprKind");
+ case ConstantExprKind::NonClassTemplateArgument:
+ return true;
}
+ llvm_unreachable("unknown ConstantExprKind");
+}
- static bool isTemplateArgument(ConstantExprKind Kind) {
- switch (Kind) {
- case ConstantExprKind::Normal:
- case ConstantExprKind::ImmediateInvocation:
- return false;
+static bool isTemplateArgument(ConstantExprKind Kind) {
+ switch (Kind) {
+ case ConstantExprKind::Normal:
+ case ConstantExprKind::ImmediateInvocation:
+ return false;
- case ConstantExprKind::ClassTemplateArgument:
- case ConstantExprKind::NonClassTemplateArgument:
- return true;
- }
- llvm_unreachable("unknown ConstantExprKind");
- }
-
- /// The bound to claim that an array of unknown bound has.
- /// The value in MostDerivedArraySize is undefined in this case. So, set it
- /// to an arbitrary value that's likely to loudly break things if it's used.
- static const uint64_t AssumedSizeForUnsizedArray =
- std::numeric_limits<uint64_t>::max() / 2;
-
- /// Determines if an LValue with the given LValueBase will have an unsized
- /// array in its designator.
- /// Find the path length and type of the most-derived subobject in the given
- /// path, and find the size of the containing array, if any.
- static unsigned
- findMostDerivedSubobject(ASTContext &Ctx, APValue::LValueBase Base,
- ArrayRef<APValue::LValuePathEntry> Path,
- uint64_t &ArraySize, QualType &Type, bool &IsArray,
- bool &FirstEntryIsUnsizedArray) {
- // This only accepts LValueBases from APValues, and APValues don't support
- // arrays that lack size info.
- assert(!isBaseAnAllocSizeCall(Base) &&
- "Unsized arrays shouldn't appear here");
- unsigned MostDerivedLength = 0;
- Type = getType(Base);
-
- for (unsigned I = 0, N = Path.size(); I != N; ++I) {
- if (Type->isArrayType()) {
- const ArrayType *AT = Ctx.getAsArrayType(Type);
- Type = AT->getElementType();
- MostDerivedLength = I + 1;
- IsArray = true;
-
- if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
- ArraySize = CAT->getZExtSize();
- } else {
- assert(I == 0 && "unexpected unsized array designator");
- FirstEntryIsUnsizedArray = true;
- ArraySize = AssumedSizeForUnsizedArray;
- }
- } else if (Type->isAnyComplexType()) {
- const ComplexType *CT = Type->castAs<ComplexType>();
- Type = CT->getElementType();
- ArraySize = 2;
- MostDerivedLength = I + 1;
- IsArray = true;
- } else if (const auto *VT = Type->getAs<VectorType>()) {
- Type = VT->getElementType();
- ArraySize = VT->getNumElements();
- MostDerivedLength = I + 1;
- IsArray = true;
- } else if (const FieldDecl *FD = getAsField(Path[I])) {
- Type = FD->getType();
- ArraySize = 0;
- MostDerivedLength = I + 1;
- IsArray = false;
+ case ConstantExprKind::ClassTemplateArgument:
+ case ConstantExprKind::NonClassTemplateArgument:
+ return true;
+ }
+ llvm_unreachable("unknown ConstantExprKind");
+}
+
+/// The bound to claim that an array of unknown bound has.
+/// The value in MostDerivedArraySize is undefined in this case. So, set it
+/// to an arbitrary value that's likely to loudly break things if it's used.
+static const uint64_t AssumedSizeForUnsizedArray =
+ std::numeric_limits<uint64_t>::max() / 2;
+
+/// Determines if an LValue with the given LValueBase will have an unsized
+/// array in its designator.
+/// Find the path length and type of the most-derived subobject in the given
+/// path, and find the size of the containing array, if any.
+static unsigned
+findMostDerivedSubobject(ASTContext &Ctx, APValue::LValueBase Base,
+ ArrayRef<APValue::LValuePathEntry> Path,
+ uint64_t &ArraySize, QualType &Type, bool &IsArray,
+ bool &FirstEntryIsUnsizedArray) {
+ // This only accepts LValueBases from APValues, and APValues don't support
+ // arrays that lack size info.
+ assert(!isBaseAnAllocSizeCall(Base) &&
+ "Unsized arrays shouldn't appear here");
+ unsigned MostDerivedLength = 0;
+ Type = getType(Base);
+
+ for (unsigned I = 0, N = Path.size(); I != N; ++I) {
+ if (Type->isArrayType()) {
+ const ArrayType *AT = Ctx.getAsArrayType(Type);
+ Type = AT->getElementType();
+ MostDerivedLength = I + 1;
+ IsArray = true;
+
+ if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ ArraySize = CAT->getZExtSize();
} else {
- // Path[I] describes a base class.
- ArraySize = 0;
- IsArray = false;
- }
- }
- return MostDerivedLength;
- }
-
- /// A path from a glvalue to a subobject of that glvalue.
- struct SubobjectDesignator {
- /// True if the subobject was named in a manner not supported by C++11. Such
- /// lvalues can still be folded, but they are not core constant expressions
- /// and we cannot perform lvalue-to-rvalue conversions on them.
- LLVM_PREFERRED_TYPE(bool)
- unsigned Invalid : 1;
-
- /// Is this a pointer one past the end of an object?
- LLVM_PREFERRED_TYPE(bool)
- unsigned IsOnePastTheEnd : 1;
-
- /// Indicator of whether the first entry is an unsized array.
- LLVM_PREFERRED_TYPE(bool)
- unsigned FirstEntryIsAnUnsizedArray : 1;
-
- /// Indicator of whether the most-derived object is an array element.
- LLVM_PREFERRED_TYPE(bool)
- unsigned MostDerivedIsArrayElement : 1;
-
- /// The length of the path to the most-derived object of which this is a
- /// subobject.
- unsigned MostDerivedPathLength : 28;
-
- /// The size of the array of which the most-derived object is an element.
- /// This will always be 0 if the most-derived object is not an array
- /// element. 0 is not an indicator of whether or not the most-derived object
- /// is an array, however, because 0-length arrays are allowed.
- ///
- /// If the current array is an unsized array, the value of this is
- /// undefined.
- uint64_t MostDerivedArraySize;
- /// The type of the most derived object referred to by this address.
- QualType MostDerivedType;
-
- typedef APValue::LValuePathEntry PathEntry;
-
- /// The entries on the path from the glvalue to the designated subobject.
- SmallVector<PathEntry, 8> Entries;
-
- SubobjectDesignator() : Invalid(true) {}
-
- explicit SubobjectDesignator(QualType T)
- : Invalid(false), IsOnePastTheEnd(false),
- FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
- MostDerivedPathLength(0), MostDerivedArraySize(0),
- MostDerivedType(T) {}
-
- SubobjectDesignator(ASTContext &Ctx, const APValue &V)
- : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
- FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
- MostDerivedPathLength(0), MostDerivedArraySize(0) {
- assert(V.isLValue() && "Non-LValue used to make an LValue designator?");
- if (!Invalid) {
- IsOnePastTheEnd = V.isLValueOnePastTheEnd();
- ArrayRef<PathEntry> VEntries = V.getLValuePath();
- Entries.insert(Entries.end(), VEntries.begin(), VEntries.end());
- if (V.getLValueBase()) {
- bool IsArray = false;
- bool FirstIsUnsizedArray = false;
- MostDerivedPathLength = findMostDerivedSubobject(
- Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize,
- MostDerivedType, IsArray, FirstIsUnsizedArray);
- MostDerivedIsArrayElement = IsArray;
- FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
- }
+ assert(I == 0 && "unexpected unsized array designator");
+ FirstEntryIsUnsizedArray = true;
+ ArraySize = AssumedSizeForUnsizedArray;
}
+ } else if (Type->isAnyComplexType()) {
+ const ComplexType *CT = Type->castAs<ComplexType>();
+ Type = CT->getElementType();
+ ArraySize = 2;
+ MostDerivedLength = I + 1;
+ IsArray = true;
+ } else if (const auto *VT = Type->getAs<VectorType>()) {
+ Type = VT->getElementType();
+ ArraySize = VT->getNumElements();
+ MostDerivedLength = I + 1;
+ IsArray = true;
+ } else if (const FieldDecl *FD = getAsField(Path[I])) {
+ Type = FD->getType();
+ ArraySize = 0;
+ MostDerivedLength = I + 1;
+ IsArray = false;
+ } else {
+ // Path[I] describes a base class.
+ ArraySize = 0;
+ IsArray = false;
}
+ }
+ return MostDerivedLength;
+}
- void truncate(ASTContext &Ctx, APValue::LValueBase Base,
- unsigned NewLength) {
- if (Invalid)
- return;
+/// A path from a glvalue to a subobject of that glvalue.
+struct SubobjectDesignator {
+ /// True if the subobject was named in a manner not supported by C++11. Such
+ /// lvalues can still be folded, but they are not core constant expressions
+ /// and we cannot perform lvalue-to-rvalue conversions on them.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned Invalid : 1;
- assert(Base && "cannot truncate path for null pointer");
- assert(NewLength <= Entries.size() && "not a truncation");
+ /// Is this a pointer one past the end of an object?
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsOnePastTheEnd : 1;
- if (NewLength == Entries.size())
- return;
- Entries.resize(NewLength);
+ /// Indicator of whether the first entry is an unsized array.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned FirstEntryIsAnUnsizedArray : 1;
- bool IsArray = false;
- bool FirstIsUnsizedArray = false;
- MostDerivedPathLength = findMostDerivedSubobject(
- Ctx, Base, Entries, MostDerivedArraySize, MostDerivedType, IsArray,
- FirstIsUnsizedArray);
- MostDerivedIsArrayElement = IsArray;
- FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
- }
+ /// Indicator of whether the most-derived object is an array element.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned MostDerivedIsArrayElement : 1;
- void setInvalid() {
- Invalid = true;
- Entries.clear();
- }
+ /// The length of the path to the most-derived object of which this is a
+ /// subobject.
+ unsigned MostDerivedPathLength : 28;
- /// Determine whether the most derived subobject is an array without a
- /// known bound.
- bool isMostDerivedAnUnsizedArray() const {
- assert(!Invalid && "Calling this makes no sense on invalid designators");
- return Entries.size() == 1 && FirstEntryIsAnUnsizedArray;
- }
-
- /// Determine what the most derived array's size is. Results in an assertion
- /// failure if the most derived array lacks a size.
- uint64_t getMostDerivedArraySize() const {
- assert(!isMostDerivedAnUnsizedArray() && "Unsized array has no size");
- return MostDerivedArraySize;
+ /// The size of the array of which the most-derived object is an element.
+ /// This will always be 0 if the most-derived object is not an array
+ /// element. 0 is not an indicator of whether or not the most-derived object
+ /// is an array, however, because 0-length arrays are allowed.
+ ///
+ /// If the current array is an unsized array, the value of this is
+ /// undefined.
+ uint64_t MostDerivedArraySize;
+ /// The type of the most derived object referred to by this address.
+ QualType MostDerivedType;
+
+ typedef APValue::LValuePathEntry PathEntry;
+
+ /// The entries on the path from the glvalue to the designated subobject.
+ SmallVector<PathEntry, 8> Entries;
+
+ SubobjectDesignator() : Invalid(true) {}
+
+ explicit SubobjectDesignator(QualType T)
+ : Invalid(false), IsOnePastTheEnd(false),
+ FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
+ MostDerivedPathLength(0), MostDerivedArraySize(0), MostDerivedType(T) {}
+
+ SubobjectDesignator(ASTContext &Ctx, const APValue &V)
+ : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
+ FirstEntryIsAnUnsizedArray(false), MostDerivedIsArrayElement(false),
+ MostDerivedPathLength(0), MostDerivedArraySize(0) {
+ assert(V.isLValue() && "Non-LValue used to make an LValue designator?");
+ if (!Invalid) {
+ IsOnePastTheEnd = V.isLValueOnePastTheEnd();
+ ArrayRef<PathEntry> VEntries = V.getLValuePath();
+ Entries.insert(Entries.end(), VEntries.begin(), VEntries.end());
+ if (V.getLValueBase()) {
+ bool IsArray = false;
+ bool FirstIsUnsizedArray = false;
+ MostDerivedPathLength = findMostDerivedSubobject(
+ Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize,
+ MostDerivedType, IsArray, FirstIsUnsizedArray);
+ MostDerivedIsArrayElement = IsArray;
+ FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
+ }
}
+ }
- /// Determine whether this is a one-past-the-end pointer.
- bool isOnePastTheEnd() const {
- assert(!Invalid);
- if (IsOnePastTheEnd)
- return true;
- if (!isMostDerivedAnUnsizedArray() && MostDerivedIsArrayElement &&
- Entries[MostDerivedPathLength - 1].getAsArrayIndex() ==
- MostDerivedArraySize)
- return true;
- return false;
- }
+ void truncate(ASTContext &Ctx, APValue::LValueBase Base, unsigned NewLength) {
+ if (Invalid)
+ return;
- /// Get the range of valid index adjustments in the form
- /// {maximum value that can be subtracted from this pointer,
- /// maximum value that can be added to this pointer}
- std::pair<uint64_t, uint64_t> validIndexAdjustments() {
- if (Invalid || isMostDerivedAnUnsizedArray())
- return {0, 0};
+ assert(Base && "cannot truncate path for null pointer");
+ assert(NewLength <= Entries.size() && "not a truncation");
- // [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;
- return {ArrayIndex, ArraySize - ArrayIndex};
- }
+ if (NewLength == Entries.size())
+ return;
+ Entries.resize(NewLength);
- /// Check that this refers to a valid subobject.
- bool isValidSubobject() const {
- if (Invalid)
- return false;
- return !isOnePastTheEnd();
- }
- /// Check that this refers to a valid subobject, and if not, produce a
- /// relevant diagnostic and set the designator as invalid.
- bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK);
+ bool IsArray = false;
+ bool FirstIsUnsizedArray = false;
+ MostDerivedPathLength =
+ findMostDerivedSubobject(Ctx, Base, Entries, MostDerivedArraySize,
+ MostDerivedType, IsArray, FirstIsUnsizedArray);
+ MostDerivedIsArrayElement = IsArray;
+ FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
+ }
- /// Get the type of the designated object.
- QualType getType(ASTContext &Ctx) const {
- assert(!Invalid && "invalid designator has no subobject type");
- return MostDerivedPathLength == Entries.size()
- ? MostDerivedType
- : Ctx.getRecordType(getAsBaseClass(Entries.back()));
- }
+ void setInvalid() {
+ Invalid = true;
+ Entries.clear();
+ }
- /// Update this designator to refer to the first element within this array.
- void addArrayUnchecked(const ConstantArrayType *CAT) {
- Entries.push_back(PathEntry::ArrayIndex(0));
+ /// Determine whether the most derived subobject is an array without a
+ /// known bound.
+ bool isMostDerivedAnUnsizedArray() const {
+ assert(!Invalid && "Calling this makes no sense on invalid designators");
+ return Entries.size() == 1 && FirstEntryIsAnUnsizedArray;
+ }
- // This is a most-derived object.
- MostDerivedType = CAT->getElementType();
- MostDerivedIsArrayElement = true;
- MostDerivedArraySize = CAT->getZExtSize();
- MostDerivedPathLength = Entries.size();
- }
- /// Update this designator to refer to the first element within the array of
- /// elements of type T. This is an array of unknown size.
- void addUnsizedArrayUnchecked(QualType ElemTy) {
- Entries.push_back(PathEntry::ArrayIndex(0));
-
- MostDerivedType = ElemTy;
- MostDerivedIsArrayElement = true;
- // The value in MostDerivedArraySize is undefined in this case. So, set it
- // to an arbitrary value that's likely to loudly break things if it's
- // used.
- MostDerivedArraySize = AssumedSizeForUnsizedArray;
- MostDerivedPathLength = Entries.size();
- }
- /// Update this designator to refer to the given base or member of this
- /// object.
- void addDeclUnchecked(const Decl *D, bool Virtual = false) {
- Entries.push_back(APValue::BaseOrMemberType(D, Virtual));
-
- // If this isn't a base class, it's a new most-derived object.
- if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
- MostDerivedType = FD->getType();
- MostDerivedIsArrayElement = false;
- MostDerivedArraySize = 0;
- MostDerivedPathLength = Entries.size();
- }
- }
- /// Update this designator to refer to the given complex component.
- void addComplexUnchecked(QualType EltTy, bool Imag) {
- Entries.push_back(PathEntry::ArrayIndex(Imag));
+ /// Determine what the most derived array's size is. Results in an assertion
+ /// failure if the most derived array lacks a size.
+ uint64_t getMostDerivedArraySize() const {
+ assert(!isMostDerivedAnUnsizedArray() && "Unsized array has no size");
+ return MostDerivedArraySize;
+ }
- // This is technically a most-derived object, though in practice this
- // is unlikely to matter.
- MostDerivedType = EltTy;
- MostDerivedIsArrayElement = true;
- MostDerivedArraySize = 2;
- MostDerivedPathLength = Entries.size();
- }
+ /// Determine whether this is a one-past-the-end pointer.
+ bool isOnePastTheEnd() const {
+ assert(!Invalid);
+ if (IsOnePastTheEnd)
+ return true;
+ if (!isMostDerivedAnUnsizedArray() && MostDerivedIsArrayElement &&
+ Entries[MostDerivedPathLength - 1].getAsArrayIndex() ==
+ MostDerivedArraySize)
+ return true;
+ return false;
+ }
- void addVectorElementUnchecked(QualType EltTy, uint64_t Size,
- uint64_t Idx) {
- Entries.push_back(PathEntry::ArrayIndex(Idx));
- MostDerivedType = EltTy;
- MostDerivedPathLength = Entries.size();
- MostDerivedArraySize = 0;
+ /// Get the range of valid index adjustments in the form
+ /// {maximum value that can be subtracted from this pointer,
+ /// maximum value that can be added to this pointer}
+ std::pair<uint64_t, uint64_t> validIndexAdjustments() {
+ if (Invalid || isMostDerivedAnUnsizedArray())
+ return {0, 0};
+
+ // [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;
+ return {ArrayIndex, ArraySize - ArrayIndex};
+ }
+
+ /// Check that this refers to a valid subobject.
+ bool isValidSubobject() const {
+ if (Invalid)
+ return false;
+ return !isOnePastTheEnd();
+ }
+ /// Check that this refers to a valid subobject, and if not, produce a
+ /// relevant diagnostic and set the designator as invalid.
+ bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK);
+
+ /// Get the type of the designated object.
+ QualType getType(ASTContext &Ctx) const {
+ assert(!Invalid && "invalid designator has no subobject type");
+ return MostDerivedPathLength == Entries.size()
+ ? MostDerivedType
+ : Ctx.getRecordType(getAsBaseClass(Entries.back()));
+ }
+
+ /// Update this designator to refer to the first element within this array.
+ void addArrayUnchecked(const ConstantArrayType *CAT) {
+ Entries.push_back(PathEntry::ArrayIndex(0));
+
+ // This is a most-derived object.
+ MostDerivedType = CAT->getElementType();
+ MostDerivedIsArrayElement = true;
+ MostDerivedArraySize = CAT->getZExtSize();
+ MostDerivedPathLength = Entries.size();
+ }
+ /// Update this designator to refer to the first element within the array of
+ /// elements of type T. This is an array of unknown size.
+ void addUnsizedArrayUnchecked(QualType ElemTy) {
+ Entries.push_back(PathEntry::ArrayIndex(0));
+
+ MostDerivedType = ElemTy;
+ MostDerivedIsArrayElement = true;
+ // The value in MostDerivedArraySize is undefined in this case. So, set it
+ // to an arbitrary value that's likely to loudly break things if it's
+ // used.
+ MostDerivedArraySize = AssumedSizeForUnsizedArray;
+ MostDerivedPathLength = Entries.size();
+ }
+ /// Update this designator to refer to the given base or member of this
+ /// object.
+ void addDeclUnchecked(const Decl *D, bool Virtual = false) {
+ Entries.push_back(APValue::BaseOrMemberType(D, Virtual));
+
+ // If this isn't a base class, it's a new most-derived object.
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ MostDerivedType = FD->getType();
MostDerivedIsArrayElement = false;
+ MostDerivedArraySize = 0;
+ MostDerivedPathLength = Entries.size();
}
+ }
+ /// Update this designator to refer to the given complex component.
+ void addComplexUnchecked(QualType EltTy, bool Imag) {
+ Entries.push_back(PathEntry::ArrayIndex(Imag));
- void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E);
- 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;
- }
+ // This is technically a most-derived object, though in practice this
+ // is unlikely to matter.
+ MostDerivedType = EltTy;
+ MostDerivedIsArrayElement = true;
+ MostDerivedArraySize = 2;
+ MostDerivedPathLength = Entries.size();
+ }
- // [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;
- }
+ void addVectorElementUnchecked(QualType EltTy, uint64_t Size, uint64_t Idx) {
+ Entries.push_back(PathEntry::ArrayIndex(Idx));
+ MostDerivedType = EltTy;
+ MostDerivedPathLength = Entries.size();
+ MostDerivedArraySize = 0;
+ MostDerivedIsArrayElement = false;
+ }
- ArrayIndex += TruncatedN;
- assert(ArrayIndex <= ArraySize &&
- "bounds check succeeded for out-of-bounds index");
+ void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E);
+ 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;
+ }
- if (IsArray)
- Entries.back() = PathEntry::ArrayIndex(ArrayIndex);
- else
- IsOnePastTheEnd = (ArrayIndex != 0);
+ // [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;
}
- };
- /// A scope at the end of which an object can need to be destroyed.
- enum class ScopeKind {
- Block,
- FullExpression,
- Call
- };
+ ArrayIndex += TruncatedN;
+ assert(ArrayIndex <= ArraySize &&
+ "bounds check succeeded for out-of-bounds index");
- /// A reference to a particular call and its arguments.
- struct CallRef {
- CallRef() : OrigCallee(), CallIndex(0), Version() {}
- CallRef(const FunctionDecl *Callee, unsigned CallIndex, unsigned Version)
- : OrigCallee(Callee), CallIndex(CallIndex), Version(Version) {}
-
- explicit operator bool() const { return OrigCallee; }
-
- /// Get the parameter that the caller initialized, corresponding to the
- /// given parameter in the callee.
- const ParmVarDecl *getOrigParam(const ParmVarDecl *PVD) const {
- return OrigCallee ? OrigCallee->getParamDecl(PVD->getFunctionScopeIndex())
- : PVD;
- }
-
- /// The callee at the point where the arguments were evaluated. This might
- /// be different from the actual callee (a different redeclaration, or a
- /// virtual override), but this function's parameters are the ones that
- /// appear in the parameter map.
- const FunctionDecl *OrigCallee;
- /// The call index of the frame that holds the argument values.
- unsigned CallIndex;
- /// The version of the parameters corresponding to this call.
- unsigned Version;
- };
+ if (IsArray)
+ Entries.back() = PathEntry::ArrayIndex(ArrayIndex);
+ else
+ IsOnePastTheEnd = (ArrayIndex != 0);
+ }
+};
- /// A stack frame in the constexpr call stack.
- class CallStackFrame : public interp::Frame {
- public:
- EvalInfo &Info;
+/// A scope at the end of which an object can need to be destroyed.
+enum class ScopeKind { Block, FullExpression, Call };
+
+/// A reference to a particular call and its arguments.
+struct CallRef {
+ CallRef() : OrigCallee(), CallIndex(0), Version() {}
+ CallRef(const FunctionDecl *Callee, unsigned CallIndex, unsigned Version)
+ : OrigCallee(Callee), CallIndex(CallIndex), Version(Version) {}
+
+ explicit operator bool() const { return OrigCallee; }
+
+ /// Get the parameter that the caller initialized, corresponding to the
+ /// given parameter in the callee.
+ const ParmVarDecl *getOrigParam(const ParmVarDecl *PVD) const {
+ return OrigCallee ? OrigCallee->getParamDecl(PVD->getFunctionScopeIndex())
+ : PVD;
+ }
+
+ /// The callee at the point where the arguments were evaluated. This might
+ /// be different from the actual callee (a different redeclaration, or a
+ /// virtual override), but this function's parameters are the ones that
+ /// appear in the parameter map.
+ const FunctionDecl *OrigCallee;
+ /// The call index of the frame that holds the argument values.
+ unsigned CallIndex;
+ /// The version of the parameters corresponding to this call.
+ unsigned Version;
+};
- /// Parent - The caller of this stack frame.
- CallStackFrame *Caller;
+/// A stack frame in the constexpr call stack.
+class CallStackFrame : public interp::Frame {
+public:
+ EvalInfo &Info;
- /// Callee - The function which was called.
- const FunctionDecl *Callee;
+ /// Parent - The caller of this stack frame.
+ CallStackFrame *Caller;
- /// This - The binding for the this pointer in this call, if any.
- const LValue *This;
+ /// Callee - The function which was called.
+ const FunctionDecl *Callee;
- /// CallExpr - The syntactical structure of member function calls
- const Expr *CallExpr;
+ /// This - The binding for the this pointer in this call, if any.
+ const LValue *This;
- /// Information on how to find the arguments to this call. Our arguments
- /// are stored in our parent's CallStackFrame, using the ParmVarDecl* as a
- /// key and this value as the version.
- CallRef Arguments;
+ /// CallExpr - The syntactical structure of member function calls
+ const Expr *CallExpr;
- /// Source location information about the default argument or default
- /// initializer expression we're evaluating, if any.
- CurrentSourceLocExprScope CurSourceLocExprScope;
+ /// Information on how to find the arguments to this call. Our arguments
+ /// are stored in our parent's CallStackFrame, using the ParmVarDecl* as a
+ /// key and this value as the version.
+ CallRef Arguments;
- // Note that we intentionally use std::map here so that references to
- // values are stable.
- typedef std::pair<const void *, unsigned> MapKeyTy;
- typedef std::map<MapKeyTy, APValue> MapTy;
- /// Temporaries - Temporary lvalues materialized within this stack frame.
- MapTy Temporaries;
- MapTy ConstexprUnknownAPValues;
+ /// Source location information about the default argument or default
+ /// initializer expression we're evaluating, if any.
+ CurrentSourceLocExprScope CurSourceLocExprScope;
- /// CallRange - The source range of the call expression for this call.
- SourceRange CallRange;
+ // Note that we intentionally use std::map here so that references to
+ // values are stable.
+ typedef std::pair<const void *, unsigned> MapKeyTy;
+ typedef std::map<MapKeyTy, APValue> MapTy;
+ /// Temporaries - Temporary lvalues materialized within this stack frame.
+ MapTy Temporaries;
+ MapTy ConstexprUnknownAPValues;
- /// Index - The call index of this call.
- unsigned Index;
+ /// CallRange - The source range of the call expression for this call.
+ SourceRange CallRange;
- /// The stack of integers for tracking version numbers for temporaries.
- SmallVector<unsigned, 2> TempVersionStack = {1};
- unsigned CurTempVersion = TempVersionStack.back();
+ /// Index - The call index of this call.
+ unsigned Index;
- unsigned getTempVersion() const { return TempVersionStack.back(); }
+ /// The stack of integers for tracking version numbers for temporaries.
+ SmallVector<unsigned, 2> TempVersionStack = {1};
+ unsigned CurTempVersion = TempVersionStack.back();
- void pushTempVersion() {
- TempVersionStack.push_back(++CurTempVersion);
- }
+ unsigned getTempVersion() const { return TempVersionStack.back(); }
- void popTempVersion() {
- TempVersionStack.pop_back();
- }
+ void pushTempVersion() { TempVersionStack.push_back(++CurTempVersion); }
- CallRef createCall(const FunctionDecl *Callee) {
- return {Callee, Index, ++CurTempVersion};
- }
+ void popTempVersion() { TempVersionStack.pop_back(); }
- // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
- // on the overall stack usage of deeply-recursing constexpr evaluations.
- // (We should cache this map rather than recomputing it repeatedly.)
- // But let's try this and see how it goes; we can look into caching the map
- // as a later change.
+ CallRef createCall(const FunctionDecl *Callee) {
+ return {Callee, Index, ++CurTempVersion};
+ }
- /// LambdaCaptureFields - Mapping from captured variables/this to
- /// corresponding data members in the closure class.
- llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
- FieldDecl *LambdaThisCaptureField = nullptr;
+ // FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
+ // on the overall stack usage of deeply-recursing constexpr evaluations.
+ // (We should cache this map rather than recomputing it repeatedly.)
+ // But let's try this and see how it goes; we can look into caching the map
+ // as a later change.
- CallStackFrame(EvalInfo &Info, SourceRange CallRange,
- const FunctionDecl *Callee, const LValue *This,
- const Expr *CallExpr, CallRef Arguments);
- ~CallStackFrame();
+ /// LambdaCaptureFields - Mapping from captured variables/this to
+ /// corresponding data members in the closure class.
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
+ FieldDecl *LambdaThisCaptureField = nullptr;
- // Return the temporary for Key whose version number is Version.
- APValue *getTemporary(const void *Key, unsigned Version) {
- MapKeyTy KV(Key, Version);
- auto LB = Temporaries.lower_bound(KV);
- if (LB != Temporaries.end() && LB->first == KV)
- return &LB->second;
- return nullptr;
- }
+ CallStackFrame(EvalInfo &Info, SourceRange CallRange,
+ const FunctionDecl *Callee, const LValue *This,
+ const Expr *CallExpr, CallRef Arguments);
+ ~CallStackFrame();
- // Return the current temporary for Key in the map.
- APValue *getCurrentTemporary(const void *Key) {
- auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
- if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
- return &std::prev(UB)->second;
- return nullptr;
- }
+ // Return the temporary for Key whose version number is Version.
+ APValue *getTemporary(const void *Key, unsigned Version) {
+ MapKeyTy KV(Key, Version);
+ auto LB = Temporaries.lower_bound(KV);
+ if (LB != Temporaries.end() && LB->first == KV)
+ return &LB->second;
+ return nullptr;
+ }
- // Return the version number of the current temporary for Key.
- unsigned getCurrentTemporaryVersion(const void *Key) const {
- auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
- if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
- return std::prev(UB)->first.second;
- return 0;
- }
+ // Return the current temporary for Key in the map.
+ APValue *getCurrentTemporary(const void *Key) {
+ auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
+ if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
+ return &std::prev(UB)->second;
+ return nullptr;
+ }
- /// Allocate storage for an object of type T in this stack frame.
- /// Populates LV with a handle to the created object. Key identifies
- /// the temporary within the stack frame, and must not be reused without
- /// bumping the temporary version number.
- template<typename KeyT>
- APValue &createTemporary(const KeyT *Key, QualType T,
- ScopeKind Scope, LValue &LV);
+ // Return the version number of the current temporary for Key.
+ unsigned getCurrentTemporaryVersion(const void *Key) const {
+ auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
+ if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
+ return std::prev(UB)->first.second;
+ return 0;
+ }
- APValue &createConstexprUnknownAPValues(const VarDecl *Key,
- APValue::LValueBase Base);
+ /// Allocate storage for an object of type T in this stack frame.
+ /// Populates LV with a handle to the created object. Key identifies
+ /// the temporary within the stack frame, and must not be reused without
+ /// bumping the temporary version number.
+ template <typename KeyT>
+ APValue &createTemporary(const KeyT *Key, QualType T, ScopeKind Scope,
+ LValue &LV);
- /// Allocate storage for a parameter of a function call made in this frame.
- APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV);
+ APValue &createConstexprUnknownAPValues(const VarDecl *Key,
+ APValue::LValueBase Base);
- void describe(llvm::raw_ostream &OS) const override;
+ /// Allocate storage for a parameter of a function call made in this frame.
+ APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV);
- Frame *getCaller() const override { return Caller; }
- SourceRange getCallRange() const override { return CallRange; }
- const FunctionDecl *getCallee() const override { return Callee; }
+ void describe(llvm::raw_ostream &OS) const override;
- bool isStdFunction() const {
- for (const DeclContext *DC = Callee; DC; DC = DC->getParent())
- if (DC->isStdNamespace())
- return true;
- return false;
- }
+ Frame *getCaller() const override { return Caller; }
+ SourceRange getCallRange() const override { return CallRange; }
+ const FunctionDecl *getCallee() const override { return Callee; }
- /// Whether we're in a context where [[msvc::constexpr]] evaluation is
- /// permitted. See MSConstexprDocs for description of permitted contexts.
- bool CanEvalMSConstexpr = false;
+ bool isStdFunction() const {
+ for (const DeclContext *DC = Callee; DC; DC = DC->getParent())
+ if (DC->isStdNamespace())
+ return true;
+ return false;
+ }
- private:
- APValue &createLocal(APValue::LValueBase Base, const void *Key, QualType T,
- ScopeKind Scope);
- };
+ /// Whether we're in a context where [[msvc::constexpr]] evaluation is
+ /// permitted. See MSConstexprDocs for description of permitted contexts.
+ bool CanEvalMSConstexpr = false;
- /// Temporarily override 'this'.
- class ThisOverrideRAII {
- public:
- ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable)
- : Frame(Frame), OldThis(Frame.This) {
- if (Enable)
- Frame.This = NewThis;
- }
- ~ThisOverrideRAII() {
- Frame.This = OldThis;
- }
- private:
- CallStackFrame &Frame;
- const LValue *OldThis;
- };
+private:
+ APValue &createLocal(APValue::LValueBase Base, const void *Key, QualType T,
+ ScopeKind Scope);
+};
- // A shorthand time trace scope struct, prints source range, for example
- // {"name":"EvaluateAsRValue","args":{"detail":"<test.cc:8:21, col:25>"}}}
- class ExprTimeTraceScope {
- public:
- ExprTimeTraceScope(const Expr *E, const ASTContext &Ctx, StringRef Name)
- : TimeScope(Name, [E, &Ctx] {
- return E->getSourceRange().printToString(Ctx.getSourceManager());
- }) {}
+/// Temporarily override 'this'.
+class ThisOverrideRAII {
+public:
+ ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable)
+ : Frame(Frame), OldThis(Frame.This) {
+ if (Enable)
+ Frame.This = NewThis;
+ }
+ ~ThisOverrideRAII() { Frame.This = OldThis; }
- private:
- llvm::TimeTraceScope TimeScope;
- };
+private:
+ CallStackFrame &Frame;
+ const LValue *OldThis;
+};
- /// RAII object used to change the current ability of
- /// [[msvc::constexpr]] evaulation.
- struct MSConstexprContextRAII {
- CallStackFrame &Frame;
- bool OldValue;
- explicit MSConstexprContextRAII(CallStackFrame &Frame, bool Value)
- : Frame(Frame), OldValue(Frame.CanEvalMSConstexpr) {
- Frame.CanEvalMSConstexpr = Value;
- }
+// A shorthand time trace scope struct, prints source range, for example
+// {"name":"EvaluateAsRValue","args":{"detail":"<test.cc:8:21, col:25>"}}}
+class ExprTimeTraceScope {
+public:
+ ExprTimeTraceScope(const Expr *E, const ASTContext &Ctx, StringRef Name)
+ : TimeScope(Name, [E, &Ctx] {
+ return E->getSourceRange().printToString(Ctx.getSourceManager());
+ }) {}
- ~MSConstexprContextRAII() { Frame.CanEvalMSConstexpr = OldValue; }
- };
-}
+private:
+ llvm::TimeTraceScope TimeScope;
+};
+
+/// RAII object used to change the current ability of
+/// [[msvc::constexpr]] evaulation.
+struct MSConstexprContextRAII {
+ CallStackFrame &Frame;
+ bool OldValue;
+ explicit MSConstexprContextRAII(CallStackFrame &Frame, bool Value)
+ : Frame(Frame), OldValue(Frame.CanEvalMSConstexpr) {
+ Frame.CanEvalMSConstexpr = Value;
+ }
-static bool HandleDestruction(EvalInfo &Info, const Expr *E,
- const LValue &This, QualType ThisType);
+ ~MSConstexprContextRAII() { Frame.CanEvalMSConstexpr = OldValue; }
+};
+} // namespace
+
+static bool HandleDestruction(EvalInfo &Info, const Expr *E, const LValue &This,
+ QualType ThisType);
static bool HandleDestruction(EvalInfo &Info, SourceLocation Loc,
APValue::LValueBase LVBase, APValue &Value,
QualType T);
namespace {
- /// A cleanup, and a flag indicating whether it is lifetime-extended.
- class Cleanup {
- llvm::PointerIntPair<APValue*, 2, ScopeKind> Value;
- APValue::LValueBase Base;
- QualType T;
+/// A cleanup, and a flag indicating whether it is lifetime-extended.
+class Cleanup {
+ llvm::PointerIntPair<APValue *, 2, ScopeKind> Value;
+ APValue::LValueBase Base;
+ QualType T;
- public:
- Cleanup(APValue *Val, APValue::LValueBase Base, QualType T,
- ScopeKind Scope)
- : Value(Val, Scope), Base(Base), T(T) {}
-
- /// Determine whether this cleanup should be performed at the end of the
- /// given kind of scope.
- bool isDestroyedAtEndOf(ScopeKind K) const {
- return (int)Value.getInt() >= (int)K;
- }
- bool endLifetime(EvalInfo &Info, bool RunDestructors) {
- if (RunDestructors) {
- SourceLocation Loc;
- if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
- Loc = VD->getLocation();
- else if (const Expr *E = Base.dyn_cast<const Expr*>())
- Loc = E->getExprLoc();
- return HandleDestruction(Info, Loc, Base, *Value.getPointer(), T);
- }
- *Value.getPointer() = APValue();
- return true;
- }
+public:
+ Cleanup(APValue *Val, APValue::LValueBase Base, QualType T, ScopeKind Scope)
+ : Value(Val, Scope), Base(Base), T(T) {}
+
+ /// Determine whether this cleanup should be performed at the end of the
+ /// given kind of scope.
+ bool isDestroyedAtEndOf(ScopeKind K) const {
+ return (int)Value.getInt() >= (int)K;
+ }
+ bool endLifetime(EvalInfo &Info, bool RunDestructors) {
+ if (RunDestructors) {
+ SourceLocation Loc;
+ if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl *>())
+ Loc = VD->getLocation();
+ else if (const Expr *E = Base.dyn_cast<const Expr *>())
+ Loc = E->getExprLoc();
+ return HandleDestruction(Info, Loc, Base, *Value.getPointer(), T);
+ }
+ *Value.getPointer() = APValue();
+ return true;
+ }
- bool hasSideEffect() {
- return T.isDestructedType();
- }
- };
+ bool hasSideEffect() { return T.isDestructedType(); }
+};
- /// A reference to an object whose construction we are currently evaluating.
- struct ObjectUnderConstruction {
- APValue::LValueBase Base;
- ArrayRef<APValue::LValuePathEntry> Path;
- friend bool operator==(const ObjectUnderConstruction &LHS,
- const ObjectUnderConstruction &RHS) {
- return LHS.Base == RHS.Base && LHS.Path == RHS.Path;
- }
- friend llvm::hash_code hash_value(const ObjectUnderConstruction &Obj) {
- return llvm::hash_combine(Obj.Base, Obj.Path);
- }
- };
- enum class ConstructionPhase {
- None,
- Bases,
- AfterBases,
- AfterFields,
- Destroying,
- DestroyingBases
- };
-}
+/// A reference to an object whose construction we are currently evaluating.
+struct ObjectUnderConstruction {
+ APValue::LValueBase Base;
+ ArrayRef<APValue::LValuePathEntry> Path;
+ friend bool operator==(const ObjectUnderConstruction &LHS,
+ const ObjectUnderConstruction &RHS) {
+ return LHS.Base == RHS.Base && LHS.Path == RHS.Path;
+ }
+ friend llvm::hash_code hash_value(const ObjectUnderConstruction &Obj) {
+ return llvm::hash_combine(Obj.Base, Obj.Path);
+ }
+};
+enum class ConstructionPhase {
+ None,
+ Bases,
+ AfterBases,
+ AfterFields,
+ Destroying,
+ DestroyingBases
+};
+} // namespace
namespace llvm {
-template<> struct DenseMapInfo<ObjectUnderConstruction> {
+template <> struct DenseMapInfo<ObjectUnderConstruction> {
using Base = DenseMapInfo<APValue::LValueBase>;
static ObjectUnderConstruction getEmptyKey() {
- return {Base::getEmptyKey(), {}}; }
+ return {Base::getEmptyKey(), {}};
+ }
static ObjectUnderConstruction getTombstoneKey() {
return {Base::getTombstoneKey(), {}};
}
@@ -797,690 +780,680 @@ template<> struct DenseMapInfo<ObjectUnderConstruction> {
return LHS == RHS;
}
};
-}
+} // namespace llvm
namespace {
- /// A dynamically-allocated heap object.
- struct DynAlloc {
- /// The value of this heap-allocated object.
- APValue Value;
- /// The allocating expression; used for diagnostics. Either a CXXNewExpr
- /// or a CallExpr (the latter is for direct calls to operator new inside
- /// std::allocator<T>::allocate).
- const Expr *AllocExpr = nullptr;
-
- enum Kind {
- New,
- ArrayNew,
- StdAllocator
- };
+/// A dynamically-allocated heap object.
+struct DynAlloc {
+ /// The value of this heap-allocated object.
+ APValue Value;
+ /// The allocating expression; used for diagnostics. Either a CXXNewExpr
+ /// or a CallExpr (the latter is for direct calls to operator new inside
+ /// std::allocator<T>::allocate).
+ const Expr *AllocExpr = nullptr;
+
+ enum Kind { New, ArrayNew, StdAllocator };
+
+ /// Get the kind of the allocation. This must match between allocation
+ /// and deallocation.
+ Kind getKind() const {
+ if (auto *NE = dyn_cast<CXXNewExpr>(AllocExpr))
+ return NE->isArray() ? ArrayNew : New;
+ assert(isa<CallExpr>(AllocExpr));
+ return StdAllocator;
+ }
+};
- /// Get the kind of the allocation. This must match between allocation
- /// and deallocation.
- Kind getKind() const {
- if (auto *NE = dyn_cast<CXXNewExpr>(AllocExpr))
- return NE->isArray() ? ArrayNew : New;
- assert(isa<CallExpr>(AllocExpr));
- return StdAllocator;
- }
- };
+struct DynAllocOrder {
+ bool operator()(DynamicAllocLValue L, DynamicAllocLValue R) const {
+ return L.getIndex() < R.getIndex();
+ }
+};
- struct DynAllocOrder {
- bool operator()(DynamicAllocLValue L, DynamicAllocLValue R) const {
- return L.getIndex() < R.getIndex();
- }
- };
+/// EvalInfo - This is a private struct used by the evaluator to capture
+/// information about a subexpression as it is folded. It retains information
+/// about the AST context, but also maintains information about the folded
+/// expression.
+///
+/// If an expression could be evaluated, it is still possible it is not a C
+/// "integer constant expression" or constant expression. If not, this struct
+/// captures information about how and why not.
+///
+/// One bit of information passed *into* the request for constant folding
+/// indicates whether the subexpression is "evaluated" or not according to C
+/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
+/// evaluate the expression regardless of what the RHS is, but C only allows
+/// certain things in certain situations.
+class EvalInfo : public interp::State {
+public:
+ ASTContext &Ctx;
- /// EvalInfo - This is a private struct used by the evaluator to capture
- /// information about a subexpression as it is folded. It retains information
- /// about the AST context, but also maintains information about the folded
- /// expression.
- ///
- /// If an expression could be evaluated, it is still possible it is not a C
- /// "integer constant expression" or constant expression. If not, this struct
- /// captures information about how and why not.
- ///
- /// One bit of information passed *into* the request for constant folding
- /// indicates whether the subexpression is "evaluated" or not according to C
- /// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
- /// evaluate the expression regardless of what the RHS is, but C only allows
- /// certain things in certain situations.
- class EvalInfo : public interp::State {
- public:
- ASTContext &Ctx;
+ /// EvalStatus - Contains information about the evaluation.
+ Expr::EvalStatus &EvalStatus;
- /// EvalStatus - Contains information about the evaluation.
- Expr::EvalStatus &EvalStatus;
+ /// CurrentCall - The top of the constexpr call stack.
+ CallStackFrame *CurrentCall;
- /// CurrentCall - The top of the constexpr call stack.
- CallStackFrame *CurrentCall;
+ /// CallStackDepth - The number of calls in the call stack right now.
+ unsigned CallStackDepth;
- /// CallStackDepth - The number of calls in the call stack right now.
- unsigned CallStackDepth;
+ /// NextCallIndex - The next call index to assign.
+ unsigned NextCallIndex;
- /// NextCallIndex - The next call index to assign.
- unsigned NextCallIndex;
+ /// StepsLeft - The remaining number of evaluation steps we're permitted
+ /// to perform. This is essentially a limit for the number of statements
+ /// we will evaluate.
+ unsigned StepsLeft;
- /// StepsLeft - The remaining number of evaluation steps we're permitted
- /// to perform. This is essentially a limit for the number of statements
- /// we will evaluate.
- unsigned StepsLeft;
+ /// Enable the experimental new constant interpreter. If an expression is
+ /// not supported by the interpreter, an error is triggered.
+ bool EnableNewConstInterp;
- /// Enable the experimental new constant interpreter. If an expression is
- /// not supported by the interpreter, an error is triggered.
- bool EnableNewConstInterp;
+ /// BottomFrame - The frame in which evaluation started. This must be
+ /// initialized after CurrentCall and CallStackDepth.
+ CallStackFrame BottomFrame;
- /// BottomFrame - The frame in which evaluation started. This must be
- /// initialized after CurrentCall and CallStackDepth.
- CallStackFrame BottomFrame;
+ /// A stack of values whose lifetimes end at the end of some surrounding
+ /// evaluation frame.
+ llvm::SmallVector<Cleanup, 16> CleanupStack;
- /// A stack of values whose lifetimes end at the end of some surrounding
- /// evaluation frame.
- llvm::SmallVector<Cleanup, 16> CleanupStack;
+ /// EvaluatingDecl - This is the declaration whose initializer is being
+ /// evaluated, if any.
+ APValue::LValueBase EvaluatingDecl;
- /// EvaluatingDecl - This is the declaration whose initializer is being
- /// evaluated, if any.
- APValue::LValueBase EvaluatingDecl;
+ enum class EvaluatingDeclKind {
+ None,
+ /// We're evaluating the construction of EvaluatingDecl.
+ Ctor,
+ /// We're evaluating the destruction of EvaluatingDecl.
+ Dtor,
+ };
+ EvaluatingDeclKind IsEvaluatingDecl = EvaluatingDeclKind::None;
+
+ /// EvaluatingDeclValue - This is the value being constructed for the
+ /// declaration whose initializer is being evaluated, if any.
+ APValue *EvaluatingDeclValue;
+
+ /// Set of objects that are currently being constructed.
+ llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase>
+ ObjectsUnderConstruction;
+
+ /// Current heap allocations, along with the location where each was
+ /// allocated. We use std::map here because we need stable addresses
+ /// for the stored APValues.
+ std::map<DynamicAllocLValue, DynAlloc, DynAllocOrder> HeapAllocs;
+
+ /// The number of heap allocations performed so far in this evaluation.
+ unsigned NumHeapAllocs = 0;
+
+ struct EvaluatingConstructorRAII {
+ EvalInfo &EI;
+ ObjectUnderConstruction Object;
+ bool DidInsert;
+ EvaluatingConstructorRAII(EvalInfo &EI, ObjectUnderConstruction Object,
+ bool HasBases)
+ : EI(EI), Object(Object) {
+ DidInsert =
+ EI.ObjectsUnderConstruction
+ .insert({Object, HasBases ? ConstructionPhase::Bases
+ : ConstructionPhase::AfterBases})
+ .second;
+ }
+ void finishedConstructingBases() {
+ EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterBases;
+ }
+ void finishedConstructingFields() {
+ EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterFields;
+ }
+ ~EvaluatingConstructorRAII() {
+ if (DidInsert)
+ EI.ObjectsUnderConstruction.erase(Object);
+ }
+ };
- enum class EvaluatingDeclKind {
- None,
- /// We're evaluating the construction of EvaluatingDecl.
- Ctor,
- /// We're evaluating the destruction of EvaluatingDecl.
- Dtor,
- };
- EvaluatingDeclKind IsEvaluatingDecl = EvaluatingDeclKind::None;
-
- /// EvaluatingDeclValue - This is the value being constructed for the
- /// declaration whose initializer is being evaluated, if any.
- APValue *EvaluatingDeclValue;
-
- /// Set of objects that are currently being constructed.
- llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase>
- ObjectsUnderConstruction;
-
- /// Current heap allocations, along with the location where each was
- /// allocated. We use std::map here because we need stable addresses
- /// for the stored APValues.
- std::map<DynamicAllocLValue, DynAlloc, DynAllocOrder> HeapAllocs;
-
- /// The number of heap allocations performed so far in this evaluation.
- unsigned NumHeapAllocs = 0;
-
- struct EvaluatingConstructorRAII {
- EvalInfo &EI;
- ObjectUnderConstruction Object;
- bool DidInsert;
- EvaluatingConstructorRAII(EvalInfo &EI, ObjectUnderConstruction Object,
- bool HasBases)
- : EI(EI), Object(Object) {
- DidInsert =
- EI.ObjectsUnderConstruction
- .insert({Object, HasBases ? ConstructionPhase::Bases
- : ConstructionPhase::AfterBases})
- .second;
- }
- void finishedConstructingBases() {
- EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterBases;
- }
- void finishedConstructingFields() {
- EI.ObjectsUnderConstruction[Object] = ConstructionPhase::AfterFields;
- }
- ~EvaluatingConstructorRAII() {
- if (DidInsert) EI.ObjectsUnderConstruction.erase(Object);
- }
- };
+ struct EvaluatingDestructorRAII {
+ EvalInfo &EI;
+ ObjectUnderConstruction Object;
+ bool DidInsert;
+ EvaluatingDestructorRAII(EvalInfo &EI, ObjectUnderConstruction Object)
+ : EI(EI), Object(Object) {
+ DidInsert = EI.ObjectsUnderConstruction
+ .insert({Object, ConstructionPhase::Destroying})
+ .second;
+ }
+ void startedDestroyingBases() {
+ EI.ObjectsUnderConstruction[Object] = ConstructionPhase::DestroyingBases;
+ }
+ ~EvaluatingDestructorRAII() {
+ if (DidInsert)
+ EI.ObjectsUnderConstruction.erase(Object);
+ }
+ };
- struct EvaluatingDestructorRAII {
- EvalInfo &EI;
- ObjectUnderConstruction Object;
- bool DidInsert;
- EvaluatingDestructorRAII(EvalInfo &EI, ObjectUnderConstruction Object)
- : EI(EI), Object(Object) {
- DidInsert = EI.ObjectsUnderConstruction
- .insert({Object, ConstructionPhase::Destroying})
- .second;
- }
- void startedDestroyingBases() {
- EI.ObjectsUnderConstruction[Object] =
- ConstructionPhase::DestroyingBases;
- }
- ~EvaluatingDestructorRAII() {
- if (DidInsert)
- EI.ObjectsUnderConstruction.erase(Object);
- }
- };
+ ConstructionPhase
+ isEvaluatingCtorDtor(APValue::LValueBase Base,
+ ArrayRef<APValue::LValuePathEntry> Path) {
+ return ObjectsUnderConstruction.lookup({Base, Path});
+ }
- ConstructionPhase
- isEvaluatingCtorDtor(APValue::LValueBase Base,
- ArrayRef<APValue::LValuePathEntry> Path) {
- return ObjectsUnderConstruction.lookup({Base, Path});
- }
-
- /// If we're currently speculatively evaluating, the outermost call stack
- /// depth at which we can mutate state, otherwise 0.
- unsigned SpeculativeEvaluationDepth = 0;
-
- /// The current array initialization index, if we're performing array
- /// initialization.
- uint64_t ArrayInitIndex = -1;
-
- /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
- /// notes attached to it will also be stored, otherwise they will not be.
- bool HasActiveDiagnostic;
-
- /// Have we emitted a diagnostic explaining why we couldn't constant
- /// 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.
- EM_ConstantExpression,
-
- /// Evaluate as a constant expression. Stop if we find that the expression
- /// is not a constant expression. Some expressions can be retried in the
- /// optimizer if we don't constant fold them here, but in an unevaluated
- /// context we try to fold them immediately since the optimizer never
- /// gets a chance to look at it.
- EM_ConstantExpressionUnevaluated,
-
- /// Fold the expression to a constant. Stop if we hit a side-effect that
- /// we can't model.
- EM_ConstantFold,
-
- /// Evaluate in any way we know how. Don't worry about side-effects that
- /// can't be modeled.
- 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),
- StepsLeft(C.getLangOpts().ConstexprStepLimit),
- EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
- BottomFrame(*this, SourceLocation(), /*Callee=*/nullptr,
- /*This=*/nullptr,
- /*CallExpr=*/nullptr, CallRef()),
- EvaluatingDecl((const ValueDecl *)nullptr),
- EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
-
- ~EvalInfo() {
- discardCleanups();
- }
-
- ASTContext &getASTContext() const override { return Ctx; }
-
- void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
- EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
- EvaluatingDecl = Base;
- IsEvaluatingDecl = EDK;
- EvaluatingDeclValue = &Value;
- }
-
- bool CheckCallLimit(SourceLocation Loc) {
- // Don't perform any constexpr calls (other than the call we're checking)
- // when checking a potential constant expression.
- if (checkingPotentialConstantExpression() && CallStackDepth > 1)
- return false;
- if (NextCallIndex == 0) {
- // NextCallIndex has wrapped around.
- FFDiag(Loc, diag::note_constexpr_call_limit_exceeded);
- return false;
- }
- if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
- return true;
- FFDiag(Loc, diag::note_constexpr_depth_limit_exceeded)
- << getLangOpts().ConstexprCallDepth;
- return false;
- }
+ /// If we're currently speculatively evaluating, the outermost call stack
+ /// depth at which we can mutate state, otherwise 0.
+ unsigned SpeculativeEvaluationDepth = 0;
- bool CheckArraySize(SourceLocation Loc, unsigned BitWidth,
- uint64_t ElemCount, bool Diag) {
- // FIXME: GH63562
- // APValue stores array extents as unsigned,
- // so anything that is greater that unsigned would overflow when
- // constructing the array, we catch this here.
- if (BitWidth > ConstantArrayType::getMaxSizeBits(Ctx) ||
- ElemCount > uint64_t(std::numeric_limits<unsigned>::max())) {
- if (Diag)
- FFDiag(Loc, diag::note_constexpr_new_too_large) << ElemCount;
- return false;
- }
+ /// The current array initialization index, if we're performing array
+ /// initialization.
+ uint64_t ArrayInitIndex = -1;
- // FIXME: GH63562
- // Arrays allocate an APValue per element.
- // We use the number of constexpr steps as a proxy for the maximum size
- // of arrays to avoid exhausting the system resources, as initialization
- // of each element is likely to take some number of steps anyway.
- uint64_t Limit = Ctx.getLangOpts().ConstexprStepLimit;
- if (ElemCount > Limit) {
- if (Diag)
- FFDiag(Loc, diag::note_constexpr_new_exceeds_limits)
- << ElemCount << Limit;
- return false;
- }
- return true;
- }
+ /// HasActiveDiagnostic - Was the previous diagnostic stored? If so, further
+ /// notes attached to it will also be stored, otherwise they will not be.
+ bool HasActiveDiagnostic;
- std::pair<CallStackFrame *, unsigned>
- getCallFrameAndDepth(unsigned CallIndex) {
- assert(CallIndex && "no call index in getCallFrameAndDepth");
- // We will eventually hit BottomFrame, which has Index 1, so Frame can't
- // be null in this loop.
- unsigned Depth = CallStackDepth;
- CallStackFrame *Frame = CurrentCall;
- while (Frame->Index > CallIndex) {
- Frame = Frame->Caller;
- --Depth;
- }
- if (Frame->Index == CallIndex)
- return {Frame, Depth};
- return {nullptr, 0};
- }
+ /// Have we emitted a diagnostic explaining why we couldn't constant
+ /// fold (not just why it's not strictly a constant expression)?
+ bool HasFoldFailureDiagnostic;
- bool nextStep(const Stmt *S) {
- if (!StepsLeft) {
- FFDiag(S->getBeginLoc(), diag::note_constexpr_step_limit_exceeded);
- return false;
- }
- --StepsLeft;
+ /// 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.
+ EM_ConstantExpression,
+
+ /// Evaluate as a constant expression. Stop if we find that the expression
+ /// is not a constant expression. Some expressions can be retried in the
+ /// optimizer if we don't constant fold them here, but in an unevaluated
+ /// context we try to fold them immediately since the optimizer never
+ /// gets a chance to look at it.
+ EM_ConstantExpressionUnevaluated,
+
+ /// Fold the expression to a constant. Stop if we hit a side-effect that
+ /// we can't model.
+ EM_ConstantFold,
+
+ /// Evaluate in any way we know how. Don't worry about side-effects that
+ /// can't be modeled.
+ 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),
+ StepsLeft(C.getLangOpts().ConstexprStepLimit),
+ EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp),
+ BottomFrame(*this, SourceLocation(), /*Callee=*/nullptr,
+ /*This=*/nullptr,
+ /*CallExpr=*/nullptr, CallRef()),
+ EvaluatingDecl((const ValueDecl *)nullptr),
+ EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
+ HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
+
+ ~EvalInfo() { discardCleanups(); }
+
+ ASTContext &getASTContext() const override { return Ctx; }
+
+ void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value,
+ EvaluatingDeclKind EDK = EvaluatingDeclKind::Ctor) {
+ EvaluatingDecl = Base;
+ IsEvaluatingDecl = EDK;
+ EvaluatingDeclValue = &Value;
+ }
+
+ bool CheckCallLimit(SourceLocation Loc) {
+ // Don't perform any constexpr calls (other than the call we're checking)
+ // when checking a potential constant expression.
+ if (checkingPotentialConstantExpression() && CallStackDepth > 1)
+ return false;
+ if (NextCallIndex == 0) {
+ // NextCallIndex has wrapped around.
+ FFDiag(Loc, diag::note_constexpr_call_limit_exceeded);
+ return false;
+ }
+ if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
return true;
+ FFDiag(Loc, diag::note_constexpr_depth_limit_exceeded)
+ << getLangOpts().ConstexprCallDepth;
+ return false;
+ }
+
+ bool CheckArraySize(SourceLocation Loc, unsigned BitWidth, uint64_t ElemCount,
+ bool Diag) {
+ // FIXME: GH63562
+ // APValue stores array extents as unsigned,
+ // so anything that is greater that unsigned would overflow when
+ // constructing the array, we catch this here.
+ if (BitWidth > ConstantArrayType::getMaxSizeBits(Ctx) ||
+ ElemCount > uint64_t(std::numeric_limits<unsigned>::max())) {
+ if (Diag)
+ FFDiag(Loc, diag::note_constexpr_new_too_large) << ElemCount;
+ return false;
}
- APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
+ // FIXME: GH63562
+ // Arrays allocate an APValue per element.
+ // We use the number of constexpr steps as a proxy for the maximum size
+ // of arrays to avoid exhausting the system resources, as initialization
+ // of each element is likely to take some number of steps anyway.
+ uint64_t Limit = Ctx.getLangOpts().ConstexprStepLimit;
+ if (ElemCount > Limit) {
+ if (Diag)
+ FFDiag(Loc, diag::note_constexpr_new_exceeds_limits)
+ << ElemCount << Limit;
+ return false;
+ }
+ return true;
+ }
- std::optional<DynAlloc *> lookupDynamicAlloc(DynamicAllocLValue DA) {
- std::optional<DynAlloc *> Result;
- auto It = HeapAllocs.find(DA);
- if (It != HeapAllocs.end())
- Result = &It->second;
- return Result;
+ std::pair<CallStackFrame *, unsigned>
+ getCallFrameAndDepth(unsigned CallIndex) {
+ assert(CallIndex && "no call index in getCallFrameAndDepth");
+ // We will eventually hit BottomFrame, which has Index 1, so Frame can't
+ // be null in this loop.
+ unsigned Depth = CallStackDepth;
+ CallStackFrame *Frame = CurrentCall;
+ while (Frame->Index > CallIndex) {
+ Frame = Frame->Caller;
+ --Depth;
}
+ if (Frame->Index == CallIndex)
+ return {Frame, Depth};
+ return {nullptr, 0};
+ }
- /// Get the allocated storage for the given parameter of the given call.
- APValue *getParamSlot(CallRef Call, const ParmVarDecl *PVD) {
- CallStackFrame *Frame = getCallFrameAndDepth(Call.CallIndex).first;
- return Frame ? Frame->getTemporary(Call.getOrigParam(PVD), Call.Version)
- : nullptr;
+ bool nextStep(const Stmt *S) {
+ if (!StepsLeft) {
+ FFDiag(S->getBeginLoc(), diag::note_constexpr_step_limit_exceeded);
+ return false;
}
+ --StepsLeft;
+ return true;
+ }
- /// Information about a stack frame for std::allocator<T>::[de]allocate.
- struct StdAllocatorCaller {
- unsigned FrameIndex;
- QualType ElemType;
- const Expr *Call;
- explicit operator bool() const { return FrameIndex != 0; };
- };
+ APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
- StdAllocatorCaller getStdAllocatorCaller(StringRef FnName) const {
- for (const CallStackFrame *Call = CurrentCall; Call != &BottomFrame;
- Call = Call->Caller) {
- const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Call->Callee);
- if (!MD)
- continue;
- const IdentifierInfo *FnII = MD->getIdentifier();
- if (!FnII || !FnII->isStr(FnName))
- continue;
+ std::optional<DynAlloc *> lookupDynamicAlloc(DynamicAllocLValue DA) {
+ std::optional<DynAlloc *> Result;
+ auto It = HeapAllocs.find(DA);
+ if (It != HeapAllocs.end())
+ Result = &It->second;
+ return Result;
+ }
- const auto *CTSD =
- dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
- if (!CTSD)
- continue;
+ /// Get the allocated storage for the given parameter of the given call.
+ APValue *getParamSlot(CallRef Call, const ParmVarDecl *PVD) {
+ CallStackFrame *Frame = getCallFrameAndDepth(Call.CallIndex).first;
+ return Frame ? Frame->getTemporary(Call.getOrigParam(PVD), Call.Version)
+ : nullptr;
+ }
- const IdentifierInfo *ClassII = CTSD->getIdentifier();
- const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
- if (CTSD->isInStdNamespace() && ClassII &&
- ClassII->isStr("allocator") && TAL.size() >= 1 &&
- TAL[0].getKind() == TemplateArgument::Type)
- return {Call->Index, TAL[0].getAsType(), Call->CallExpr};
- }
+ /// Information about a stack frame for std::allocator<T>::[de]allocate.
+ struct StdAllocatorCaller {
+ unsigned FrameIndex;
+ QualType ElemType;
+ const Expr *Call;
+ explicit operator bool() const { return FrameIndex != 0; };
+ };
- return {};
- }
+ StdAllocatorCaller getStdAllocatorCaller(StringRef FnName) const {
+ for (const CallStackFrame *Call = CurrentCall; Call != &BottomFrame;
+ Call = Call->Caller) {
+ const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Call->Callee);
+ if (!MD)
+ continue;
+ const IdentifierInfo *FnII = MD->getIdentifier();
+ if (!FnII || !FnII->isStr(FnName))
+ continue;
- void performLifetimeExtension() {
- // Disable the cleanups for lifetime-extended temporaries.
- llvm::erase_if(CleanupStack, [](Cleanup &C) {
- return !C.isDestroyedAtEndOf(ScopeKind::FullExpression);
- });
- }
+ const auto *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(MD->getParent());
+ if (!CTSD)
+ continue;
- /// Throw away any remaining cleanups at the end of evaluation. If any
- /// cleanups would have had a side-effect, note that as an unmodeled
- /// side-effect and return false. Otherwise, return true.
- bool discardCleanups() {
- for (Cleanup &C : CleanupStack) {
- if (C.hasSideEffect() && !noteSideEffect()) {
- CleanupStack.clear();
- return false;
- }
- }
- CleanupStack.clear();
- return true;
+ const IdentifierInfo *ClassII = CTSD->getIdentifier();
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ if (CTSD->isInStdNamespace() && ClassII && ClassII->isStr("allocator") &&
+ TAL.size() >= 1 && TAL[0].getKind() == TemplateArgument::Type)
+ return {Call->Index, TAL[0].getAsType(), Call->CallExpr};
}
- private:
- interp::Frame *getCurrentFrame() override { return CurrentCall; }
- const interp::Frame *getBottomFrame() const override { return &BottomFrame; }
+ return {};
+ }
- bool hasActiveDiagnostic() override { return HasActiveDiagnostic; }
- void setActiveDiagnostic(bool Flag) override { HasActiveDiagnostic = Flag; }
+ void performLifetimeExtension() {
+ // Disable the cleanups for lifetime-extended temporaries.
+ llvm::erase_if(CleanupStack, [](Cleanup &C) {
+ return !C.isDestroyedAtEndOf(ScopeKind::FullExpression);
+ });
+ }
- void setFoldFailureDiagnostic(bool Flag) override {
- HasFoldFailureDiagnostic = Flag;
+ /// Throw away any remaining cleanups at the end of evaluation. If any
+ /// cleanups would have had a side-effect, note that as an unmodeled
+ /// side-effect and return false. Otherwise, return true.
+ bool discardCleanups() {
+ for (Cleanup &C : CleanupStack) {
+ if (C.hasSideEffect() && !noteSideEffect()) {
+ CleanupStack.clear();
+ return false;
+ }
}
+ CleanupStack.clear();
+ return true;
+ }
- Expr::EvalStatus &getEvalStatus() const override { return EvalStatus; }
+private:
+ interp::Frame *getCurrentFrame() override { return CurrentCall; }
+ const interp::Frame *getBottomFrame() const override { return &BottomFrame; }
- // If we have a prior diagnostic, it will be noting that the expression
- // isn't a constant expression. This diagnostic is more important,
- // unless we require this evaluation to produce a constant expression.
- //
- // FIXME: We might want to show both diagnostics to the user in
- // EM_ConstantFold mode.
- bool hasPriorDiagnostic() override {
- if (!EvalStatus.Diag->empty()) {
- switch (EvalMode) {
- case EM_ConstantFold:
- case EM_IgnoreSideEffects:
- if (!HasFoldFailureDiagnostic)
- break;
- // We've already failed to fold something. Keep that diagnostic.
- [[fallthrough]];
- case EM_ConstantExpression:
- case EM_ConstantExpressionUnevaluated:
- setActiveDiagnostic(false);
- return true;
- }
- }
- return false;
- }
+ bool hasActiveDiagnostic() override { return HasActiveDiagnostic; }
+ void setActiveDiagnostic(bool Flag) override { HasActiveDiagnostic = Flag; }
- unsigned getCallStackDepth() override { return CallStackDepth; }
+ void setFoldFailureDiagnostic(bool Flag) override {
+ HasFoldFailureDiagnostic = Flag;
+ }
- public:
- /// Should we continue evaluation after encountering a side-effect that we
- /// couldn't model?
- bool keepEvaluatingAfterSideEffect() const override {
+ Expr::EvalStatus &getEvalStatus() const override { return EvalStatus; }
+
+ // If we have a prior diagnostic, it will be noting that the expression
+ // isn't a constant expression. This diagnostic is more important,
+ // unless we require this evaluation to produce a constant expression.
+ //
+ // FIXME: We might want to show both diagnostics to the user in
+ // EM_ConstantFold mode.
+ bool hasPriorDiagnostic() override {
+ if (!EvalStatus.Diag->empty()) {
switch (EvalMode) {
+ case EM_ConstantFold:
case EM_IgnoreSideEffects:
- return true;
-
+ if (!HasFoldFailureDiagnostic)
+ break;
+ // We've already failed to fold something. Keep that diagnostic.
+ [[fallthrough]];
case EM_ConstantExpression:
case EM_ConstantExpressionUnevaluated:
- case EM_ConstantFold:
- // By default, assume any side effect might be valid in some other
- // evaluation of this expression from a different context.
- return checkingPotentialConstantExpression() ||
- checkingForUndefinedBehavior();
+ setActiveDiagnostic(false);
+ return true;
}
- llvm_unreachable("Missed EvalMode case");
}
+ return false;
+ }
- /// Note that we have had a side-effect, and determine whether we should
- /// keep evaluating.
- bool noteSideEffect() override {
- EvalStatus.HasSideEffects = true;
- return keepEvaluatingAfterSideEffect();
- }
+ unsigned getCallStackDepth() override { return CallStackDepth; }
- /// Should we continue evaluation after encountering undefined behavior?
- bool keepEvaluatingAfterUndefinedBehavior() {
- switch (EvalMode) {
- case EM_IgnoreSideEffects:
- case EM_ConstantFold:
- return true;
+public:
+ /// Should we continue evaluation after encountering a side-effect that we
+ /// couldn't model?
+ bool keepEvaluatingAfterSideEffect() const override {
+ switch (EvalMode) {
+ case EM_IgnoreSideEffects:
+ return true;
- case EM_ConstantExpression:
- case EM_ConstantExpressionUnevaluated:
- return checkingForUndefinedBehavior();
- }
- llvm_unreachable("Missed EvalMode case");
+ case EM_ConstantExpression:
+ case EM_ConstantExpressionUnevaluated:
+ case EM_ConstantFold:
+ // By default, assume any side effect might be valid in some other
+ // evaluation of this expression from a different context.
+ return checkingPotentialConstantExpression() ||
+ checkingForUndefinedBehavior();
}
+ llvm_unreachable("Missed EvalMode case");
+ }
+
+ /// Note that we have had a side-effect, and determine whether we should
+ /// keep evaluating.
+ bool noteSideEffect() override {
+ EvalStatus.HasSideEffects = true;
+ return keepEvaluatingAfterSideEffect();
+ }
+
+ /// Should we continue evaluation after encountering undefined behavior?
+ bool keepEvaluatingAfterUndefinedBehavior() {
+ switch (EvalMode) {
+ case EM_IgnoreSideEffects:
+ case EM_ConstantFold:
+ return true;
- /// Note that we hit something that was technically undefined behavior, but
- /// that we can evaluate past it (such as signed overflow or floating-point
- /// division by zero.)
- bool noteUndefinedBehavior() override {
- EvalStatus.HasUndefinedBehavior = true;
- return keepEvaluatingAfterUndefinedBehavior();
+ case EM_ConstantExpression:
+ case EM_ConstantExpressionUnevaluated:
+ return checkingForUndefinedBehavior();
}
+ llvm_unreachable("Missed EvalMode case");
+ }
- /// Should we continue evaluation as much as possible after encountering a
- /// construct which can't be reduced to a value?
- bool keepEvaluatingAfterFailure() const override {
- if (!StepsLeft)
- return false;
+ /// Note that we hit something that was technically undefined behavior, but
+ /// that we can evaluate past it (such as signed overflow or floating-point
+ /// division by zero.)
+ bool noteUndefinedBehavior() override {
+ EvalStatus.HasUndefinedBehavior = true;
+ return keepEvaluatingAfterUndefinedBehavior();
+ }
- switch (EvalMode) {
- case EM_ConstantExpression:
- case EM_ConstantExpressionUnevaluated:
- case EM_ConstantFold:
- case EM_IgnoreSideEffects:
- return checkingPotentialConstantExpression() ||
- checkingForUndefinedBehavior();
- }
- llvm_unreachable("Missed EvalMode case");
- }
-
- /// Notes that we failed to evaluate an expression that other expressions
- /// directly depend on, and determine if we should keep evaluating. This
- /// should only be called if we actually intend to keep evaluating.
- ///
- /// Call noteSideEffect() instead if we may be able to ignore the value that
- /// we failed to evaluate, e.g. if we failed to evaluate Foo() in:
- ///
- /// (Foo(), 1) // use noteSideEffect
- /// (Foo() || true) // use noteSideEffect
- /// Foo() + 1 // use noteFailure
- [[nodiscard]] bool noteFailure() {
- // Failure when evaluating some expression often means there is some
- // subexpression whose evaluation was skipped. Therefore, (because we
- // don't track whether we skipped an expression when unwinding after an
- // evaluation failure) every evaluation failure that bubbles up from a
- // subexpression implies that a side-effect has potentially happened. We
- // skip setting the HasSideEffects flag to true until we decide to
- // continue evaluating after that point, which happens here.
- bool KeepGoing = keepEvaluatingAfterFailure();
- EvalStatus.HasSideEffects |= KeepGoing;
- return KeepGoing;
- }
-
- class ArrayInitLoopIndex {
- EvalInfo &Info;
- uint64_t OuterIndex;
+ /// Should we continue evaluation as much as possible after encountering a
+ /// construct which can't be reduced to a value?
+ bool keepEvaluatingAfterFailure() const override {
+ if (!StepsLeft)
+ return false;
- public:
- ArrayInitLoopIndex(EvalInfo &Info)
- : Info(Info), OuterIndex(Info.ArrayInitIndex) {
- Info.ArrayInitIndex = 0;
- }
- ~ArrayInitLoopIndex() { Info.ArrayInitIndex = OuterIndex; }
+ switch (EvalMode) {
+ case EM_ConstantExpression:
+ case EM_ConstantExpressionUnevaluated:
+ case EM_ConstantFold:
+ case EM_IgnoreSideEffects:
+ return checkingPotentialConstantExpression() ||
+ checkingForUndefinedBehavior();
+ }
+ llvm_unreachable("Missed EvalMode case");
+ }
- operator uint64_t&() { return Info.ArrayInitIndex; }
- };
+ /// Notes that we failed to evaluate an expression that other expressions
+ /// directly depend on, and determine if we should keep evaluating. This
+ /// should only be called if we actually intend to keep evaluating.
+ ///
+ /// Call noteSideEffect() instead if we may be able to ignore the value that
+ /// we failed to evaluate, e.g. if we failed to evaluate Foo() in:
+ ///
+ /// (Foo(), 1) // use noteSideEffect
+ /// (Foo() || true) // use noteSideEffect
+ /// Foo() + 1 // use noteFailure
+ [[nodiscard]] bool noteFailure() {
+ // Failure when evaluating some expression often means there is some
+ // subexpression whose evaluation was skipped. Therefore, (because we
+ // don't track whether we skipped an expression when unwinding after an
+ // evaluation failure) every evaluation failure that bubbles up from a
+ // subexpression implies that a side-effect has potentially happened. We
+ // skip setting the HasSideEffects flag to true until we decide to
+ // continue evaluating after that point, which happens here.
+ bool KeepGoing = keepEvaluatingAfterFailure();
+ EvalStatus.HasSideEffects |= KeepGoing;
+ return KeepGoing;
+ }
+
+ class ArrayInitLoopIndex {
+ EvalInfo &Info;
+ uint64_t OuterIndex;
+
+ public:
+ ArrayInitLoopIndex(EvalInfo &Info)
+ : Info(Info), OuterIndex(Info.ArrayInitIndex) {
+ Info.ArrayInitIndex = 0;
+ }
+ ~ArrayInitLoopIndex() { Info.ArrayInitIndex = OuterIndex; }
+
+ operator uint64_t &() { return Info.ArrayInitIndex; }
};
+};
- /// Object used to treat all foldable expressions as constant expressions.
- struct FoldConstant {
- EvalInfo &Info;
- bool Enabled;
- bool HadNoPriorDiags;
- EvalInfo::EvaluationMode OldMode;
+/// Object used to treat all foldable expressions as constant expressions.
+struct FoldConstant {
+ EvalInfo &Info;
+ bool Enabled;
+ bool HadNoPriorDiags;
+ EvalInfo::EvaluationMode OldMode;
- explicit FoldConstant(EvalInfo &Info, bool Enabled)
- : Info(Info),
- Enabled(Enabled),
- HadNoPriorDiags(Info.EvalStatus.Diag &&
- Info.EvalStatus.Diag->empty() &&
+ explicit FoldConstant(EvalInfo &Info, bool Enabled)
+ : Info(Info), Enabled(Enabled),
+ HadNoPriorDiags(Info.EvalStatus.Diag && Info.EvalStatus.Diag->empty() &&
!Info.EvalStatus.HasSideEffects),
OldMode(Info.EvalMode) {
- if (Enabled)
- Info.EvalMode = EvalInfo::EM_ConstantFold;
- }
- void keepDiagnostics() { Enabled = false; }
- ~FoldConstant() {
- if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() &&
- !Info.EvalStatus.HasSideEffects)
- Info.EvalStatus.Diag->clear();
- Info.EvalMode = OldMode;
- }
- };
+ if (Enabled)
+ Info.EvalMode = EvalInfo::EM_ConstantFold;
+ }
+ void keepDiagnostics() { Enabled = false; }
+ ~FoldConstant() {
+ if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() &&
+ !Info.EvalStatus.HasSideEffects)
+ Info.EvalStatus.Diag->clear();
+ Info.EvalMode = OldMode;
+ }
+};
- /// RAII object used to set the current evaluation mode to ignore
- /// side-effects.
- struct IgnoreSideEffectsRAII {
- EvalInfo &Info;
- EvalInfo::EvaluationMode OldMode;
- explicit IgnoreSideEffectsRAII(EvalInfo &Info)
- : Info(Info), OldMode(Info.EvalMode) {
- Info.EvalMode = EvalInfo::EM_IgnoreSideEffects;
- }
+/// RAII object used to set the current evaluation mode to ignore
+/// side-effects.
+struct IgnoreSideEffectsRAII {
+ EvalInfo &Info;
+ EvalInfo::EvaluationMode OldMode;
+ explicit IgnoreSideEffectsRAII(EvalInfo &Info)
+ : Info(Info), OldMode(Info.EvalMode) {
+ Info.EvalMode = EvalInfo::EM_IgnoreSideEffects;
+ }
- ~IgnoreSideEffectsRAII() { Info.EvalMode = OldMode; }
- };
+ ~IgnoreSideEffectsRAII() { Info.EvalMode = OldMode; }
+};
- /// RAII object used to optionally suppress diagnostics and side-effects from
- /// a speculative evaluation.
- class SpeculativeEvaluationRAII {
- EvalInfo *Info = nullptr;
- Expr::EvalStatus OldStatus;
- unsigned OldSpeculativeEvaluationDepth = 0;
+/// RAII object used to optionally suppress diagnostics and side-effects from
+/// a speculative evaluation.
+class SpeculativeEvaluationRAII {
+ EvalInfo *Info = nullptr;
+ Expr::EvalStatus OldStatus;
+ unsigned OldSpeculativeEvaluationDepth = 0;
- void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
- Info = Other.Info;
- OldStatus = Other.OldStatus;
- OldSpeculativeEvaluationDepth = Other.OldSpeculativeEvaluationDepth;
- Other.Info = nullptr;
- }
+ void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
+ Info = Other.Info;
+ OldStatus = Other.OldStatus;
+ OldSpeculativeEvaluationDepth = Other.OldSpeculativeEvaluationDepth;
+ Other.Info = nullptr;
+ }
- void maybeRestoreState() {
- if (!Info)
- return;
+ void maybeRestoreState() {
+ if (!Info)
+ return;
- Info->EvalStatus = OldStatus;
- Info->SpeculativeEvaluationDepth = OldSpeculativeEvaluationDepth;
- }
+ Info->EvalStatus = OldStatus;
+ Info->SpeculativeEvaluationDepth = OldSpeculativeEvaluationDepth;
+ }
- public:
- SpeculativeEvaluationRAII() = default;
+public:
+ SpeculativeEvaluationRAII() = default;
- SpeculativeEvaluationRAII(
- EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
- : Info(&Info), OldStatus(Info.EvalStatus),
- OldSpeculativeEvaluationDepth(Info.SpeculativeEvaluationDepth) {
- Info.EvalStatus.Diag = NewDiag;
- Info.SpeculativeEvaluationDepth = Info.CallStackDepth + 1;
- }
+ SpeculativeEvaluationRAII(
+ EvalInfo &Info, SmallVectorImpl<PartialDiagnosticAt> *NewDiag = nullptr)
+ : Info(&Info), OldStatus(Info.EvalStatus),
+ OldSpeculativeEvaluationDepth(Info.SpeculativeEvaluationDepth) {
+ Info.EvalStatus.Diag = NewDiag;
+ Info.SpeculativeEvaluationDepth = Info.CallStackDepth + 1;
+ }
- SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete;
- SpeculativeEvaluationRAII(SpeculativeEvaluationRAII &&Other) {
- moveFromAndCancel(std::move(Other));
- }
+ SpeculativeEvaluationRAII(const SpeculativeEvaluationRAII &Other) = delete;
+ SpeculativeEvaluationRAII(SpeculativeEvaluationRAII &&Other) {
+ moveFromAndCancel(std::move(Other));
+ }
- SpeculativeEvaluationRAII &operator=(SpeculativeEvaluationRAII &&Other) {
- maybeRestoreState();
- moveFromAndCancel(std::move(Other));
- return *this;
- }
+ SpeculativeEvaluationRAII &operator=(SpeculativeEvaluationRAII &&Other) {
+ maybeRestoreState();
+ moveFromAndCancel(std::move(Other));
+ return *this;
+ }
- ~SpeculativeEvaluationRAII() { maybeRestoreState(); }
- };
+ ~SpeculativeEvaluationRAII() { maybeRestoreState(); }
+};
- /// RAII object wrapping a full-expression or block scope, and handling
- /// the ending of the lifetime of temporaries created within it.
- template<ScopeKind Kind>
- class ScopeRAII {
- EvalInfo &Info;
- unsigned OldStackSize;
- public:
- ScopeRAII(EvalInfo &Info)
- : Info(Info), OldStackSize(Info.CleanupStack.size()) {
- // Push a new temporary version. This is needed to distinguish between
- // temporaries created in different iterations of a loop.
- Info.CurrentCall->pushTempVersion();
- }
- bool destroy(bool RunDestructors = true) {
- bool OK = cleanup(Info, RunDestructors, OldStackSize);
- OldStackSize = -1U;
- return OK;
- }
- ~ScopeRAII() {
- if (OldStackSize != -1U)
- destroy(false);
- // Body moved to a static method to encourage the compiler to inline away
- // instances of this class.
- Info.CurrentCall->popTempVersion();
- }
- private:
- static bool cleanup(EvalInfo &Info, bool RunDestructors,
- unsigned OldStackSize) {
- assert(OldStackSize <= Info.CleanupStack.size() &&
- "running cleanups out of order?");
+/// RAII object wrapping a full-expression or block scope, and handling
+/// the ending of the lifetime of temporaries created within it.
+template <ScopeKind Kind> class ScopeRAII {
+ EvalInfo &Info;
+ unsigned OldStackSize;
- // Run all cleanups for a block scope, and non-lifetime-extended cleanups
- // for a full-expression scope.
- bool Success = true;
- for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
- if (Info.CleanupStack[I - 1].isDestroyedAtEndOf(Kind)) {
- if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
- Success = false;
- break;
- }
+public:
+ ScopeRAII(EvalInfo &Info)
+ : Info(Info), OldStackSize(Info.CleanupStack.size()) {
+ // Push a new temporary version. This is needed to distinguish between
+ // temporaries created in different iterations of a loop.
+ Info.CurrentCall->pushTempVersion();
+ }
+ bool destroy(bool RunDestructors = true) {
+ bool OK = cleanup(Info, RunDestructors, OldStackSize);
+ OldStackSize = -1U;
+ return OK;
+ }
+ ~ScopeRAII() {
+ if (OldStackSize != -1U)
+ destroy(false);
+ // Body moved to a static method to encourage the compiler to inline away
+ // instances of this class.
+ Info.CurrentCall->popTempVersion();
+ }
+
+private:
+ static bool cleanup(EvalInfo &Info, bool RunDestructors,
+ unsigned OldStackSize) {
+ assert(OldStackSize <= Info.CleanupStack.size() &&
+ "running cleanups out of order?");
+
+ // Run all cleanups for a block scope, and non-lifetime-extended cleanups
+ // for a full-expression scope.
+ bool Success = true;
+ for (unsigned I = Info.CleanupStack.size(); I > OldStackSize; --I) {
+ if (Info.CleanupStack[I - 1].isDestroyedAtEndOf(Kind)) {
+ if (!Info.CleanupStack[I - 1].endLifetime(Info, RunDestructors)) {
+ Success = false;
+ break;
}
}
-
- // Compact any retained cleanups.
- auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
- if (Kind != ScopeKind::Block)
- NewEnd =
- std::remove_if(NewEnd, Info.CleanupStack.end(), [](Cleanup &C) {
- return C.isDestroyedAtEndOf(Kind);
- });
- Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
- return Success;
}
- };
- typedef ScopeRAII<ScopeKind::Block> BlockScopeRAII;
- typedef ScopeRAII<ScopeKind::FullExpression> FullExpressionRAII;
- typedef ScopeRAII<ScopeKind::Call> CallScopeRAII;
-}
+
+ // Compact any retained cleanups.
+ auto NewEnd = Info.CleanupStack.begin() + OldStackSize;
+ if (Kind != ScopeKind::Block)
+ NewEnd = std::remove_if(NewEnd, Info.CleanupStack.end(), [](Cleanup &C) {
+ return C.isDestroyedAtEndOf(Kind);
+ });
+ Info.CleanupStack.erase(NewEnd, Info.CleanupStack.end());
+ return Success;
+ }
+};
+typedef ScopeRAII<ScopeKind::Block> BlockScopeRAII;
+typedef ScopeRAII<ScopeKind::FullExpression> FullExpressionRAII;
+typedef ScopeRAII<ScopeKind::Call> CallScopeRAII;
+} // namespace
bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
CheckSubobjectKind CSK) {
if (Invalid)
return false;
if (isOnePastTheEnd()) {
- Info.CCEDiag(E, diag::note_constexpr_past_end_subobject)
- << CSK;
+ Info.CCEDiag(E, diag::note_constexpr_past_end_subobject) << CSK;
setInvalid();
return false;
}
@@ -1504,11 +1477,9 @@ void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
// the most derived array.
if (MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement)
Info.CCEDiag(E, diag::note_constexpr_array_index)
- << N << /*array*/ 0
- << static_cast<unsigned>(getMostDerivedArraySize());
+ << N << /*array*/ 0 << static_cast<unsigned>(getMostDerivedArraySize());
else
- Info.CCEDiag(E, diag::note_constexpr_array_index)
- << N << /*non-array*/ 1;
+ Info.CCEDiag(E, diag::note_constexpr_array_index) << N << /*non-array*/ 1;
setInvalid();
}
@@ -1589,324 +1560,315 @@ static bool isValidIndeterminateAccess(AccessKinds AK) {
}
namespace {
- struct ComplexValue {
- private:
- bool IsInt;
+struct ComplexValue {
+private:
+ bool IsInt;
- public:
- APSInt IntReal, IntImag;
- APFloat FloatReal, FloatImag;
+public:
+ APSInt IntReal, IntImag;
+ APFloat FloatReal, FloatImag;
- ComplexValue() : FloatReal(APFloat::Bogus()), FloatImag(APFloat::Bogus()) {}
+ ComplexValue() : FloatReal(APFloat::Bogus()), FloatImag(APFloat::Bogus()) {}
- void makeComplexFloat() { IsInt = false; }
- bool isComplexFloat() const { return !IsInt; }
- APFloat &getComplexFloatReal() { return FloatReal; }
- APFloat &getComplexFloatImag() { return FloatImag; }
+ void makeComplexFloat() { IsInt = false; }
+ bool isComplexFloat() const { return !IsInt; }
+ APFloat &getComplexFloatReal() { return FloatReal; }
+ APFloat &getComplexFloatImag() { return FloatImag; }
- void makeComplexInt() { IsInt = true; }
- bool isComplexInt() const { return IsInt; }
- APSInt &getComplexIntReal() { return IntReal; }
- APSInt &getComplexIntImag() { return IntImag; }
+ void makeComplexInt() { IsInt = true; }
+ bool isComplexInt() const { return IsInt; }
+ APSInt &getComplexIntReal() { return IntReal; }
+ APSInt &getComplexIntImag() { return IntImag; }
- void moveInto(APValue &v) const {
- if (isComplexFloat())
- v = APValue(FloatReal, FloatImag);
- else
- v = APValue(IntReal, IntImag);
- }
- void setFrom(const APValue &v) {
- assert(v.isComplexFloat() || v.isComplexInt());
- if (v.isComplexFloat()) {
- makeComplexFloat();
- FloatReal = v.getComplexFloatReal();
- FloatImag = v.getComplexFloatImag();
- } else {
- makeComplexInt();
- IntReal = v.getComplexIntReal();
- IntImag = v.getComplexIntImag();
- }
+ void moveInto(APValue &v) const {
+ if (isComplexFloat())
+ v = APValue(FloatReal, FloatImag);
+ else
+ v = APValue(IntReal, IntImag);
+ }
+ void setFrom(const APValue &v) {
+ assert(v.isComplexFloat() || v.isComplexInt());
+ if (v.isComplexFloat()) {
+ makeComplexFloat();
+ FloatReal = v.getComplexFloatReal();
+ FloatImag = v.getComplexFloatImag();
+ } else {
+ makeComplexInt();
+ IntReal = v.getComplexIntReal();
+ IntImag = v.getComplexIntImag();
}
- };
+ }
+};
- struct LValue {
- APValue::LValueBase Base;
- CharUnits Offset;
- SubobjectDesignator Designator;
- bool IsNullPtr : 1;
- bool InvalidBase : 1;
- // P2280R4 track if we have an unknown reference or pointer.
- bool AllowConstexprUnknown = false;
-
- const APValue::LValueBase getLValueBase() const { return Base; }
- bool allowConstexprUnknown() const { return AllowConstexprUnknown; }
- CharUnits &getLValueOffset() { return Offset; }
- const CharUnits &getLValueOffset() const { return Offset; }
- SubobjectDesignator &getLValueDesignator() { return Designator; }
- const SubobjectDesignator &getLValueDesignator() const { return Designator;}
- bool isNullPointer() const { return IsNullPtr;}
-
- unsigned getLValueCallIndex() const { return Base.getCallIndex(); }
- unsigned getLValueVersion() const { return Base.getVersion(); }
-
- void moveInto(APValue &V) const {
- if (Designator.Invalid)
- V = APValue(Base, Offset, APValue::NoLValuePath(), IsNullPtr);
- else {
- assert(!InvalidBase && "APValues can't handle invalid LValue bases");
- V = APValue(Base, Offset, Designator.Entries,
- Designator.IsOnePastTheEnd, IsNullPtr);
- }
- if (AllowConstexprUnknown)
- V.setConstexprUnknown();
- }
- void setFrom(ASTContext &Ctx, const APValue &V) {
- assert(V.isLValue() && "Setting LValue from a non-LValue?");
- Base = V.getLValueBase();
- Offset = V.getLValueOffset();
- InvalidBase = false;
- Designator = SubobjectDesignator(Ctx, V);
- IsNullPtr = V.isNullPointer();
- AllowConstexprUnknown = V.allowConstexprUnknown();
+struct LValue {
+ APValue::LValueBase Base;
+ CharUnits Offset;
+ SubobjectDesignator Designator;
+ bool IsNullPtr : 1;
+ bool InvalidBase : 1;
+ // P2280R4 track if we have an unknown reference or pointer.
+ bool AllowConstexprUnknown = false;
+
+ const APValue::LValueBase getLValueBase() const { return Base; }
+ bool allowConstexprUnknown() const { return AllowConstexprUnknown; }
+ CharUnits &getLValueOffset() { return Offset; }
+ const CharUnits &getLValueOffset() const { return Offset; }
+ SubobjectDesignator &getLValueDesignator() { return Designator; }
+ const SubobjectDesignator &getLValueDesignator() const { return Designator; }
+ bool isNullPointer() const { return IsNullPtr; }
+
+ unsigned getLValueCallIndex() const { return Base.getCallIndex(); }
+ unsigned getLValueVersion() const { return Base.getVersion(); }
+
+ void moveInto(APValue &V) const {
+ if (Designator.Invalid)
+ V = APValue(Base, Offset, APValue::NoLValuePath(), IsNullPtr);
+ else {
+ assert(!InvalidBase && "APValues can't handle invalid LValue bases");
+ V = APValue(Base, Offset, Designator.Entries, Designator.IsOnePastTheEnd,
+ IsNullPtr);
}
+ if (AllowConstexprUnknown)
+ V.setConstexprUnknown();
+ }
+ void setFrom(ASTContext &Ctx, const APValue &V) {
+ assert(V.isLValue() && "Setting LValue from a non-LValue?");
+ Base = V.getLValueBase();
+ Offset = V.getLValueOffset();
+ InvalidBase = false;
+ Designator = SubobjectDesignator(Ctx, V);
+ IsNullPtr = V.isNullPointer();
+ AllowConstexprUnknown = V.allowConstexprUnknown();
+ }
- void set(APValue::LValueBase B, bool BInvalid = false) {
+ void set(APValue::LValueBase B, bool BInvalid = false) {
#ifndef NDEBUG
- // We only allow a few types of invalid bases. Enforce that here.
- if (BInvalid) {
- const auto *E = B.get<const Expr *>();
- assert((isa<MemberExpr>(E) || tryUnwrapAllocSizeCall(E)) &&
- "Unexpected type of invalid base");
- }
+ // We only allow a few types of invalid bases. Enforce that here.
+ if (BInvalid) {
+ const auto *E = B.get<const Expr *>();
+ assert((isa<MemberExpr>(E) || tryUnwrapAllocSizeCall(E)) &&
+ "Unexpected type of invalid base");
+ }
#endif
- Base = B;
- Offset = CharUnits::fromQuantity(0);
- InvalidBase = BInvalid;
- Designator = SubobjectDesignator(getType(B));
- IsNullPtr = false;
- AllowConstexprUnknown = false;
- }
+ Base = B;
+ Offset = CharUnits::fromQuantity(0);
+ InvalidBase = BInvalid;
+ Designator = SubobjectDesignator(getType(B));
+ IsNullPtr = false;
+ AllowConstexprUnknown = false;
+ }
- void setNull(ASTContext &Ctx, QualType PointerTy) {
- Base = (const ValueDecl *)nullptr;
- Offset =
- CharUnits::fromQuantity(Ctx.getTargetNullPointerValue(PointerTy));
- InvalidBase = false;
- Designator = SubobjectDesignator(PointerTy->getPointeeType());
- IsNullPtr = true;
- AllowConstexprUnknown = false;
- }
+ void setNull(ASTContext &Ctx, QualType PointerTy) {
+ Base = (const ValueDecl *)nullptr;
+ Offset = CharUnits::fromQuantity(Ctx.getTargetNullPointerValue(PointerTy));
+ InvalidBase = false;
+ Designator = SubobjectDesignator(PointerTy->getPointeeType());
+ IsNullPtr = true;
+ AllowConstexprUnknown = false;
+ }
- void setInvalid(APValue::LValueBase B, unsigned I = 0) {
- set(B, true);
- }
+ void setInvalid(APValue::LValueBase B, unsigned I = 0) { set(B, true); }
- std::string toString(ASTContext &Ctx, QualType T) const {
- APValue Printable;
- moveInto(Printable);
- return Printable.getAsString(Ctx, T);
- }
+ std::string toString(ASTContext &Ctx, QualType T) const {
+ APValue Printable;
+ moveInto(Printable);
+ return Printable.getAsString(Ctx, T);
+ }
- private:
- // Check that this LValue is not based on a null pointer. If it is, produce
- // a diagnostic and mark the designator as invalid.
- template <typename GenDiagType>
- bool checkNullPointerDiagnosingWith(const GenDiagType &GenDiag) {
- if (Designator.Invalid)
- return false;
- if (IsNullPtr) {
- GenDiag();
- Designator.setInvalid();
- return false;
- }
- return true;
+private:
+ // Check that this LValue is not based on a null pointer. If it is, produce
+ // a diagnostic and mark the designator as invalid.
+ template <typename GenDiagType>
+ bool checkNullPointerDiagnosingWith(const GenDiagType &GenDiag) {
+ if (Designator.Invalid)
+ return false;
+ if (IsNullPtr) {
+ GenDiag();
+ Designator.setInvalid();
+ return false;
}
+ return true;
+ }
- public:
- bool checkNullPointer(EvalInfo &Info, const Expr *E,
- CheckSubobjectKind CSK) {
- return checkNullPointerDiagnosingWith([&Info, E, CSK] {
- Info.CCEDiag(E, diag::note_constexpr_null_subobject) << CSK;
- });
- }
+public:
+ bool checkNullPointer(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
+ return checkNullPointerDiagnosingWith([&Info, E, CSK] {
+ Info.CCEDiag(E, diag::note_constexpr_null_subobject) << CSK;
+ });
+ }
- bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
- AccessKinds AK) {
- return checkNullPointerDiagnosingWith([&Info, E, AK] {
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
- });
- }
+ bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
+ AccessKinds AK) {
+ return checkNullPointerDiagnosingWith([&Info, E, AK] {
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
+ });
+ }
- // Check this LValue refers to an object. If not, set the designator to be
- // invalid and emit a diagnostic.
- bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
- return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) &&
- Designator.checkSubobject(Info, E, CSK);
- }
+ // Check this LValue refers to an object. If not, set the designator to be
+ // invalid and emit a diagnostic.
+ bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
+ return (CSK == CSK_ArrayToPointer || checkNullPointer(Info, E, CSK)) &&
+ Designator.checkSubobject(Info, E, CSK);
+ }
- void addDecl(EvalInfo &Info, const Expr *E,
- const Decl *D, bool Virtual = false) {
- if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))
- Designator.addDeclUnchecked(D, Virtual);
- }
- void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) {
- if (!Designator.Entries.empty()) {
- Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array);
- Designator.setInvalid();
- return;
- }
- if (checkSubobject(Info, E, CSK_ArrayToPointer)) {
- assert(getType(Base)->isPointerType() || getType(Base)->isArrayType());
- Designator.FirstEntryIsAnUnsizedArray = true;
- Designator.addUnsizedArrayUnchecked(ElemTy);
- }
- }
- void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) {
- if (checkSubobject(Info, E, CSK_ArrayToPointer))
- Designator.addArrayUnchecked(CAT);
- }
- void addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) {
- if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))
- Designator.addComplexUnchecked(EltTy, Imag);
- }
- void addVectorElement(EvalInfo &Info, const Expr *E, QualType EltTy,
- uint64_t Size, uint64_t Idx) {
- if (checkSubobject(Info, E, CSK_VectorElement))
- Designator.addVectorElementUnchecked(EltTy, Size, Idx);
+ void addDecl(EvalInfo &Info, const Expr *E, const Decl *D,
+ bool Virtual = false) {
+ if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))
+ Designator.addDeclUnchecked(D, Virtual);
+ }
+ void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) {
+ if (!Designator.Entries.empty()) {
+ Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array);
+ Designator.setInvalid();
+ return;
}
- void clearIsNullPointer() {
- IsNullPtr = false;
+ if (checkSubobject(Info, E, CSK_ArrayToPointer)) {
+ assert(getType(Base)->isPointerType() || getType(Base)->isArrayType());
+ Designator.FirstEntryIsAnUnsizedArray = true;
+ Designator.addUnsizedArrayUnchecked(ElemTy);
}
- void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E,
- const APSInt &Index, CharUnits ElementSize) {
- // An index of 0 has no effect. (In C, adding 0 to a null pointer is UB,
- // but we're not required to diagnose it and it's valid in C++.)
- if (!Index)
- return;
-
- // Compute the new offset in the appropriate width, wrapping at 64 bits.
- // FIXME: When compiling for a 32-bit target, we should use 32-bit
- // offsets.
- uint64_t Offset64 = Offset.getQuantity();
- uint64_t ElemSize64 = ElementSize.getQuantity();
- uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
- Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64);
+ }
+ void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) {
+ if (checkSubobject(Info, E, CSK_ArrayToPointer))
+ Designator.addArrayUnchecked(CAT);
+ }
+ void addComplex(EvalInfo &Info, const Expr *E, QualType EltTy, bool Imag) {
+ if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))
+ Designator.addComplexUnchecked(EltTy, Imag);
+ }
+ void addVectorElement(EvalInfo &Info, const Expr *E, QualType EltTy,
+ uint64_t Size, uint64_t Idx) {
+ if (checkSubobject(Info, E, CSK_VectorElement))
+ Designator.addVectorElementUnchecked(EltTy, Size, Idx);
+ }
+ void clearIsNullPointer() { IsNullPtr = false; }
+ void adjustOffsetAndIndex(EvalInfo &Info, const Expr *E, const APSInt &Index,
+ CharUnits ElementSize) {
+ // An index of 0 has no effect. (In C, adding 0 to a null pointer is UB,
+ // but we're not required to diagnose it and it's valid in C++.)
+ if (!Index)
+ return;
- if (checkNullPointer(Info, E, CSK_ArrayIndex))
- Designator.adjustIndex(Info, E, Index);
+ // Compute the new offset in the appropriate width, wrapping at 64 bits.
+ // FIXME: When compiling for a 32-bit target, we should use 32-bit
+ // offsets.
+ uint64_t Offset64 = Offset.getQuantity();
+ uint64_t ElemSize64 = ElementSize.getQuantity();
+ uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
+ Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64);
+
+ if (checkNullPointer(Info, E, CSK_ArrayIndex))
+ Designator.adjustIndex(Info, E, Index);
+ clearIsNullPointer();
+ }
+ void adjustOffset(CharUnits N) {
+ Offset += N;
+ if (N.getQuantity())
clearIsNullPointer();
- }
- void adjustOffset(CharUnits N) {
- Offset += N;
- if (N.getQuantity())
- clearIsNullPointer();
- }
- };
+ }
+};
- struct MemberPtr {
- MemberPtr() {}
- explicit MemberPtr(const ValueDecl *Decl)
- : DeclAndIsDerivedMember(Decl, false) {}
-
- /// The member or (direct or indirect) field referred to by this member
- /// pointer, or 0 if this is a null member pointer.
- const ValueDecl *getDecl() const {
- return DeclAndIsDerivedMember.getPointer();
- }
- /// Is this actually a member of some type derived from the relevant class?
- bool isDerivedMember() const {
- return DeclAndIsDerivedMember.getInt();
- }
- /// Get the class which the declaration actually lives in.
- const CXXRecordDecl *getContainingRecord() const {
- return cast<CXXRecordDecl>(
- DeclAndIsDerivedMember.getPointer()->getDeclContext());
- }
-
- void moveInto(APValue &V) const {
- V = APValue(getDecl(), isDerivedMember(), Path);
- }
- void setFrom(const APValue &V) {
- assert(V.isMemberPointer());
- DeclAndIsDerivedMember.setPointer(V.getMemberPointerDecl());
- DeclAndIsDerivedMember.setInt(V.isMemberPointerToDerivedMember());
- Path.clear();
- ArrayRef<const CXXRecordDecl*> P = V.getMemberPointerPath();
- Path.insert(Path.end(), P.begin(), P.end());
- }
-
- /// DeclAndIsDerivedMember - The member declaration, and a flag indicating
- /// whether the member is a member of some class derived from the class type
- /// of the member pointer.
- llvm::PointerIntPair<const ValueDecl*, 1, bool> DeclAndIsDerivedMember;
- /// Path - The path of base/derived classes from the member declaration's
- /// class (exclusive) to the class type of the member pointer (inclusive).
- SmallVector<const CXXRecordDecl*, 4> Path;
-
- /// Perform a cast towards the class of the Decl (either up or down the
- /// hierarchy).
- bool castBack(const CXXRecordDecl *Class) {
- assert(!Path.empty());
- const CXXRecordDecl *Expected;
- if (Path.size() >= 2)
- Expected = Path[Path.size() - 2];
- else
- Expected = getContainingRecord();
- if (Expected->getCanonicalDecl() != Class->getCanonicalDecl()) {
- // C++11 [expr.static.cast]p12: In a conversion from (D::*) to (B::*),
- // if B does not contain the original member and is not a base or
- // derived class of the class containing the original member, the result
- // of the cast is undefined.
- // C++11 [conv.mem]p2 does not cover this case for a cast from (B::*) to
- // (D::*). We consider that to be a language defect.
- return false;
- }
- Path.pop_back();
- return true;
+struct MemberPtr {
+ MemberPtr() {}
+ explicit MemberPtr(const ValueDecl *Decl)
+ : DeclAndIsDerivedMember(Decl, false) {}
+
+ /// The member or (direct or indirect) field referred to by this member
+ /// pointer, or 0 if this is a null member pointer.
+ const ValueDecl *getDecl() const {
+ return DeclAndIsDerivedMember.getPointer();
+ }
+ /// Is this actually a member of some type derived from the relevant class?
+ bool isDerivedMember() const { return DeclAndIsDerivedMember.getInt(); }
+ /// Get the class which the declaration actually lives in.
+ const CXXRecordDecl *getContainingRecord() const {
+ return cast<CXXRecordDecl>(
+ DeclAndIsDerivedMember.getPointer()->getDeclContext());
+ }
+
+ void moveInto(APValue &V) const {
+ V = APValue(getDecl(), isDerivedMember(), Path);
+ }
+ void setFrom(const APValue &V) {
+ assert(V.isMemberPointer());
+ DeclAndIsDerivedMember.setPointer(V.getMemberPointerDecl());
+ DeclAndIsDerivedMember.setInt(V.isMemberPointerToDerivedMember());
+ Path.clear();
+ ArrayRef<const CXXRecordDecl *> P = V.getMemberPointerPath();
+ Path.insert(Path.end(), P.begin(), P.end());
+ }
+
+ /// DeclAndIsDerivedMember - The member declaration, and a flag indicating
+ /// whether the member is a member of some class derived from the class type
+ /// of the member pointer.
+ llvm::PointerIntPair<const ValueDecl *, 1, bool> DeclAndIsDerivedMember;
+ /// Path - The path of base/derived classes from the member declaration's
+ /// class (exclusive) to the class type of the member pointer (inclusive).
+ SmallVector<const CXXRecordDecl *, 4> Path;
+
+ /// Perform a cast towards the class of the Decl (either up or down the
+ /// hierarchy).
+ bool castBack(const CXXRecordDecl *Class) {
+ assert(!Path.empty());
+ const CXXRecordDecl *Expected;
+ if (Path.size() >= 2)
+ Expected = Path[Path.size() - 2];
+ else
+ Expected = getContainingRecord();
+ if (Expected->getCanonicalDecl() != Class->getCanonicalDecl()) {
+ // C++11 [expr.static.cast]p12: In a conversion from (D::*) to (B::*),
+ // if B does not contain the original member and is not a base or
+ // derived class of the class containing the original member, the result
+ // of the cast is undefined.
+ // C++11 [conv.mem]p2 does not cover this case for a cast from (B::*) to
+ // (D::*). We consider that to be a language defect.
+ return false;
}
- /// Perform a base-to-derived member pointer cast.
- bool castToDerived(const CXXRecordDecl *Derived) {
- if (!getDecl())
- return true;
- if (!isDerivedMember()) {
- Path.push_back(Derived);
- return true;
- }
- if (!castBack(Derived))
- return false;
- if (Path.empty())
- DeclAndIsDerivedMember.setInt(false);
+ Path.pop_back();
+ return true;
+ }
+ /// Perform a base-to-derived member pointer cast.
+ bool castToDerived(const CXXRecordDecl *Derived) {
+ if (!getDecl())
+ return true;
+ if (!isDerivedMember()) {
+ Path.push_back(Derived);
return true;
}
- /// Perform a derived-to-base member pointer cast.
- bool castToBase(const CXXRecordDecl *Base) {
- if (!getDecl())
- return true;
- if (Path.empty())
- DeclAndIsDerivedMember.setInt(true);
- if (isDerivedMember()) {
- Path.push_back(Base);
- return true;
- }
- return castBack(Base);
- }
- };
-
- /// Compare two member pointers, which are assumed to be of the same type.
- static bool operator==(const MemberPtr &LHS, const MemberPtr &RHS) {
- if (!LHS.getDecl() || !RHS.getDecl())
- return !LHS.getDecl() && !RHS.getDecl();
- if (LHS.getDecl()->getCanonicalDecl() != RHS.getDecl()->getCanonicalDecl())
+ if (!castBack(Derived))
return false;
- return LHS.Path == RHS.Path;
+ if (Path.empty())
+ DeclAndIsDerivedMember.setInt(false);
+ return true;
}
+ /// Perform a derived-to-base member pointer cast.
+ bool castToBase(const CXXRecordDecl *Base) {
+ if (!getDecl())
+ return true;
+ if (Path.empty())
+ DeclAndIsDerivedMember.setInt(true);
+ if (isDerivedMember()) {
+ Path.push_back(Base);
+ return true;
+ }
+ return castBack(Base);
+ }
+};
+
+/// Compare two member pointers, which are assumed to be of the same type.
+static bool operator==(const MemberPtr &LHS, const MemberPtr &RHS) {
+ if (!LHS.getDecl() || !RHS.getDecl())
+ return !LHS.getDecl() && !RHS.getDecl();
+ if (LHS.getDecl()->getCanonicalDecl() != RHS.getDecl()->getCanonicalDecl())
+ return false;
+ return LHS.Path == RHS.Path;
}
+} // namespace
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
-static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
- const LValue &This, const Expr *E,
- bool AllowNonLiteralTypes = false);
+static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
+ const Expr *E, bool AllowNonLiteralTypes = false);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
bool InvalidBaseOK = false);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info,
@@ -1948,7 +1910,7 @@ static void negateAsSigned(APSInt &Int) {
Int = -Int;
}
-template<typename KeyT>
+template <typename KeyT>
APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T,
ScopeKind Scope, LValue &LV) {
unsigned Version = getTempVersion();
@@ -2030,9 +1992,9 @@ void CallStackFrame::describe(raw_ostream &Out) const {
Object->printPretty(Out, /*Helper=*/nullptr, Info.Ctx.getPrintingPolicy(),
/*Indentation=*/0);
if (Object->getType()->isPointerType())
- Out << "->";
+ Out << "->";
else
- Out << ".";
+ Out << ".";
} else if (const auto *OCE =
dyn_cast_if_present<CXXOperatorCallExpr>(CallExpr)) {
OCE->getArg(0)->printPretty(Out, /*Helper=*/nullptr,
@@ -2055,7 +2017,8 @@ void CallStackFrame::describe(raw_ostream &Out) const {
Out << '(';
for (FunctionDecl::param_const_iterator I = Callee->param_begin(),
- E = Callee->param_end(); I != E; ++I, ++ArgIndex) {
+ E = Callee->param_end();
+ I != E; ++I, ++ArgIndex) {
if (ArgIndex > (unsigned)IsMemberCall)
Out << ", ";
@@ -2109,7 +2072,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
if (!B)
return true;
- if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl *>()) {
// ... the address of an object with static storage duration,
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->hasGlobalStorage();
@@ -2124,7 +2087,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
if (B.is<TypeInfoLValue>() || B.is<DynamicAllocLValue>())
return true;
- const Expr *E = B.get<const Expr*>();
+ const Expr *E = B.get<const Expr *>();
switch (E->getStmtClass()) {
default:
return false;
@@ -2169,7 +2132,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
}
static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
- return LVal.Base.dyn_cast<const ValueDecl*>();
+ return LVal.Base.dyn_cast<const ValueDecl *>();
}
// Information about an LValueBase that is some kind of string.
@@ -2281,8 +2244,7 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
if (!B.getLValueBase())
return false;
- if (A.getLValueBase().getOpaqueValue() !=
- B.getLValueBase().getOpaqueValue())
+ if (A.getLValueBase().getOpaqueValue() != B.getLValueBase().getOpaqueValue())
return false;
return A.getLValueCallIndex() == B.getLValueCallIndex() &&
@@ -2291,7 +2253,7 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
assert(Base && "no location for a null lvalue");
- const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+ const ValueDecl *VD = Base.dyn_cast<const ValueDecl *>();
// For a parameter, find the corresponding call stack frame (if it still
// exists), and point at the parameter of the function definition we actually
@@ -2310,7 +2272,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
if (VD)
Info.Note(VD->getLocation(), diag::note_declared_at);
- else if (const Expr *E = Base.dyn_cast<const Expr*>())
+ else if (const Expr *E = Base.dyn_cast<const Expr *>())
Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here);
else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
// FIXME: Produce a note for dangling pointers too.
@@ -2352,7 +2314,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
const SubobjectDesignator &Designator = LVal.getLValueDesignator();
const Expr *BaseE = Base.dyn_cast<const Expr *>();
- const ValueDecl *BaseVD = Base.dyn_cast<const ValueDecl*>();
+ const ValueDecl *BaseVD = Base.dyn_cast<const ValueDecl *>();
// Additional restrictions apply in a template argument. We only enforce the
// C++20 restrictions here; additional syntactic and semantic restrictions
@@ -2513,7 +2475,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// Does this refer one past the end of some object?
if (!Designator.Invalid && Designator.isOnePastTheEnd()) {
Info.FFDiag(Loc, diag::note_constexpr_past_end, 1)
- << !Designator.Entries.empty() << !!BaseVD << BaseVD;
+ << !Designator.Entries.empty() << !!BaseVD << BaseVD;
NoteLValueLocation(Info, Base);
}
@@ -2569,8 +2531,7 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
// Prvalue constant expressions must be of literal types.
if (Info.getLangOpts().CPlusPlus11)
- Info.FFDiag(E, diag::note_constexpr_nonliteral)
- << E->getType();
+ Info.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
else
Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -2662,7 +2623,8 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
if (Value.isMemberPointer() &&
CERK == CheckEvaluationResultKind::ConstantExpression)
- return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Kind);
+ return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value,
+ Kind);
// Everything else is fine.
return true;
@@ -2720,7 +2682,7 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
// We have a non-null base. These are generally known to be true, but if it's
// a weak declaration it can be null at runtime.
Result = true;
- const ValueDecl *Decl = Value.getLValueBase().dyn_cast<const ValueDecl*>();
+ const ValueDecl *Decl = Value.getLValueBase().dyn_cast<const ValueDecl *>();
return !Decl || !Decl->isWeak();
}
@@ -2776,11 +2738,10 @@ static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result,
return HandleConversionToBool(Val, Result);
}
-template<typename T>
-static bool HandleOverflow(EvalInfo &Info, const Expr *E,
- const T &SrcValue, QualType DestType) {
- Info.CCEDiag(E, diag::note_constexpr_overflow)
- << SrcValue << DestType;
+template <typename T>
+static bool HandleOverflow(EvalInfo &Info, const Expr *E, const T &SrcValue,
+ QualType DestType) {
+ Info.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << DestType;
return Info.noteUndefinedBehavior();
}
@@ -2793,8 +2754,8 @@ static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E,
Result = APSInt(DestWidth, !DestSigned);
bool ignored;
- if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored)
- & APFloat::opInvalidOp)
+ if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored) &
+ APFloat::opInvalidOp)
return HandleOverflow(Info, E, Value, DestType);
return true;
}
@@ -2883,17 +2844,17 @@ static APSInt HandleIntToIntCast(EvalInfo &Info, const Expr *E,
}
static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
- const FPOptions FPO,
- QualType SrcType, const APSInt &Value,
- QualType DestType, APFloat &Result) {
+ const FPOptions FPO, QualType SrcType,
+ const APSInt &Value, QualType DestType,
+ APFloat &Result) {
Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(), RM);
return checkFloatingPointResult(Info, E, St);
}
-static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
- APValue &Value, const FieldDecl *FD) {
+static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E, APValue &Value,
+ const FieldDecl *FD) {
assert(FD->isBitField() && "truncateBitfieldValue on non-bitfield");
if (!Value.isInt()) {
@@ -2916,7 +2877,7 @@ static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
/// Perform the given integer operation, which is known to need at most BitWidth
/// bits, and check for overflow in the original type (if that type was not an
/// unsigned type).
-template<typename Operation>
+template <typename Operation>
static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
const APSInt &LHS, const APSInt &RHS,
unsigned BitWidth, Operation Op,
@@ -2958,9 +2919,15 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
case BO_Sub:
return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
std::minus<APSInt>(), Result);
- case BO_And: Result = LHS & RHS; return true;
- case BO_Xor: Result = LHS ^ RHS; return true;
- case BO_Or: Result = LHS | RHS; return true;
+ case BO_And:
+ Result = LHS & RHS;
+ return true;
+ case BO_Xor:
+ Result = LHS ^ RHS;
+ return true;
+ case BO_Or:
+ Result = LHS | RHS;
+ return true;
case BO_Div:
case BO_Rem:
if (RHS == 0) {
@@ -2980,7 +2947,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
if (Info.getLangOpts().OpenCL)
// OpenCL 6.3j: shift values are effectively % word size of LHS.
RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
- static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
RHS.isUnsigned());
else if (RHS.isSigned() && RHS.isNegative()) {
// During constant-folding, a negative shift is an opposite shift. Such
@@ -2994,10 +2961,10 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
shift_left:
// C++11 [expr.shift]p1: Shift width must be less than the bit width of
// the shifted type.
- unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ unsigned SA = (unsigned)RHS.getLimitedValue(LHS.getBitWidth() - 1);
if (SA != RHS) {
Info.CCEDiag(E, diag::note_constexpr_large_shift)
- << RHS << E->getType() << LHS.getBitWidth();
+ << RHS << E->getType() << LHS.getBitWidth();
if (!Info.noteUndefinedBehavior())
return false;
} else if (LHS.isSigned() && !Info.getLangOpts().CPlusPlus20) {
@@ -3022,7 +2989,7 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
if (Info.getLangOpts().OpenCL)
// OpenCL 6.3j: shift values are effectively % word size of LHS.
RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
- static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
RHS.isUnsigned());
else if (RHS.isSigned() && RHS.isNegative()) {
// During constant-folding, a negative shift is an opposite shift. Such a
@@ -3036,10 +3003,10 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
shift_right:
// C++11 [expr.shift]p1: Shift width must be less than the bit width of the
// shifted type.
- unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ unsigned SA = (unsigned)RHS.getLimitedValue(LHS.getBitWidth() - 1);
if (SA != RHS) {
Info.CCEDiag(E, diag::note_constexpr_large_shift)
- << RHS << E->getType() << LHS.getBitWidth();
+ << RHS << E->getType() << LHS.getBitWidth();
if (!Info.noteUndefinedBehavior())
return false;
}
@@ -3048,12 +3015,24 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
return true;
}
- case BO_LT: Result = LHS < RHS; return true;
- case BO_GT: Result = LHS > RHS; return true;
- case BO_LE: Result = LHS <= RHS; return true;
- case BO_GE: Result = LHS >= RHS; return true;
- case BO_EQ: Result = LHS == RHS; return true;
- case BO_NE: Result = LHS != RHS; return true;
+ case BO_LT:
+ Result = LHS < RHS;
+ return true;
+ case BO_GT:
+ Result = LHS > RHS;
+ return true;
+ case BO_LE:
+ Result = LHS <= RHS;
+ return true;
+ case BO_GE:
+ Result = LHS >= RHS;
+ return true;
+ case BO_EQ:
+ Result = LHS == RHS;
+ return true;
+ case BO_NE:
+ Result = LHS != RHS;
+ return true;
case BO_Cmp:
llvm_unreachable("BO_Cmp should be handled elsewhere");
}
@@ -3271,7 +3250,8 @@ static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
// Truncate the path to the subobject, and remove any derived-to-base offsets.
const RecordDecl *RD = TruncatedType;
for (unsigned I = TruncatedElements, N = D.Entries.size(); I != N; ++I) {
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
const CXXRecordDecl *Base = getAsBaseClass(D.Entries[I]);
if (isVirtualBaseClass(D.Entries[I]))
@@ -3289,7 +3269,8 @@ static bool HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj,
const CXXRecordDecl *Base,
const ASTRecordLayout *RL = nullptr) {
if (!RL) {
- if (Derived->isInvalidDecl()) return false;
+ if (Derived->isInvalidDecl())
+ return false;
RL = &Info.Ctx.getASTRecordLayout(Derived);
}
@@ -3316,7 +3297,8 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj,
return false;
// Find the virtual base class.
- if (DerivedDecl->isInvalidDecl()) return false;
+ if (DerivedDecl->isInvalidDecl())
+ return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true);
Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl);
@@ -3328,8 +3310,7 @@ static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E,
for (CastExpr::path_const_iterator PathI = E->path_begin(),
PathE = E->path_end();
PathI != PathE; ++PathI) {
- if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
- *PathI))
+ if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(), *PathI))
return false;
Type = (*PathI)->getType();
}
@@ -3357,7 +3338,8 @@ static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
const FieldDecl *FD,
const ASTRecordLayout *RL = nullptr) {
if (!RL) {
- if (FD->getParent()->isInvalidDecl()) return false;
+ if (FD->getParent()->isInvalidDecl())
+ return false;
RL = &Info.Ctx.getASTRecordLayout(FD->getParent());
}
@@ -3528,8 +3510,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
!Info.CurrentCall->Callee ||
!Info.CurrentCall->Callee->Equals(VD->getDeclContext())) {
if (Info.getLangOpts().CPlusPlus11) {
- Info.FFDiag(E, diag::note_constexpr_function_param_value_unknown)
- << VD;
+ Info.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << VD;
NoteLValueLocation(Info, Base);
} else {
Info.FFDiag(E);
@@ -3553,8 +3534,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// Don't diagnose during potential constant expression checking; an
// initializer might be added later.
if (!Info.checkingPotentialConstantExpression()) {
- Info.FFDiag(E, diag::note_constexpr_var_init_unknown, 1)
- << VD;
+ Info.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
NoteLValueLocation(Info, Base);
}
return false;
@@ -3572,9 +3552,11 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// have been value-dependent too), so diagnose that.
assert(!VD->mightBeUsableInConstantExpressions(Info.Ctx));
if (!Info.checkingPotentialConstantExpression()) {
- Info.FFDiag(E, Info.getLangOpts().CPlusPlus11
- ? diag::note_constexpr_ltor_non_constexpr
- : diag::note_constexpr_ltor_non_integral, 1)
+ Info.FFDiag(E,
+ Info.getLangOpts().CPlusPlus11
+ ? diag::note_constexpr_ltor_non_constexpr
+ : diag::note_constexpr_ltor_non_integral,
+ 1)
<< VD << VD->getType();
NoteLValueLocation(Info, Base);
}
@@ -3650,7 +3632,8 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
Base = Base->getCanonicalDecl();
unsigned Index = 0;
for (CXXRecordDecl::base_class_const_iterator I = Derived->bases_begin(),
- E = Derived->bases_end(); I != E; ++I, ++Index) {
+ E = Derived->bases_end();
+ I != E; ++I, ++Index) {
if (I->getType()->getAsCXXRecordDecl()->getCanonicalDecl() == Base)
return Index;
}
@@ -3675,8 +3658,7 @@ static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
if (auto PE = dyn_cast<PredefinedExpr>(Lit))
Lit = PE->getFunctionName();
const StringLiteral *S = cast<StringLiteral>(Lit);
- const ConstantArrayType *CAT =
- Info.Ctx.getAsConstantArrayType(S->getType());
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(S->getType());
assert(CAT && "string literal isn't an array");
QualType CharType = CAT->getElementType();
assert(CharType->isIntegerType() && "unexpected character type");
@@ -3701,8 +3683,8 @@ static void expandStringLiteral(EvalInfo &Info, const StringLiteral *S,
assert(CharType->isIntegerType() && "unexpected character type");
unsigned Elts = CAT->getZExtSize();
- Result = APValue(APValue::UninitArray(),
- std::min(S->getLength(), Elts), Elts);
+ Result =
+ APValue(APValue::UninitArray(), std::min(S->getLength(), Elts), Elts);
APSInt Value(Info.Ctx.getTypeSize(CharType),
CharType->isUnsignedIntegerType());
if (Result.hasArrayFiller())
@@ -3720,7 +3702,7 @@ static void expandArray(APValue &Array, unsigned Index) {
// Always at least double the number of elements for which we store a value.
unsigned OldElts = Array.getArrayInitializedElts();
- unsigned NewElts = std::max(Index+1, OldElts * 2);
+ unsigned NewElts = std::max(Index + 1, OldElts * 2);
NewElts = std::min(Size, std::max(NewElts, 8u));
// Copy the data across.
@@ -3876,7 +3858,7 @@ struct CompleteObject {
if (!Info.getLangOpts().CPlusPlus14 &&
AK != AccessKinds::AK_IsWithinLifetime)
return false;
- return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/true);
+ return lifetimeStartedInEvaluation(Info, Base, /*MutableSubobject*/ true);
}
explicit operator bool() const { return !Type.isNull(); }
@@ -3928,7 +3910,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// Walk the designator's path to find the subobject.
for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
- // Reading an indeterminate value is undefined, but assigning over one is OK.
+ // Reading an indeterminate value is undefined, but assigning over one is
+ // OK.
if ((O->isAbsent() && !(handler.AccessKind == AK_Construct && I == N)) ||
(O->isIndeterminate() &&
!isValidIndeterminateAccess(handler.AccessKind))) {
@@ -3971,7 +3954,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
DiagKind = 2;
Loc = VolatileField->getLocation();
Decl = VolatileField;
- } else if (auto *VD = Obj.Base.dyn_cast<const ValueDecl*>()) {
+ } else if (auto *VD = Obj.Base.dyn_cast<const ValueDecl *>()) {
DiagKind = 1;
Loc = VD->getLocation();
Decl = VD;
@@ -4004,8 +3987,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
return false;
// If we modified a bit-field, truncate it to the right width.
- if (isModification(handler.AccessKind) &&
- LastField && LastField->isBitField() &&
+ if (isModification(handler.AccessKind) && LastField &&
+ LastField->isBitField() &&
!truncateBitfieldValue(Info, E, *O, LastField))
return false;
@@ -4023,7 +4006,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
// designator which points more than one past the end of the array.
if (Info.getLangOpts().CPlusPlus11)
Info.FFDiag(E, diag::note_constexpr_access_past_end)
- << handler.AccessKind;
+ << handler.AccessKind;
else
Info.FFDiag(E);
return handler.failed();
@@ -4047,7 +4030,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (Index > 1) {
if (Info.getLangOpts().CPlusPlus11)
Info.FFDiag(E, diag::note_constexpr_access_past_end)
- << handler.AccessKind;
+ << handler.AccessKind;
else
Info.FFDiag(E);
return handler.failed();
@@ -4058,12 +4041,13 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
assert(I == N - 1 && "extracting subobject of scalar?");
if (O->isComplexInt()) {
- return handler.found(Index ? O->getComplexIntImag()
- : O->getComplexIntReal(), ObjType);
+ return handler.found(
+ Index ? O->getComplexIntImag() : O->getComplexIntReal(), ObjType);
} else {
assert(O->isComplexFloat());
return handler.found(Index ? O->getComplexFloatImag()
- : O->getComplexFloatReal(), ObjType);
+ : O->getComplexFloatReal(),
+ ObjType);
}
} else if (const auto *VT = ObjType->getAs<VectorType>()) {
uint64_t Index = Sub.Entries[I].getAsArrayIndex();
@@ -4090,7 +4074,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (Field->isMutable() &&
!Obj.mayAccessMutableMembers(Info, handler.AccessKind)) {
Info.FFDiag(E, diag::note_constexpr_access_mutable, 1)
- << handler.AccessKind << Field;
+ << handler.AccessKind << Field;
Info.Note(Field->getLocation(), diag::note_declared_at);
return handler.failed();
}
@@ -4223,9 +4207,8 @@ const AccessKinds ModifySubobjectHandler::AccessKind;
/// Update the designated sub-object of an rvalue to the given value.
static bool modifySubobject(EvalInfo &Info, const Expr *E,
const CompleteObject &Obj,
- const SubobjectDesignator &Sub,
- APValue &NewVal) {
- ModifySubobjectHandler Handler = { Info, NewVal, E };
+ const SubobjectDesignator &Sub, APValue &NewVal) {
+ ModifySubobjectHandler Handler = {Info, NewVal, E};
return findSubobject(Info, E, Obj, Sub, Handler);
}
@@ -4308,7 +4291,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
Info.getCallFrameAndDepth(LVal.getLValueCallIndex());
if (!Frame) {
Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1)
- << AK << LVal.Base.is<const ValueDecl*>();
+ << AK << LVal.Base.is<const ValueDecl *>();
NoteLValueLocation(Info, LVal.Base);
return CompleteObject();
}
@@ -4323,7 +4306,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (isFormalAccess(AK) && LValType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus)
Info.FFDiag(E, diag::note_constexpr_access_volatile_type)
- << AK << LValType;
+ << AK << LValType;
else
Info.FFDiag(E);
return CompleteObject();
@@ -4441,9 +4424,11 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
// folding of const floating-point types, in order to make static const
// data members of such types (supported as an extension) more useful.
if (Info.getLangOpts().CPlusPlus) {
- Info.CCEDiag(E, Info.getLangOpts().CPlusPlus11
- ? diag::note_constexpr_ltor_non_constexpr
- : diag::note_constexpr_ltor_non_integral, 1)
+ Info.CCEDiag(E,
+ Info.getLangOpts().CPlusPlus11
+ ? diag::note_constexpr_ltor_non_constexpr
+ : diag::note_constexpr_ltor_non_integral,
+ 1)
<< VD << BaseType;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -4452,9 +4437,11 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
} else {
// Never allow reading a non-const value.
if (Info.getLangOpts().CPlusPlus) {
- Info.FFDiag(E, Info.getLangOpts().CPlusPlus11
- ? diag::note_constexpr_ltor_non_constexpr
- : diag::note_constexpr_ltor_non_integral, 1)
+ Info.FFDiag(E,
+ Info.getLangOpts().CPlusPlus11
+ ? diag::note_constexpr_ltor_non_constexpr
+ : diag::note_constexpr_ltor_non_integral,
+ 1)
<< VD << BaseType;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -4464,7 +4451,8 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
}
- if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
+ if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(),
+ BaseVal))
return CompleteObject();
} else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
@@ -4475,7 +4463,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
return CompleteObject(LVal.Base, &(*Alloc)->Value,
LVal.Base.getDynamicAllocType());
} else {
- const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
+ const Expr *Base = LVal.Base.dyn_cast<const Expr *>();
if (!Frame) {
if (const MaterializeTemporaryExpr *MTE =
@@ -4578,7 +4566,7 @@ handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, QualType Type,
return false;
// Check for special cases where there is no existing APValue to look at.
- const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
+ const Expr *Base = LVal.Base.dyn_cast<const Expr *>();
AccessKinds AK =
WantObjectRepresentation ? AK_ReadObjectRepresentation : AK_Read;
@@ -4744,8 +4732,7 @@ struct CompoundAssignSubobjectHandler {
Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS);
return true;
} else if (RHS.isFloat()) {
- const FPOptions FPO = E->getFPFeaturesInEffect(
- Info.Ctx.getLangOpts());
+ const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
APFloat FValue(0.0);
return HandleIntToFloatCast(Info, E, FPO, SubobjType, Value,
PromotedLHSType, FValue) &&
@@ -4810,8 +4797,8 @@ static bool handleCompoundAssignment(EvalInfo &Info,
}
CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType);
- CompoundAssignSubobjectHandler Handler = { Info, E, PromotedLValType, Opcode,
- RVal };
+ CompoundAssignSubobjectHandler Handler = {Info, E, PromotedLValType, Opcode,
+ RVal};
return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler);
}
@@ -4848,13 +4835,15 @@ struct IncDecSubobjectHandler {
case APValue::Float:
return found(Subobj.getFloat(), SubobjType);
case APValue::ComplexInt:
- return found(Subobj.getComplexIntReal(),
- SubobjType->castAs<ComplexType>()->getElementType()
- .withCVRQualifiers(SubobjType.getCVRQualifiers()));
+ return found(
+ Subobj.getComplexIntReal(),
+ SubobjType->castAs<ComplexType>()->getElementType().withCVRQualifiers(
+ SubobjType.getCVRQualifiers()));
case APValue::ComplexFloat:
- return found(Subobj.getComplexFloatReal(),
- SubobjType->castAs<ComplexType>()->getElementType()
- .withCVRQualifiers(SubobjType.getCVRQualifiers()));
+ return found(
+ Subobj.getComplexFloatReal(),
+ SubobjType->castAs<ComplexType>()->getElementType().withCVRQualifiers(
+ SubobjType.getCVRQualifiers()));
case APValue::LValue:
return foundPointer(Subobj, SubobjType);
default:
@@ -4874,7 +4863,8 @@ struct IncDecSubobjectHandler {
return false;
}
- if (Old) *Old = APValue(Value);
+ if (Old)
+ *Old = APValue(Value);
// bool arithmetic promotes to int, and the conversion back to bool
// doesn't reduce mod 2^n, so special-case it.
@@ -4891,7 +4881,7 @@ struct IncDecSubobjectHandler {
++Value;
if (!WasNegative && Value.isNegative() && E->canOverflow()) {
- APSInt ActualValue(Value, /*IsUnsigned*/true);
+ APSInt ActualValue(Value, /*IsUnsigned*/ true);
return HandleOverflow(Info, E, ActualValue, SubobjType);
}
} else {
@@ -4899,7 +4889,7 @@ struct IncDecSubobjectHandler {
if (WasNegative && !Value.isNegative() && E->canOverflow()) {
unsigned BitWidth = Value.getBitWidth();
- APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false);
+ APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/ false);
ActualValue.setBit(BitWidth);
return HandleOverflow(Info, E, ActualValue, SubobjType);
}
@@ -4910,7 +4900,8 @@ struct IncDecSubobjectHandler {
if (!checkConst(SubobjType))
return false;
- if (Old) *Old = APValue(Value);
+ if (Old)
+ *Old = APValue(Value);
APFloat One(Value.getSemantics(), 1);
llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
@@ -4992,8 +4983,7 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
/// \return The field or method declaration to which the member pointer refers,
/// or 0 if evaluation fails.
static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
- QualType LVType,
- LValue &LV,
+ QualType LVType, LValue &LV,
const Expr *RHS,
bool IncludeMember = true) {
MemberPtr MemPtr;
@@ -5020,8 +5010,8 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
unsigned PathLengthToMember =
LV.Designator.Entries.size() - MemPtr.Path.size();
for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) {
- const CXXRecordDecl *LVDecl = getAsBaseClass(
- LV.Designator.Entries[PathLengthToMember + I]);
+ const CXXRecordDecl *LVDecl =
+ getAsBaseClass(LV.Designator.Entries[PathLengthToMember + I]);
const CXXRecordDecl *MPDecl = MemPtr.Path[I];
if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) {
Info.FFDiag(RHS);
@@ -5062,7 +5052,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
if (!HandleLValueMember(Info, RHS, LV, FD))
return nullptr;
} else if (const IndirectFieldDecl *IFD =
- dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) {
+ dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) {
if (!HandleLValueIndirectMember(Info, RHS, LV, IFD))
return nullptr;
} else {
@@ -5106,7 +5096,7 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
// 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;
+ << D.MostDerivedType << TargetQT;
return false;
}
@@ -5121,7 +5111,7 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]);
if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) {
Info.CCEDiag(E, diag::note_constexpr_invalid_downcast)
- << D.MostDerivedType << TargetQT;
+ << D.MostDerivedType << TargetQT;
return false;
}
@@ -5303,12 +5293,10 @@ struct TempVersionRAII {
Frame.pushTempVersion();
}
- ~TempVersionRAII() {
- Frame.popTempVersion();
- }
+ ~TempVersionRAII() { Frame.popTempVersion(); }
};
-}
+} // namespace
static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
const Stmt *S,
@@ -5386,8 +5374,8 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
const CaseStmt *CS = cast<CaseStmt>(SC);
APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
- APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
- : LHS;
+ APSInt RHS =
+ CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx) : LHS;
if (LHS <= Value && Value <= RHS) {
Found = SC;
break;
@@ -5521,8 +5509,7 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
}
}
- EvalStmtResult ESR =
- EvaluateLoopBody(Result, Info, FS->getBody(), Case);
+ EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody(), Case);
if (ESR != ESR_Continue)
return ESR;
if (const auto *Inc = FS->getInc()) {
@@ -5611,10 +5598,9 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// We know we returned, but we don't know what the value is.
return ESR_Failed;
}
- if (RetExpr &&
- !(Result.Slot
- ? EvaluateInPlace(Result.Value, Info, *Result.Slot, RetExpr)
- : Evaluate(Result.Value, Info, RetExpr)))
+ if (RetExpr && !(Result.Slot ? EvaluateInPlace(Result.Value, Info,
+ *Result.Slot, RetExpr)
+ : Evaluate(Result.Value, Info, RetExpr)))
return ESR_Failed;
return Scope.destroy() ? ESR_Returned : ESR_Failed;
}
@@ -5925,7 +5911,7 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
// FIXME: If DiagDecl is an implicitly-declared special member function,
// we should be much more explicit about why it's not constexpr.
Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
- << /*IsConstexpr*/0 << /*IsConstructor*/1 << CD;
+ << /*IsConstexpr*/ 0 << /*IsConstructor*/ 1 << CD;
Info.Note(CD->getLocation(), diag::note_declared_at);
} else {
Info.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
@@ -5969,7 +5955,7 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
// Can we evaluate this function call?
if (Definition && Body &&
(Definition->isConstexpr() || (Info.CurrentCall->CanEvalMSConstexpr &&
- Definition->hasAttr<MSConstexprAttr>())))
+ Definition->hasAttr<MSConstexprAttr>())))
return true;
if (Info.getLangOpts().CPlusPlus11) {
@@ -5989,10 +5975,10 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
// it's not constexpr.
if (CD && CD->isInheritingConstructor())
Info.FFDiag(CallLoc, diag::note_constexpr_invalid_inhctor, 1)
- << CD->getInheritedConstructor().getConstructor()->getParent();
+ << CD->getInheritedConstructor().getConstructor()->getParent();
else
Info.FFDiag(CallLoc, diag::note_constexpr_invalid_function, 1)
- << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
+ << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
Info.Note(DiagDecl->getLocation(), diag::note_declared_at);
} else {
Info.FFDiag(CallLoc, diag::note_invalid_subexpr_in_const_expr);
@@ -6081,8 +6067,8 @@ struct DynamicType {
static const CXXRecordDecl *getBaseClassType(SubobjectDesignator &Designator,
unsigned PathLength) {
- assert(PathLength >= Designator.MostDerivedPathLength && PathLength <=
- Designator.Entries.size() && "invalid path length");
+ assert(PathLength >= Designator.MostDerivedPathLength &&
+ PathLength <= Designator.Entries.size() && "invalid path length");
return (PathLength == Designator.MostDerivedPathLength)
? Designator.MostDerivedType->getAsCXXRecordDecl()
: getAsBaseClass(Designator.Entries[PathLength - 1]);
@@ -6288,7 +6274,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
assert(C && "dynamic_cast target is not void pointer nor class");
CanQualType CQT = Info.Ctx.getCanonicalType(Info.Ctx.getRecordType(C));
- auto RuntimeCheckFailed = [&] (CXXBasePaths *Paths) {
+ auto RuntimeCheckFailed = [&](CXXBasePaths *Paths) {
// C++ [expr.dynamic.cast]p9:
if (!E->isGLValue()) {
// The value of a failed cast to pointer type is the null pointer value
@@ -6412,7 +6398,7 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
if (LHS.InvalidBase || LHS.Designator.Invalid)
return false;
- llvm::SmallVector<std::pair<unsigned, const FieldDecl*>, 4> UnionPathLengths;
+ llvm::SmallVector<std::pair<unsigned, const FieldDecl *>, 4> UnionPathLengths;
// C++ [class.union]p5:
// define the set S(E) of subexpressions of E as follows:
unsigned PathLength = LHS.Designator.Entries.size();
@@ -6438,9 +6424,9 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
E = ME->getBase();
--PathLength;
- assert(declaresSameEntity(FD,
- LHS.Designator.Entries[PathLength]
- .getAsBaseOrMember().getPointer()));
+ assert(declaresSameEntity(
+ FD,
+ LHS.Designator.Entries[PathLength].getAsBaseOrMember().getPointer()));
// -- If E is of the form A[B] and is interpreted as a built-in array
// subscripting operator, S(E) is [S(the array operand, if any)].
@@ -6473,10 +6459,11 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
--PathLength;
assert(declaresSameEntity(Elt->getType()->getAsCXXRecordDecl(),
LHS.Designator.Entries[PathLength]
- .getAsBaseOrMember().getPointer()));
+ .getAsBaseOrMember()
+ .getPointer()));
}
- // -- Otherwise, S(E) is empty.
+ // -- Otherwise, S(E) is empty.
} else {
break;
}
@@ -6493,7 +6480,7 @@ static bool MaybeHandleUnionActiveMemberChange(EvalInfo &Info,
if (!Obj)
return false;
for (std::pair<unsigned, const FieldDecl *> LengthAndField :
- llvm::reverse(UnionPathLengths)) {
+ llvm::reverse(UnionPathLengths)) {
// Form a designator for the union object.
SubobjectDesignator D = LHS.Designator;
D.truncate(Info.Ctx, LHS.Base, LengthAndField.first);
@@ -6620,8 +6607,7 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
if (!handleTrivialCopy(Info, MD->getParamDecl(0), Args[0], RHSValue,
MD->getParent()->isUnion()))
return false;
- if (!handleAssignment(Info, Args[0], *This, MD->getThisType(),
- RHSValue))
+ if (!handleAssignment(Info, Args[0], *This, MD->getThisType(), RHSValue))
return false;
This->moveInto(Result);
return true;
@@ -6711,10 +6697,11 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
std::distance(RD->field_begin(), RD->field_end()));
else
// A union starts with no active member.
- Result = APValue((const FieldDecl*)nullptr);
+ Result = APValue((const FieldDecl *)nullptr);
}
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
// A scope for temporaries lifetime-extended by reference members.
@@ -6863,7 +6850,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
}
static bool HandleConstructorCall(const Expr *E, const LValue &This,
- ArrayRef<const Expr*> Args,
+ ArrayRef<const Expr *> Args,
const CXXConstructorDecl *Definition,
EvalInfo &Info, APValue &Result) {
CallScopeRAII CallScope(Info);
@@ -7010,7 +6997,7 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange,
// 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->fields());
+ SmallVector<FieldDecl *, 16> Fields(RD->fields());
for (const FieldDecl *FD : llvm::reverse(Fields)) {
if (FD->isUnnamedBitField())
continue;
@@ -7072,12 +7059,12 @@ struct DestroyObjectHandler {
return false;
}
};
-}
+} // namespace
/// Perform a destructor or pseudo-destructor call on the given object, which
/// might in general not be a complete object.
-static bool HandleDestruction(EvalInfo &Info, const Expr *E,
- const LValue &This, QualType ThisType) {
+static bool HandleDestruction(EvalInfo &Info, const Expr *E, const LValue &This,
+ QualType ThisType) {
CompleteObject Obj = findCompleteObject(Info, E, AK_Destroy, This, ThisType);
DestroyObjectHandler Handler = {Info, E, This, AK_Destroy};
return Obj && findSubobject(Info, E, Obj, This.Designator, Handler);
@@ -7281,8 +7268,8 @@ class BitCastBuffer {
public:
BitCastBuffer(CharUnits Width, bool TargetIsLittleEndian)
- : Bytes(Width.getQuantity()),
- TargetIsLittleEndian(TargetIsLittleEndian) {}
+ : Bytes(Width.getQuantity()), TargetIsLittleEndian(TargetIsLittleEndian) {
+ }
[[nodiscard]] bool readObject(CharUnits Offset, CharUnits Width,
SmallVectorImpl<unsigned char> &Output) const {
@@ -7601,8 +7588,7 @@ class BufferToAPValueConverter {
T->isSpecificBuiltinType(BuiltinType::Char_U));
if (!IsStdByte && !IsUChar) {
QualType DisplayType(EnumSugar ? (const Type *)EnumSugar : T, 0);
- Info.FFDiag(BCE->getExprLoc(),
- diag::note_constexpr_bit_cast_indet_dest)
+ Info.FFDiag(BCE->getExprLoc(), diag::note_constexpr_bit_cast_indet_dest)
<< DisplayType << Info.Ctx.getLangOpts().CharIsSigned;
return std::nullopt;
}
@@ -7953,10 +7939,9 @@ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
}
template <class Derived>
-class ExprEvaluatorBase
- : public ConstStmtVisitor<Derived, bool> {
+class ExprEvaluatorBase : public ConstStmtVisitor<Derived, bool> {
private:
- Derived &getDerived() { return static_cast<Derived&>(*this); }
+ Derived &getDerived() { return static_cast<Derived &>(*this); }
bool DerivedSuccess(const APValue &V, const Expr *E) {
return getDerived().Success(V, E);
}
@@ -7967,7 +7952,7 @@ class ExprEvaluatorBase
// Check whether a conditional operator with a non-constant condition is a
// potential constant expression. If neither arm is a potential constant
// expression, then the conditional operator is not either.
- template<typename ConditionalOperator>
+ template <typename ConditionalOperator>
void CheckPotentialConstantConditional(const ConditionalOperator *E) {
assert(Info.checkingPotentialConstantExpression());
@@ -7991,8 +7976,7 @@ class ExprEvaluatorBase
Error(E, diag::note_constexpr_conditional_never_const);
}
-
- template<typename ConditionalOperator>
+ template <typename ConditionalOperator>
bool HandleConditionalOperator(const ConditionalOperator *E) {
bool BoolResult;
if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) {
@@ -8046,9 +8030,7 @@ class ExprEvaluatorBase
bool VisitStmt(const Stmt *) {
llvm_unreachable("Expression evaluator should not be called on stmts");
}
- bool VisitExpr(const Expr *E) {
- return Error(E);
- }
+ bool VisitExpr(const Expr *E) { return Error(E); }
bool VisitEmbedExpr(const EmbedExpr *E) {
const auto It = E->begin();
@@ -8065,18 +8047,25 @@ class ExprEvaluatorBase
return StmtVisitorTy::Visit(E->getSubExpr());
}
- bool VisitParenExpr(const ParenExpr *E)
- { return StmtVisitorTy::Visit(E->getSubExpr()); }
- bool VisitUnaryExtension(const UnaryOperator *E)
- { return StmtVisitorTy::Visit(E->getSubExpr()); }
- bool VisitUnaryPlus(const UnaryOperator *E)
- { return StmtVisitorTy::Visit(E->getSubExpr()); }
- bool VisitChooseExpr(const ChooseExpr *E)
- { return StmtVisitorTy::Visit(E->getChosenSubExpr()); }
- bool VisitGenericSelectionExpr(const GenericSelectionExpr *E)
- { return StmtVisitorTy::Visit(E->getResultExpr()); }
- bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
- { return StmtVisitorTy::Visit(E->getReplacement()); }
+ bool VisitParenExpr(const ParenExpr *E) {
+ return StmtVisitorTy::Visit(E->getSubExpr());
+ }
+ bool VisitUnaryExtension(const UnaryOperator *E) {
+ return StmtVisitorTy::Visit(E->getSubExpr());
+ }
+ bool VisitUnaryPlus(const UnaryOperator *E) {
+ return StmtVisitorTy::Visit(E->getSubExpr());
+ }
+ bool VisitChooseExpr(const ChooseExpr *E) {
+ return StmtVisitorTy::Visit(E->getChosenSubExpr());
+ }
+ bool VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
+ return StmtVisitorTy::Visit(E->getResultExpr());
+ }
+ bool
+ VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E) {
+ return StmtVisitorTy::Visit(E->getReplacement());
+ }
bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
TempVersionRAII RAII(*Info.CurrentCall);
SourceLocExprScopeGuard Guard(E, Info.CurrentCall->CurSourceLocExprScope);
@@ -8103,16 +8092,17 @@ class ExprEvaluatorBase
}
bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E) {
- CCEDiag(E, diag::note_constexpr_invalid_cast) << diag::CastKind::Reinterpret;
- return static_cast<Derived*>(this)->VisitCastExpr(E);
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << diag::CastKind::Reinterpret;
+ return static_cast<Derived *>(this)->VisitCastExpr(E);
}
bool VisitCXXDynamicCastExpr(const CXXDynamicCastExpr *E) {
if (!Info.Ctx.getLangOpts().CPlusPlus20)
CCEDiag(E, diag::note_constexpr_invalid_cast) << diag::CastKind::Dynamic;
- return static_cast<Derived*>(this)->VisitCastExpr(E);
+ return static_cast<Derived *>(this)->VisitCastExpr(E);
}
bool VisitBuiltinBitCastExpr(const BuiltinBitCastExpr *E) {
- return static_cast<Derived*>(this)->VisitCastExpr(E);
+ return static_cast<Derived *>(this)->VisitCastExpr(E);
}
bool VisitBinaryOperator(const BinaryOperator *E) {
@@ -8162,7 +8152,7 @@ class ExprEvaluatorBase
// side-effects. This is an important GNU extension. See GCC PR38377
// for discussion.
if (const CallExpr *CallCE =
- dyn_cast<CallExpr>(E->getCond()->IgnoreParenCasts()))
+ dyn_cast<CallExpr>(E->getCond()->IgnoreParenCasts()))
if (CallCE->getBuiltinCallee() == Builtin::BI__builtin_constant_p)
IsBcpCall = true;
@@ -8236,7 +8226,7 @@ class ExprEvaluatorBase
}
bool handleCallExpr(const CallExpr *E, APValue &Result,
- const LValue *ResultSlot) {
+ const LValue *ResultSlot) {
CallScopeRAII CallScope(Info);
const Expr *Callee = E->getCallee()->IgnoreParens();
@@ -8298,7 +8288,7 @@ class ExprEvaluatorBase
// Don't call function pointers which have been cast to some other type.
// Per DR (no number yet), the caller and callee can differ in noexcept.
if (!Info.Ctx.hasSameFunctionTypeIgnoringExceptionSpec(
- CalleeType->getPointeeType(), FD->getType())) {
+ CalleeType->getPointeeType(), FD->getType())) {
return Error(E);
}
@@ -8475,10 +8465,12 @@ class ExprEvaluatorBase
QualType BaseTy = E->getBase()->getType();
const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
- if (!FD) return Error(E);
+ if (!FD)
+ return Error(E);
assert(!FD->getType()->isReferenceType() && "prvalue reference?");
assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() ==
- FD->getParent()->getCanonicalDecl() && "record / field mismatch");
+ 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
@@ -8612,7 +8604,7 @@ class ExprEvaluatorBase
}
APValue ReturnValue;
- StmtResult Result = { ReturnValue, nullptr };
+ StmtResult Result = {ReturnValue, nullptr};
EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);
if (ESR != ESR_Succeeded) {
// FIXME: If the statement-expression terminated due to 'return',
@@ -8633,9 +8625,7 @@ class ExprEvaluatorBase
}
/// Visit a value which is evaluated, but whose value is ignored.
- void VisitIgnoredValue(const Expr *E) {
- EvaluateIgnoredValue(Info, E);
- }
+ void VisitIgnoredValue(const Expr *E) { EvaluateIgnoredValue(Info, E); }
/// Potentially visit a MemberExpr's base expression.
void VisitIgnoredBaseExpression(const Expr *E) {
@@ -8653,9 +8643,8 @@ class ExprEvaluatorBase
// Common base class for lvalue and temporary evaluation.
//===----------------------------------------------------------------------===//
namespace {
-template<class Derived>
-class LValueExprEvaluatorBase
- : public ExprEvaluatorBase<Derived> {
+template <class Derived>
+class LValueExprEvaluatorBase : public ExprEvaluatorBase<Derived> {
protected:
LValue &Result;
bool InvalidBaseOK;
@@ -8706,7 +8695,8 @@ class LValueExprEvaluatorBase
const ValueDecl *MD = E->getMemberDecl();
if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() ==
- FD->getParent()->getCanonicalDecl() && "record / field mismatch");
+ FD->getParent()->getCanonicalDecl() &&
+ "record / field mismatch");
(void)BaseTy;
if (!HandleLValueMember(this->Info, E, Result, FD))
return false;
@@ -8754,7 +8744,7 @@ class LValueExprEvaluatorBase
}
}
};
-}
+} // namespace
//===----------------------------------------------------------------------===//
// LValue Evaluation
@@ -8791,10 +8781,10 @@ class LValueExprEvaluatorBase
//===----------------------------------------------------------------------===//
namespace {
class LValueExprEvaluator
- : public LValueExprEvaluatorBase<LValueExprEvaluator> {
+ : public LValueExprEvaluatorBase<LValueExprEvaluator> {
public:
- LValueExprEvaluator(EvalInfo &Info, LValue &Result, bool InvalidBaseOK) :
- LValueExprEvaluatorBaseTy(Info, Result, InvalidBaseOK) {}
+ LValueExprEvaluator(EvalInfo &Info, LValue &Result, bool InvalidBaseOK)
+ : LValueExprEvaluatorBaseTy(Info, Result, InvalidBaseOK) {}
bool VisitVarDecl(const Expr *E, const VarDecl *VD);
bool VisitUnaryPreIncDec(const UnaryOperator *UO);
@@ -8833,7 +8823,8 @@ class LValueExprEvaluator
case CK_LValueBitCast:
this->CCEDiag(E, diag::note_constexpr_invalid_cast)
- << diag::CastKind::ThisCastOrReinterpret << Info.Ctx.getLangOpts().CPlusPlus;
+ << diag::CastKind::ThisCastOrReinterpret
+ << Info.Ctx.getLangOpts().CPlusPlus;
if (!Visit(E->getSubExpr()))
return false;
Result.Designator.setInvalid();
@@ -8910,7 +8901,8 @@ static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
bool InvalidBaseOK) {
assert(!E->isValueDependent());
assert(E->isGLValue() || E->getType()->isFunctionType() ||
- E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E->IgnoreParens()));
+ E->getType()->isVoidType() ||
+ isa<ObjCSelectorExpr>(E->IgnoreParens()));
return LValueExprEvaluator(Info, Result, InvalidBaseOK).Visit(E);
}
@@ -8926,7 +8918,6 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
return Error(E);
}
-
bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
// C++23 [expr.const]p8 If we have a reference type allow unknown references
// and pointers.
@@ -9111,8 +9102,8 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
return true;
}
-bool
-LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
+bool LValueExprEvaluator::VisitCompoundLiteralExpr(
+ const CompoundLiteralExpr *E) {
assert((!Info.getLangOpts().CPlusPlus || E->isFileScope()) &&
"lvalue compound literal in c++?");
// Defer visiting the literal until the lvalue-to-rvalue conversion. We can
@@ -9131,8 +9122,8 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
} else {
if (!Info.Ctx.getLangOpts().CPlusPlus20) {
Info.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
- << E->getExprOperand()->getType()
- << E->getExprOperand()->getSourceRange();
+ << E->getExprOperand()->getType()
+ << E->getExprOperand()->getSourceRange();
}
if (!Visit(E->getExprOperand()))
@@ -9274,9 +9265,8 @@ bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) {
if (!this->Visit(UO->getSubExpr()))
return false;
- return handleIncDec(
- this->Info, UO, Result, UO->getSubExpr()->getType(),
- UO->isIncrementOp(), nullptr);
+ return handleIncDec(this->Info, UO, Result, UO->getSubExpr()->getType(),
+ UO->isIncrementOp(), nullptr);
}
bool LValueExprEvaluator::VisitCompoundAssignOperator(
@@ -9299,8 +9289,8 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator(
return false;
return handleCompoundAssignment(
- this->Info, CAO,
- Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(),
+ this->Info, CAO, Result, CAO->getLHS()->getType(),
+ CAO->getComputationLHSType(),
CAO->getOpForCompoundAssignment(CAO->getOpcode()), RHS);
}
@@ -9433,8 +9423,7 @@ static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base,
}
namespace {
-class PointerExprEvaluator
- : public ExprEvaluatorBase<PointerExprEvaluator> {
+class PointerExprEvaluator : public ExprEvaluatorBase<PointerExprEvaluator> {
LValue &Result;
bool InvalidBaseOK;
@@ -9452,8 +9441,8 @@ class PointerExprEvaluator
}
bool visitNonBuiltinCallExpr(const CallExpr *E);
-public:
+public:
PointerExprEvaluator(EvalInfo &info, LValue &Result, bool InvalidBaseOK)
: ExprEvaluatorBaseTy(info), Result(Result),
InvalidBaseOK(InvalidBaseOK) {}
@@ -9468,10 +9457,9 @@ class PointerExprEvaluator
}
bool VisitBinaryOperator(const BinaryOperator *E);
- bool VisitCastExpr(const CastExpr* E);
+ bool VisitCastExpr(const CastExpr *E);
bool VisitUnaryAddrOf(const UnaryOperator *E);
- bool VisitObjCStringLiteral(const ObjCStringLiteral *E)
- { return Success(E); }
+ bool VisitObjCStringLiteral(const ObjCStringLiteral *E) { return Success(E); }
bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
if (E->isExpressibleAsConstantInitializer())
return Success(E);
@@ -9479,8 +9467,7 @@ class PointerExprEvaluator
EvaluateIgnoredValue(Info, E->getSubExpr());
return Error(E);
}
- bool VisitAddrLabelExpr(const AddrLabelExpr *E)
- { return Success(E); }
+ bool VisitAddrLabelExpr(const AddrLabelExpr *E) { return Success(E); }
bool VisitCallExpr(const CallExpr *E);
bool VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinOp);
bool VisitBlockExpr(const BlockExpr *E) {
@@ -9570,7 +9557,7 @@ class PointerExprEvaluator
};
} // end anonymous namespace
-static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info,
+static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info,
bool InvalidBaseOK) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->hasPointerRepresentation());
@@ -9578,8 +9565,7 @@ static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info,
}
bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
- if (E->getOpcode() != BO_Add &&
- E->getOpcode() != BO_Sub)
+ if (E->getOpcode() != BO_Add && E->getOpcode() != BO_Sub)
return ExprEvaluatorBaseTy::VisitBinaryOperator(E);
const Expr *PExp = E->getLHS();
@@ -9673,7 +9659,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
<< diag::CastKind::CastFrom << SubExpr->getType();
} else
CCEDiag(E, diag::note_constexpr_invalid_cast)
- << diag::CastKind::ThisCastOrReinterpret << Info.Ctx.getLangOpts().CPlusPlus;
+ << diag::CastKind::ThisCastOrReinterpret
+ << Info.Ctx.getLangOpts().CPlusPlus;
Result.Designator.setInvalid();
}
}
@@ -9690,9 +9677,10 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
- return HandleLValueBasePath(Info, E, E->getSubExpr()->getType()->
- castAs<PointerType>()->getPointeeType(),
- Result);
+ return HandleLValueBasePath(
+ Info, E,
+ E->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType(),
+ Result);
case CK_BaseToDerived:
if (!Visit(E->getSubExpr()))
@@ -9712,7 +9700,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralToPointer: {
CCEDiag(E, diag::note_constexpr_invalid_cast)
- << diag::CastKind::ThisCastOrReinterpret << Info.Ctx.getLangOpts().CPlusPlus;
+ << diag::CastKind::ThisCastOrReinterpret
+ << Info.Ctx.getLangOpts().CPlusPlus;
APValue Value;
if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
@@ -9721,7 +9710,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (Value.isInt()) {
unsigned Size = Info.Ctx.getTypeSize(E->getType());
uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();
- Result.Base = (Expr*)nullptr;
+ Result.Base = (Expr *)nullptr;
Result.InvalidBase = false;
Result.Offset = CharUnits::fromQuantity(N);
Result.Designator.setInvalid();
@@ -10013,8 +10002,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (!EvaluateInteger(E->getArg(1), Desired, Info))
return false;
uint64_t MaxLength = uint64_t(-1);
- if (BuiltinOp != Builtin::BIstrchr &&
- BuiltinOp != Builtin::BIwcschr &&
+ if (BuiltinOp != Builtin::BIstrchr && BuiltinOp != Builtin::BIwcschr &&
BuiltinOp != Builtin::BI__builtin_strchr &&
BuiltinOp != Builtin::BI__builtin_wcschr) {
APSInt N;
@@ -10031,9 +10019,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
QualType CharTy = Result.Designator.getType(Info.Ctx);
bool IsRawByte = BuiltinOp == Builtin::BImemchr ||
BuiltinOp == Builtin::BI__builtin_memchr;
- assert(IsRawByte ||
- Info.Ctx.hasSameUnqualifiedType(
- CharTy, E->getArg(0)->getType()->getPointeeType()));
+ assert(IsRawByte || Info.Ctx.hasSameUnqualifiedType(
+ CharTy, E->getArg(0)->getType()->getPointeeType()));
// Pointers to const void may point to objects of incomplete type.
if (IsRawByte && CharTy->isIncompleteType()) {
Info.FFDiag(E, diag::note_constexpr_ltor_incomplete_type) << CharTy;
@@ -10184,7 +10171,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
llvm::APInt::udivrem(OrigN, TSize, N, Remainder);
if (Remainder) {
Info.FFDiag(E, diag::note_constexpr_memcpy_unsupported)
- << Move << WChar << 0 << T << toString(OrigN, 10, /*Signed*/false)
+ << Move << WChar << 0 << T << toString(OrigN, 10, /*Signed*/ false)
<< (unsigned)TSize;
return false;
}
@@ -10198,7 +10185,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (N.ugt(RemainingSrcSize) || N.ugt(RemainingDestSize)) {
Info.FFDiag(E, diag::note_constexpr_memcpy_unsupported)
<< Move << WChar << (N.ugt(RemainingSrcSize) ? 1 : 2) << T
- << toString(N, 10, /*Signed*/false);
+ << toString(N, 10, /*Signed*/ false);
return false;
}
uint64_t NElems = N.getZExtValue();
@@ -10393,8 +10380,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
AllocType = Info.Ctx.getConstantArrayType(AllocType, ArrayBound, nullptr,
ArraySizeModifier::Normal, 0);
} else {
- assert(!AllocType->isArrayType() &&
- "array allocation with non-array new");
+ assert(!AllocType->isArrayType() && "array allocation with non-array new");
}
APValue *Val;
@@ -10488,24 +10474,24 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
namespace {
class MemberPointerExprEvaluator
- : public ExprEvaluatorBase<MemberPointerExprEvaluator> {
+ : public ExprEvaluatorBase<MemberPointerExprEvaluator> {
MemberPtr &Result;
bool Success(const ValueDecl *D) {
Result = MemberPtr(D);
return true;
}
-public:
+public:
MemberPointerExprEvaluator(EvalInfo &Info, MemberPtr &Result)
- : ExprEvaluatorBaseTy(Info), Result(Result) {}
+ : ExprEvaluatorBaseTy(Info), Result(Result) {}
bool Success(const APValue &V, const Expr *E) {
Result.setFrom(V);
return true;
}
bool ZeroInitialization(const Expr *E) {
- return Success((const ValueDecl*)nullptr);
+ return Success((const ValueDecl *)nullptr);
}
bool VisitCastExpr(const CastExpr *E);
@@ -10555,7 +10541,8 @@ bool MemberPointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
+ PathE = E->path_end();
+ PathI != PathE; ++PathI) {
assert(!(*PathI)->isVirtual() && "memptr cast through vbase");
const CXXRecordDecl *Base = (*PathI)->getType()->getAsCXXRecordDecl();
if (!Result.castToBase(Base))
@@ -10576,42 +10563,41 @@ bool MemberPointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
- class RecordExprEvaluator
- : public ExprEvaluatorBase<RecordExprEvaluator> {
- const LValue &This;
- APValue &Result;
- public:
+class RecordExprEvaluator : public ExprEvaluatorBase<RecordExprEvaluator> {
+ const LValue &This;
+ APValue &Result;
- RecordExprEvaluator(EvalInfo &info, const LValue &This, APValue &Result)
+public:
+ RecordExprEvaluator(EvalInfo &info, const LValue &This, APValue &Result)
: ExprEvaluatorBaseTy(info), This(This), Result(Result) {}
- bool Success(const APValue &V, const Expr *E) {
- Result = V;
- return true;
- }
- bool ZeroInitialization(const Expr *E) {
- return ZeroInitialization(E, E->getType());
- }
- bool ZeroInitialization(const Expr *E, QualType T);
+ bool Success(const APValue &V, const Expr *E) {
+ Result = V;
+ return true;
+ }
+ bool ZeroInitialization(const Expr *E) {
+ return ZeroInitialization(E, E->getType());
+ }
+ bool ZeroInitialization(const Expr *E, QualType T);
- bool VisitCallExpr(const CallExpr *E) {
- return handleCallExpr(E, Result, &This);
- }
- bool VisitCastExpr(const CastExpr *E);
- bool VisitInitListExpr(const InitListExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
- return VisitCXXConstructExpr(E, E->getType());
- }
- bool VisitLambdaExpr(const LambdaExpr *E);
- bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
- bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
- bool VisitBinCmp(const BinaryOperator *E);
- bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
- bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
- ArrayRef<Expr *> Args);
- };
-}
+ bool VisitCallExpr(const CallExpr *E) {
+ return handleCallExpr(E, Result, &This);
+ }
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
+ return VisitCXXConstructExpr(E, E->getType());
+ }
+ bool VisitLambdaExpr(const LambdaExpr *E);
+ bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
+ bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
+ bool VisitBinCmp(const BinaryOperator *E);
+ bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+ bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
+ ArrayRef<Expr *> Args);
+};
+} // namespace
/// Perform zero-initialization on an object of non-union class type.
/// C++11 [dcl.init]p5:
@@ -10628,13 +10614,15 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
Result = APValue(APValue::UninitStruct(), CD ? CD->getNumBases() : 0,
std::distance(RD->field_begin(), RD->field_end()));
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
if (CD) {
unsigned Index = 0;
for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(),
- End = CD->bases_end(); I != End; ++I, ++Index) {
+ End = CD->bases_end();
+ I != End; ++I, ++Index) {
const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
LValue Subobject = This;
if (!HandleLValueDirectBase(Info, E, Subobject, CD, Base, &Layout))
@@ -10655,8 +10643,8 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
return false;
ImplicitValueInitExpr VIE(I->getType());
- if (!EvaluateInPlace(
- Result.getStructField(I->getFieldIndex()), Info, Subobject, &VIE))
+ if (!EvaluateInPlace(Result.getStructField(I->getFieldIndex()), Info,
+ Subobject, &VIE))
return false;
}
@@ -10665,7 +10653,8 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) {
const RecordDecl *RD = T->castAs<RecordType>()->getDecl();
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
if (RD->isUnion()) {
// C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the
// object's first non-static named data member is zero-initialized
@@ -10673,7 +10662,7 @@ bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) {
while (I != RD->field_end() && (*I)->isUnnamedBitField())
++I;
if (I == RD->field_end()) {
- Result = APValue((const FieldDecl*)nullptr);
+ Result = APValue((const FieldDecl *)nullptr);
return true;
}
@@ -10713,7 +10702,8 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
APValue *Value = &DerivedObject;
const CXXRecordDecl *RD = E->getSubExpr()->getType()->getAsCXXRecordDecl();
for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
+ PathE = E->path_end();
+ PathI != PathE; ++PathI) {
assert(!(*PathI)->isVirtual() && "record rvalue with virtual base");
const CXXRecordDecl *Base = (*PathI)->getType()->getAsCXXRecordDecl();
Value = &Value->getStructBase(getBaseIndex(RD, Base));
@@ -10735,7 +10725,8 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
const Expr *ExprToVisit, ArrayRef<Expr *> Args) {
const RecordDecl *RD =
ExprToVisit->getType()->castAs<RecordType>()->getDecl();
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
@@ -10852,8 +10843,8 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
- (Field->isBitField() && !truncateBitfieldValue(Info, Init,
- FieldVal, Field))) {
+ (Field->isBitField() &&
+ !truncateBitfieldValue(Info, Init, FieldVal, Field))) {
if (!Info.noteFailure())
return false;
Success = false;
@@ -10870,7 +10861,8 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
// Note that E's type is not necessarily the type of our class here; we might
// be initializing an array element instead.
const CXXConstructorDecl *FD = E->getConstructor();
- if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl()) return false;
+ if (FD->isInvalidDecl() || FD->getParent()->isInvalidDecl())
+ return false;
bool ZeroInit = E->requiresZeroInitialization();
if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
@@ -10909,9 +10901,8 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
return false;
auto Args = llvm::ArrayRef(E->getArgs(), E->getNumArgs());
- return HandleConstructorCall(E, This, Args,
- cast<CXXConstructorDecl>(Definition), Info,
- Result);
+ return HandleConstructorCall(
+ E, This, Args, cast<CXXConstructorDecl>(Definition), Info, Result);
}
bool RecordExprEvaluator::VisitCXXInheritedCtorInitExpr(
@@ -10998,7 +10989,7 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
"The number of lambda capture initializers should equal the number of "
"fields within the closure type");
- Result = APValue(APValue::UninitStruct(), /*NumBases*/0, NumFields);
+ Result = APValue(APValue::UninitStruct(), /*NumBases*/ 0, NumFields);
// Iterate through all the lambda's closure object's fields and initialize
// them.
auto *CaptureInitIt = E->capture_init_begin();
@@ -11029,8 +11020,8 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) {
return Success;
}
-static bool EvaluateRecord(const Expr *E, const LValue &This,
- APValue &Result, EvalInfo &Info) {
+static bool EvaluateRecord(const Expr *E, const LValue &This, APValue &Result,
+ EvalInfo &Info) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->isRecordType() &&
"can't evaluate expression as a record rvalue");
@@ -11046,10 +11037,10 @@ static bool EvaluateRecord(const Expr *E, const LValue &This,
//===----------------------------------------------------------------------===//
namespace {
class TemporaryExprEvaluator
- : public LValueExprEvaluatorBase<TemporaryExprEvaluator> {
+ : public LValueExprEvaluatorBase<TemporaryExprEvaluator> {
public:
- TemporaryExprEvaluator(EvalInfo &Info, LValue &Result) :
- LValueExprEvaluatorBaseTy(Info, Result, false) {}
+ TemporaryExprEvaluator(EvalInfo &Info, LValue &Result)
+ : LValueExprEvaluatorBaseTy(Info, Result, false) {}
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
@@ -11073,15 +11064,11 @@ class TemporaryExprEvaluator
bool VisitCXXConstructExpr(const CXXConstructExpr *E) {
return VisitConstructExpr(E);
}
- bool VisitCallExpr(const CallExpr *E) {
- return VisitConstructExpr(E);
- }
+ bool VisitCallExpr(const CallExpr *E) { return VisitConstructExpr(E); }
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E) {
return VisitConstructExpr(E);
}
- bool VisitLambdaExpr(const LambdaExpr *E) {
- return VisitConstructExpr(E);
- }
+ bool VisitLambdaExpr(const LambdaExpr *E) { return VisitConstructExpr(E); }
};
} // end anonymous namespace
@@ -11097,44 +11084,42 @@ static bool EvaluateTemporary(const Expr *E, LValue &Result, EvalInfo &Info) {
//===----------------------------------------------------------------------===//
namespace {
- class VectorExprEvaluator
- : public ExprEvaluatorBase<VectorExprEvaluator> {
- APValue &Result;
- public:
+class VectorExprEvaluator : public ExprEvaluatorBase<VectorExprEvaluator> {
+ APValue &Result;
- VectorExprEvaluator(EvalInfo &info, APValue &Result)
+public:
+ VectorExprEvaluator(EvalInfo &info, APValue &Result)
: ExprEvaluatorBaseTy(info), Result(Result) {}
- bool Success(ArrayRef<APValue> V, const Expr *E) {
- assert(V.size() == E->getType()->castAs<VectorType>()->getNumElements());
- // FIXME: remove this APValue copy.
- Result = APValue(V.data(), V.size());
- return true;
- }
- bool Success(const APValue &V, const Expr *E) {
- assert(V.isVector());
- Result = V;
- return true;
- }
- bool ZeroInitialization(const Expr *E);
-
- bool VisitUnaryReal(const UnaryOperator *E)
- { return Visit(E->getSubExpr()); }
- bool VisitCastExpr(const CastExpr* E);
- bool VisitInitListExpr(const InitListExpr *E);
- bool VisitUnaryImag(const UnaryOperator *E);
- bool VisitBinaryOperator(const BinaryOperator *E);
- bool VisitUnaryOperator(const UnaryOperator *E);
- bool VisitCallExpr(const CallExpr *E);
- bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
- bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
-
- // FIXME: Missing: conditional operator (for GNU
- // conditional select), ExtVectorElementExpr
- };
+ bool Success(ArrayRef<APValue> V, const Expr *E) {
+ assert(V.size() == E->getType()->castAs<VectorType>()->getNumElements());
+ // FIXME: remove this APValue copy.
+ Result = APValue(V.data(), V.size());
+ return true;
+ }
+ bool Success(const APValue &V, const Expr *E) {
+ assert(V.isVector());
+ Result = V;
+ return true;
+ }
+ bool ZeroInitialization(const Expr *E);
+
+ bool VisitUnaryReal(const UnaryOperator *E) { return Visit(E->getSubExpr()); }
+ bool VisitCastExpr(const CastExpr *E);
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitUnaryImag(const UnaryOperator *E);
+ bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitUnaryOperator(const UnaryOperator *E);
+ bool VisitCallExpr(const CallExpr *E);
+ bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
+ bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
+
+ // FIXME: Missing: conditional operator (for GNU
+ // conditional select), ExtVectorElementExpr
+};
} // end anonymous namespace
-static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
+static bool EvaluateVector(const Expr *E, APValue &Result, EvalInfo &Info) {
assert(E->isPRValue() && E->getType()->isVectorType() &&
"not a vector prvalue");
return VectorExprEvaluator(Info, Result).Visit(E);
@@ -11177,7 +11162,8 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
// Give up if the input isn't an int, float, or vector. For example, we
// reject "(v4i16)(intptr_t)&a".
Info.FFDiag(E, diag::note_constexpr_invalid_cast)
- << diag::CastKind::ThisCastOrReinterpret << Info.Ctx.getLangOpts().CPlusPlus;
+ << diag::CastKind::ThisCastOrReinterpret
+ << Info.Ctx.getLangOpts().CPlusPlus;
return false;
}
@@ -11200,8 +11186,7 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
}
-bool
-VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
+bool VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
const VectorType *VT = E->getType()->castAs<VectorType>();
unsigned NumInits = E->getNumInits();
unsigned NumElements = VT->getNumElements();
@@ -11221,8 +11206,8 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
unsigned CountInits = 0, CountElts = 0;
while (CountElts < NumElements) {
// Handle nested vector initialization.
- if (CountInits < NumInits
- && E->getInit(CountInits)->getType()->isVectorType()) {
+ if (CountInits < NumInits &&
+ E->getInit(CountInits)->getType()->isVectorType()) {
APValue v;
if (!EvaluateVector(E->getInit(CountInits), v, Info))
return Error(E);
@@ -11254,8 +11239,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
return Success(Elements, E);
}
-bool
-VectorExprEvaluator::ZeroInitialization(const Expr *E) {
+bool VectorExprEvaluator::ZeroInitialization(const Expr *E) {
const auto *VT = E->getType()->castAs<VectorType>();
QualType EltTy = VT->getElementType();
APValue ZeroElement;
@@ -11586,72 +11570,70 @@ bool VectorExprEvaluator::VisitShuffleVectorExpr(const ShuffleVectorExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
- class ArrayExprEvaluator
- : public ExprEvaluatorBase<ArrayExprEvaluator> {
- const LValue &This;
- APValue &Result;
- public:
+class ArrayExprEvaluator : public ExprEvaluatorBase<ArrayExprEvaluator> {
+ const LValue &This;
+ APValue &Result;
- ArrayExprEvaluator(EvalInfo &Info, const LValue &This, APValue &Result)
+public:
+ ArrayExprEvaluator(EvalInfo &Info, const LValue &This, APValue &Result)
: ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
- bool Success(const APValue &V, const Expr *E) {
- assert(V.isArray() && "expected array");
- Result = V;
- return true;
- }
-
- bool ZeroInitialization(const Expr *E) {
- const ConstantArrayType *CAT =
- Info.Ctx.getAsConstantArrayType(E->getType());
- if (!CAT) {
- if (E->getType()->isIncompleteArrayType()) {
- // We can be asked to zero-initialize a flexible array member; this
- // is represented as an ImplicitValueInitExpr of incomplete array
- // type. In this case, the array has zero elements.
- Result = APValue(APValue::UninitArray(), 0, 0);
- return true;
- }
- // FIXME: We could handle VLAs here.
- return Error(E);
- }
+ bool Success(const APValue &V, const Expr *E) {
+ assert(V.isArray() && "expected array");
+ Result = V;
+ return true;
+ }
- Result = APValue(APValue::UninitArray(), 0, CAT->getZExtSize());
- if (!Result.hasArrayFiller())
+ bool ZeroInitialization(const Expr *E) {
+ const ConstantArrayType *CAT =
+ Info.Ctx.getAsConstantArrayType(E->getType());
+ if (!CAT) {
+ if (E->getType()->isIncompleteArrayType()) {
+ // We can be asked to zero-initialize a flexible array member; this
+ // is represented as an ImplicitValueInitExpr of incomplete array
+ // type. In this case, the array has zero elements.
+ Result = APValue(APValue::UninitArray(), 0, 0);
return true;
+ }
+ // FIXME: We could handle VLAs here.
+ return Error(E);
+ }
- // Zero-initialize all elements.
- LValue Subobject = This;
- Subobject.addArray(Info, E, CAT);
- ImplicitValueInitExpr VIE(CAT->getElementType());
- return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE);
- }
-
- bool VisitCallExpr(const CallExpr *E) {
- return handleCallExpr(E, Result, &This);
- }
- bool VisitInitListExpr(const InitListExpr *E,
- QualType AllocType = QualType());
- bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E);
- bool VisitCXXConstructExpr(const CXXConstructExpr *E,
- const LValue &Subobject,
- APValue *Value, QualType Type);
- bool VisitStringLiteral(const StringLiteral *E,
- QualType AllocType = QualType()) {
- expandStringLiteral(Info, E, Result, AllocType);
+ Result = APValue(APValue::UninitArray(), 0, CAT->getZExtSize());
+ if (!Result.hasArrayFiller())
return true;
- }
- bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
- bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
- ArrayRef<Expr *> Args,
- const Expr *ArrayFiller,
- QualType AllocType = QualType());
- };
+
+ // Zero-initialize all elements.
+ LValue Subobject = This;
+ Subobject.addArray(Info, E, CAT);
+ ImplicitValueInitExpr VIE(CAT->getElementType());
+ return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE);
+ }
+
+ bool VisitCallExpr(const CallExpr *E) {
+ return handleCallExpr(E, Result, &This);
+ }
+ bool VisitInitListExpr(const InitListExpr *E,
+ QualType AllocType = QualType());
+ bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ bool VisitCXXConstructExpr(const CXXConstructExpr *E, const LValue &Subobject,
+ APValue *Value, QualType Type);
+ bool VisitStringLiteral(const StringLiteral *E,
+ QualType AllocType = QualType()) {
+ expandStringLiteral(Info, E, Result, AllocType);
+ return true;
+ }
+ bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+ bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
+ ArrayRef<Expr *> Args,
+ const Expr *ArrayFiller,
+ QualType AllocType = QualType());
+};
} // end anonymous namespace
-static bool EvaluateArray(const Expr *E, const LValue &This,
- APValue &Result, EvalInfo &Info) {
+static bool EvaluateArray(const Expr *E, const LValue &This, APValue &Result,
+ EvalInfo &Info) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->isArrayType() &&
"not an array prvalue");
@@ -11862,10 +11844,10 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
// array element, if any.
FullExpressionRAII Scope(Info);
- if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
- Info, Subobject, E->getSubExpr()) ||
- !HandleLValueArrayAdjustment(Info, E, Subobject,
- CAT->getElementType(), 1)) {
+ if (!EvaluateInPlace(Result.getArrayInitializedElt(Index), Info, Subobject,
+ E->getSubExpr()) ||
+ !HandleLValueArrayAdjustment(Info, E, Subobject, CAT->getElementType(),
+ 1)) {
if (!Info.noteFailure())
return false;
Success = false;
@@ -11884,17 +11866,16 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
const LValue &Subobject,
- APValue *Value,
- QualType Type) {
+ APValue *Value, QualType Type) {
bool HadZeroInit = Value->hasValue();
if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) {
unsigned FinalSize = CAT->getZExtSize();
// Preserve the array filler if we had prior zero-initialization.
- APValue Filler =
- HadZeroInit && Value->hasArrayFiller() ? Value->getArrayFiller()
- : APValue();
+ APValue Filler = HadZeroInit && Value->hasArrayFiller()
+ ? Value->getArrayFiller()
+ : APValue();
*Value = APValue(APValue::UninitArray(), 0, FinalSize);
if (FinalSize == 0)
@@ -11956,7 +11937,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
return Error(E);
return RecordExprEvaluator(Info, Subobject, *Value)
- .VisitCXXConstructExpr(E, Type);
+ .VisitCXXConstructExpr(E, Type);
}
bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
@@ -11977,9 +11958,9 @@ bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
//===----------------------------------------------------------------------===//
namespace {
-class IntExprEvaluator
- : public ExprEvaluatorBase<IntExprEvaluator> {
+class IntExprEvaluator : public ExprEvaluatorBase<IntExprEvaluator> {
APValue &Result;
+
public:
IntExprEvaluator(EvalInfo &info, APValue &result)
: ExprEvaluatorBaseTy(info), Result(result) {}
@@ -12005,7 +11986,7 @@ class IntExprEvaluator
"Invalid evaluation result.");
Result = APValue(APSInt(I));
Result.getInt().setIsUnsigned(
- E->getType()->isUnsignedIntegerOrEnumerationType());
+ E->getType()->isUnsignedIntegerOrEnumerationType());
return true;
}
bool Success(const llvm::APInt &I, const Expr *E) {
@@ -12075,7 +12056,7 @@ class IntExprEvaluator
bool VisitOffsetOfExpr(const OffsetOfExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
- bool VisitCastExpr(const CastExpr* E);
+ bool VisitCastExpr(const CastExpr *E);
bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
@@ -12097,9 +12078,7 @@ class IntExprEvaluator
}
// Note, GNU defines __null as an integer, not a pointer.
- bool VisitGNUNullExpr(const GNUNullExpr *E) {
- return ZeroInitialization(E);
- }
+ bool VisitGNUNullExpr(const GNUNullExpr *E) { return ZeroInitialization(E); }
bool VisitTypeTraitExpr(const TypeTraitExpr *E) {
return Success(E->getValue(), E);
@@ -12135,7 +12114,7 @@ class FixedPointExprEvaluator
: public ExprEvaluatorBase<FixedPointExprEvaluator> {
APValue &Result;
- public:
+public:
FixedPointExprEvaluator(EvalInfo &info, APValue &result)
: ExprEvaluatorBaseTy(info), Result(result) {}
@@ -12161,9 +12140,7 @@ class FixedPointExprEvaluator
return true;
}
- bool ZeroInitialization(const Expr *E) {
- return Success(0, E);
- }
+ bool ZeroInitialization(const Expr *E) { return Success(0, E); }
//===--------------------------------------------------------------------===//
// Visitor Methods
@@ -12250,14 +12227,14 @@ static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
/// Check whether the given declaration can be directly converted to an integral
/// rvalue. If not, no diagnostic is produced; there are other things we can
/// try.
-bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
+bool IntExprEvaluator::CheckReferencedDecl(const Expr *E, const Decl *D) {
// Enums are integer constant exprs.
if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
// Check for signedness/width mismatches between E type and ECD value.
- bool SameSign = (ECD->getInitVal().isSigned()
- == E->getType()->isSignedIntegerOrEnumerationType());
- bool SameWidth = (ECD->getInitVal().getBitWidth()
- == Info.Ctx.getIntWidth(E->getType()));
+ bool SameSign = (ECD->getInitVal().isSigned() ==
+ E->getType()->isSignedIntegerOrEnumerationType());
+ bool SameWidth =
+ (ECD->getInitVal().getBitWidth() == Info.Ctx.getIntWidth(E->getType()));
if (SameSign && SameWidth)
return Success(ECD->getInitVal(), E);
else {
@@ -12290,17 +12267,20 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
#include "clang/AST/TypeNodes.inc"
case Type::Auto:
case Type::DeducedTemplateSpecialization:
- llvm_unreachable("unexpected non-canonical or dependent type");
+ llvm_unreachable("unexpected non-canonical or dependent type");
case Type::Builtin:
- switch (cast<BuiltinType>(CanTy)->getKind()) {
+ switch (cast<BuiltinType>(CanTy)->getKind()) {
#define BUILTIN_TYPE(ID, SINGLETON_ID)
-#define SIGNED_TYPE(ID, SINGLETON_ID) \
- case BuiltinType::ID: return GCCTypeClass::Integer;
-#define FLOATING_TYPE(ID, SINGLETON_ID) \
- case BuiltinType::ID: return GCCTypeClass::RealFloat;
-#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) \
- case BuiltinType::ID: break;
+#define SIGNED_TYPE(ID, SINGLETON_ID) \
+ case BuiltinType::ID: \
+ return GCCTypeClass::Integer;
+#define FLOATING_TYPE(ID, SINGLETON_ID) \
+ case BuiltinType::ID: \
+ return GCCTypeClass::RealFloat;
+#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) \
+ case BuiltinType::ID: \
+ break;
#include "clang/AST/BuiltinTypes.def"
case BuiltinType::Void:
return GCCTypeClass::Void;
@@ -12340,22 +12320,19 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
- case BuiltinType::Id:
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ case BuiltinType::Id:
#include "clang/Basic/OpenCLImageTypes.def"
-#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
- case BuiltinType::Id:
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
case BuiltinType::OCLSampler:
case BuiltinType::OCLEvent:
case BuiltinType::OCLClkEvent:
case BuiltinType::OCLQueue:
case BuiltinType::OCLReserveID:
-#define SVE_TYPE(Name, Id, SingletonId) \
- case BuiltinType::Id:
+#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
#include "clang/Basic/AArch64SVEACLETypes.def"
-#define PPC_VECTOR_TYPE(Name, Id, Size) \
- case BuiltinType::Id:
+#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
#include "clang/Basic/PPCTypes.def"
#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
#include "clang/Basic/RISCVVTypes.def"
@@ -12429,8 +12406,8 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T,
/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way
/// as GCC.
-static GCCTypeClass
-EvaluateBuiltinClassifyType(const CallExpr *E, const LangOptions &LangOpts) {
+static GCCTypeClass EvaluateBuiltinClassifyType(const CallExpr *E,
+ const LangOptions &LangOpts) {
// If no argument was supplied, default to None. This isn't
// ideal, however it is what gcc does.
if (E->getNumArgs() == 0)
@@ -12518,10 +12495,10 @@ static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {
/// Retrieves the "underlying object type" of the given expression,
/// as used by __builtin_object_size.
static QualType getObjectType(APValue::LValueBase B) {
- if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl *>()) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getType();
- } else if (const Expr *E = B.dyn_cast<const Expr*>()) {
+ } else if (const Expr *E = B.dyn_cast<const Expr *>()) {
if (isa<CompoundLiteralExpr>(E))
return E->getType();
} else if (B.is<TypeInfoLValue>()) {
@@ -13176,10 +13153,18 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return false;
unsigned Arg;
switch (Val.getCategory()) {
- case APFloat::fcNaN: Arg = 0; break;
- case APFloat::fcInfinity: Arg = 1; break;
- case APFloat::fcNormal: Arg = Val.isDenormal() ? 3 : 2; break;
- case APFloat::fcZero: Arg = 4; break;
+ case APFloat::fcNaN:
+ Arg = 0;
+ break;
+ case APFloat::fcInfinity:
+ Arg = 1;
+ break;
+ case APFloat::fcNormal:
+ Arg = Val.isDenormal() ? 3 : 2;
+ break;
+ case APFloat::fcZero:
+ Arg = 4;
+ break;
}
return Visit(E->getArg(Arg));
}
@@ -13430,8 +13415,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return false;
uint64_t MaxLength = uint64_t(-1);
- if (BuiltinOp != Builtin::BIstrcmp &&
- BuiltinOp != Builtin::BIwcscmp &&
+ if (BuiltinOp != Builtin::BIstrcmp && BuiltinOp != Builtin::BIwcscmp &&
BuiltinOp != Builtin::BI__builtin_strcmp &&
BuiltinOp != Builtin::BI__builtin_wcscmp) {
APSInt N;
@@ -13573,8 +13557,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
}
}
- return BuiltinOp == Builtin::BI__atomic_always_lock_free ?
- Success(0, E) : Error(E);
+ return BuiltinOp == Builtin::BI__atomic_always_lock_free ? Success(0, E)
+ : Error(E);
}
case Builtin::BI__builtin_addcb:
case Builtin::BI__builtin_addcs:
@@ -13669,7 +13653,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
bool IsSigned = LHS.isSigned() || RHS.isSigned() ||
ResultType->isSignedIntegerOrEnumerationType();
bool AllSigned = LHS.isSigned() && RHS.isSigned() &&
- ResultType->isSignedIntegerOrEnumerationType();
+ ResultType->isSignedIntegerOrEnumerationType();
uint64_t LHSSize = LHS.getBitWidth();
uint64_t RHSSize = RHS.getBitWidth();
uint64_t ResultSize = Info.Ctx.getTypeSize(ResultType);
@@ -13999,7 +13983,7 @@ class DataRecursiveIntBinOpEvaluator {
public:
DataRecursiveIntBinOpEvaluator(IntExprEvaluator &IntEval, APValue &Result)
- : IntEval(IntEval), Info(IntEval.getEvalInfo()), FinalResult(Result) { }
+ : IntEval(IntEval), Info(IntEval.getEvalInfo()), FinalResult(Result) {}
/// True if \param E is a binary operator that we are going to handle
/// data recursively.
@@ -14018,7 +14002,8 @@ class DataRecursiveIntBinOpEvaluator {
while (!Queue.empty())
process(PrevResult);
- if (PrevResult.Failed) return false;
+ if (PrevResult.Failed)
+ return false;
FinalResult.swap(PrevResult.Val);
return true;
@@ -14031,12 +14016,8 @@ class DataRecursiveIntBinOpEvaluator {
bool Success(const APSInt &Value, const Expr *E, APValue &Result) {
return IntEval.Success(Value, E, Result);
}
- bool Error(const Expr *E) {
- return IntEval.Error(E);
- }
- bool Error(const Expr *E, diag::kind D) {
- return IntEval.Error(E, D);
- }
+ bool Error(const Expr *E) { return IntEval.Error(E); }
+ bool Error(const Expr *E, diag::kind D) { return IntEval.Error(E, D); }
OptionalDiagnostic CCEDiag(const Expr *E, diag::kind D) {
return Info.CCEDiag(E, D);
@@ -14059,17 +14040,17 @@ class DataRecursiveIntBinOpEvaluator {
void enqueue(const Expr *E) {
E = E->IgnoreParens();
- Queue.resize(Queue.size()+1);
+ Queue.resize(Queue.size() + 1);
Queue.back().E = E;
Queue.back().Kind = Job::AnyExprKind;
}
};
-}
+} // namespace
-bool DataRecursiveIntBinOpEvaluator::
- VisitBinOpLHSOnly(EvalResult &LHSResult, const BinaryOperator *E,
- bool &SuppressRHSDiags) {
+bool DataRecursiveIntBinOpEvaluator::VisitBinOpLHSOnly(EvalResult &LHSResult,
+ const BinaryOperator *E,
+ bool &SuppressRHSDiags) {
if (E->getOpcode() == BO_Comma) {
// Ignore LHS but note if we could not evaluate it.
if (LHSResult.Failed)
@@ -14121,13 +14102,14 @@ static void addOrSubLValueAsInteger(APValue &LVal, const APSInt &Index,
CharUnits &Offset = LVal.getLValueOffset();
uint64_t Offset64 = Offset.getQuantity();
uint64_t Index64 = Index.extOrTrunc(64).getZExtValue();
- Offset = CharUnits::fromQuantity(IsSub ? Offset64 - Index64
- : Offset64 + Index64);
+ Offset =
+ CharUnits::fromQuantity(IsSub ? Offset64 - Index64 : Offset64 + Index64);
}
-bool DataRecursiveIntBinOpEvaluator::
- VisitBinOp(const EvalResult &LHSResult, const EvalResult &RHSResult,
- const BinaryOperator *E, APValue &Result) {
+bool DataRecursiveIntBinOpEvaluator::VisitBinOp(const EvalResult &LHSResult,
+ const EvalResult &RHSResult,
+ const BinaryOperator *E,
+ APValue &Result) {
if (E->getOpcode() == BO_Comma) {
if (RHSResult.Failed)
return false;
@@ -14176,10 +14158,9 @@ bool DataRecursiveIntBinOpEvaluator::
}
// Handle cases like 4 + (unsigned long)&a
- if (E->getOpcode() == BO_Add &&
- RHSVal.isLValue() && LHSVal.isInt()) {
+ if (E->getOpcode() == BO_Add && RHSVal.isLValue() && LHSVal.isInt()) {
Result = RHSVal;
- addOrSubLValueAsInteger(Result, LHSVal.getInt(), /*IsSub*/false);
+ addOrSubLValueAsInteger(Result, LHSVal.getInt(), /*IsSub*/ false);
return true;
}
@@ -14188,8 +14169,8 @@ bool DataRecursiveIntBinOpEvaluator::
if (!LHSVal.getLValueOffset().isZero() ||
!RHSVal.getLValueOffset().isZero())
return false;
- const Expr *LHSExpr = LHSVal.getLValueBase().dyn_cast<const Expr*>();
- const Expr *RHSExpr = RHSVal.getLValueBase().dyn_cast<const Expr*>();
+ const Expr *LHSExpr = LHSVal.getLValueBase().dyn_cast<const Expr *>();
+ const Expr *RHSExpr = RHSVal.getLValueBase().dyn_cast<const Expr *>();
if (!LHSExpr || !RHSExpr)
return false;
const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr);
@@ -14223,43 +14204,43 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) {
Job &job = Queue.back();
switch (job.Kind) {
- case Job::AnyExprKind: {
- if (const BinaryOperator *Bop = dyn_cast<BinaryOperator>(job.E)) {
- if (shouldEnqueue(Bop)) {
- job.Kind = Job::BinOpKind;
- enqueue(Bop->getLHS());
- return;
- }
- }
-
- EvaluateExpr(job.E, Result);
- Queue.pop_back();
- return;
- }
-
- case Job::BinOpKind: {
- const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
- bool SuppressRHSDiags = false;
- if (!VisitBinOpLHSOnly(Result, Bop, SuppressRHSDiags)) {
- Queue.pop_back();
+ case Job::AnyExprKind: {
+ if (const BinaryOperator *Bop = dyn_cast<BinaryOperator>(job.E)) {
+ if (shouldEnqueue(Bop)) {
+ job.Kind = Job::BinOpKind;
+ enqueue(Bop->getLHS());
return;
}
- if (SuppressRHSDiags)
- job.startSpeculativeEval(Info);
- job.LHSResult.swap(Result);
- job.Kind = Job::BinOpVisitedLHSKind;
- enqueue(Bop->getRHS());
- return;
}
- case Job::BinOpVisitedLHSKind: {
- const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
- EvalResult RHS;
- RHS.swap(Result);
- Result.Failed = !VisitBinOp(job.LHSResult, RHS, Bop, Result.Val);
+ EvaluateExpr(job.E, Result);
+ Queue.pop_back();
+ return;
+ }
+
+ case Job::BinOpKind: {
+ const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
+ bool SuppressRHSDiags = false;
+ if (!VisitBinOpLHSOnly(Result, Bop, SuppressRHSDiags)) {
Queue.pop_back();
return;
}
+ if (SuppressRHSDiags)
+ job.startSpeculativeEval(Info);
+ job.LHSResult.swap(Result);
+ job.Kind = Job::BinOpVisitedLHSKind;
+ enqueue(Bop->getRHS());
+ return;
+ }
+
+ case Job::BinOpVisitedLHSKind: {
+ const BinaryOperator *Bop = cast<BinaryOperator>(job.E);
+ EvalResult RHS;
+ RHS.swap(Result);
+ Result.Failed = !VisitBinOp(job.LHSResult, RHS, Bop, Result.Val);
+ Queue.pop_back();
+ return;
+ }
}
llvm_unreachable("Invalid Job::Kind!");
@@ -14355,9 +14336,9 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (LHS.isComplexFloat()) {
APFloat::cmpResult CR_r =
- LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal());
+ LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal());
APFloat::cmpResult CR_i =
- LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag());
+ LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag());
bool IsEqual = CR_r == APFloat::cmpEqual && CR_i == APFloat::cmpEqual;
return Success(IsEqual ? CmpResult::Equal : CmpResult::Unequal, E);
} else {
@@ -14368,8 +14349,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
}
}
- if (LHSTy->isRealFloatingType() &&
- RHSTy->isRealFloatingType()) {
+ if (LHSTy->isRealFloatingType() && RHSTy->isRealFloatingType()) {
APFloat RHS(0.0), LHS(0.0);
bool LHSOK = EvaluateFloat(E->getRHS(), RHS, Info);
@@ -14381,8 +14361,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
assert(E->isComparisonOp() && "Invalid binary operator!");
llvm::APFloatBase::cmpResult APFloatCmpResult = LHS.compare(RHS);
- if (!Info.InConstantContext &&
- APFloatCmpResult == APFloat::cmpUnordered &&
+ if (!Info.InConstantContext && APFloatCmpResult == APFloat::cmpUnordered &&
E->getFPFeaturesInEffect(Info.Ctx.getLangOpts()).isFPConstrained()) {
// Note: Compares may raise invalid in some cases involving NaN or sNaN.
Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
@@ -14423,7 +14402,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
// Reject differing bases from the normal codepath; we special-case
// comparisons to null.
if (!HasSameBase(LHSValue, RHSValue)) {
- auto DiagComparison = [&] (unsigned DiagID, bool Reversed = false) {
+ auto DiagComparison = [&](unsigned DiagID, bool Reversed = false) {
std::string LHS = LHSValue.toString(Info.Ctx, E->getLHS()->getType());
std::string RHS = RHSValue.toString(Info.Ctx, E->getRHS()->getType());
Info.FFDiag(E, DiagID)
@@ -14472,7 +14451,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
return DiagComparison(diag::note_constexpr_pointer_comparison_past_end,
true);
if (RHSValue.Base && RHSValue.Offset.isZero() &&
- isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))
+ isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))
return DiagComparison(diag::note_constexpr_pointer_comparison_past_end,
false);
// We can't tell whether an object is at the same address as another
@@ -14695,8 +14674,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
auto OnSuccess = [&](CmpResult CR, const BinaryOperator *E) {
assert((CR != CmpResult::Unequal || E->isEqualityOp()) &&
"should only produce Unequal for equality comparisons");
- bool IsEqual = CR == CmpResult::Equal,
- IsLess = CR == CmpResult::Less,
+ bool IsEqual = CR == CmpResult::Equal, IsLess = CR == CmpResult::Less,
IsGreater = CR == CmpResult::Greater;
auto Op = E->getOpcode();
switch (Op) {
@@ -14828,8 +14806,8 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with
/// a result as the expression's type.
bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
- const UnaryExprOrTypeTraitExpr *E) {
- switch(E->getKind()) {
+ const UnaryExprOrTypeTraitExpr *E) {
+ switch (E->getKind()) {
case UETT_PreferredAlignOf:
case UETT_AlignOf: {
if (E->isArgumentType())
@@ -14880,11 +14858,11 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
}
case UETT_OpenMPRequiredSimdAlign:
assert(E->isArgumentType());
- return Success(
- Info.Ctx.toCharUnitsFromBits(
- Info.Ctx.getOpenMPDefaultSimdAlign(E->getArgumentType()))
- .getQuantity(),
- E);
+ return Success(Info.Ctx
+ .toCharUnitsFromBits(Info.Ctx.getOpenMPDefaultSimdAlign(
+ E->getArgumentType()))
+ .getQuantity(),
+ E);
case UETT_VectorElements: {
QualType Ty = E->getTypeOfArgument();
// If the vector has a fixed size, we can determine the number of elements
@@ -14933,7 +14911,8 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
if (!RT)
return Error(OOE);
RecordDecl *RD = RT->getDecl();
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
unsigned i = MemberDecl->getFieldIndex();
assert(i < RL.getFieldCount() && "offsetof field in wrong type");
@@ -14955,7 +14934,8 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
if (!RT)
return Error(OOE);
RecordDecl *RD = RT->getDecl();
- if (RD->isInvalidDecl()) return false;
+ if (RD->isInvalidDecl())
+ return false;
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
// Find the base class itself.
@@ -14989,7 +14969,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
case UO_Minus: {
if (!Visit(E->getSubExpr()))
return false;
- if (!Result.isInt()) return Error(E);
+ if (!Result.isInt())
+ return Error(E);
const APSInt &Value = Result.getInt();
if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow()) {
if (Info.checkingForUndefinedBehavior())
@@ -15008,7 +14989,8 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
case UO_Not: {
if (!Visit(E->getSubExpr()))
return false;
- if (!Result.isInt()) return Error(E);
+ if (!Result.isInt())
+ return Error(E);
return Success(~Result.getInt(), E);
}
case UO_LNot: {
@@ -15190,13 +15172,14 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
}
- return Success(HandleIntToIntCast(Info, E, DestType, SrcType,
- Result.getInt()), E);
+ return Success(
+ HandleIntToIntCast(Info, E, DestType, SrcType, Result.getInt()), E);
}
case CK_PointerToIntegral: {
CCEDiag(E, diag::note_constexpr_invalid_cast)
- << diag::CastKind::ThisCastOrReinterpret << Info.Ctx.getLangOpts().CPlusPlus << E->getSourceRange();
+ << diag::CastKind::ThisCastOrReinterpret
+ << Info.Ctx.getLangOpts().CPlusPlus << E->getSourceRange();
LValue LV;
if (!EvaluatePointer(SubExpr, LV, Info))
@@ -15288,7 +15271,7 @@ bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
}
bool IntExprEvaluator::VisitConceptSpecializationExpr(
- const ConceptSpecializationExpr *E) {
+ const ConceptSpecializationExpr *E) {
return Success(E->isSatisfied(), E);
}
@@ -15298,28 +15281,29 @@ bool IntExprEvaluator::VisitRequiresExpr(const RequiresExpr *E) {
bool FixedPointExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
- default:
- // Invalid unary operators
+ default:
+ // Invalid unary operators
+ return Error(E);
+ case UO_Plus:
+ // The result is just the value.
+ return Visit(E->getSubExpr());
+ case UO_Minus: {
+ if (!Visit(E->getSubExpr()))
+ return false;
+ if (!Result.isFixedPoint())
return Error(E);
- case UO_Plus:
- // The result is just the value.
- return Visit(E->getSubExpr());
- case UO_Minus: {
- if (!Visit(E->getSubExpr())) return false;
- if (!Result.isFixedPoint())
- return Error(E);
- bool Overflowed;
- APFixedPoint Negated = Result.getFixedPoint().negate(&Overflowed);
- if (Overflowed && !HandleOverflow(Info, E, Negated, E->getType()))
- return false;
- return Success(Negated, E);
- }
- case UO_LNot: {
- bool bres;
- if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
- return false;
- return Success(!bres, E);
- }
+ bool Overflowed;
+ APFixedPoint Negated = Result.getFixedPoint().negate(&Overflowed);
+ if (Overflowed && !HandleOverflow(Info, E, Negated, E->getType()))
+ return false;
+ return Success(Negated, E);
+ }
+ case UO_LNot: {
+ bool bres;
+ if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
+ return false;
+ return Success(!bres, E);
+ }
}
}
@@ -15339,9 +15323,9 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
APFixedPoint Result = Src.convert(DestFXSema, &Overflowed);
if (Overflowed) {
if (Info.checkingForUndefinedBehavior())
- Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
- diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
+ Info.Ctx.getDiagnostics().Report(
+ E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
+ << Result.toString() << E->getType();
if (!HandleOverflow(Info, E, Result, E->getType()))
return false;
}
@@ -15358,9 +15342,9 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (Overflowed) {
if (Info.checkingForUndefinedBehavior())
- Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
- diag::warn_fixedpoint_constant_overflow)
- << IntResult.toString() << E->getType();
+ Info.Ctx.getDiagnostics().Report(
+ E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
+ << IntResult.toString() << E->getType();
if (!HandleOverflow(Info, E, IntResult, E->getType()))
return false;
}
@@ -15378,9 +15362,9 @@ bool FixedPointExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (Overflowed) {
if (Info.checkingForUndefinedBehavior())
- Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
- diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
+ Info.Ctx.getDiagnostics().Report(
+ E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
+ << Result.toString() << E->getType();
if (!HandleOverflow(Info, E, Result, E->getType()))
return false;
}
@@ -15416,17 +15400,17 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
switch (E->getOpcode()) {
case BO_Add: {
Result = LHSFX.add(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Sub: {
Result = LHSFX.sub(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Mul: {
Result = LHSFX.mul(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Div: {
@@ -15435,7 +15419,7 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return false;
}
Result = LHSFX.div(RHSFX, &OpOverflow)
- .convert(ResultFXSema, &ConversionOverflow);
+ .convert(ResultFXSema, &ConversionOverflow);
break;
}
case BO_Shl:
@@ -15468,7 +15452,7 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (Info.checkingForUndefinedBehavior())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
diag::warn_fixedpoint_constant_overflow)
- << Result.toString() << E->getType();
+ << Result.toString() << E->getType();
if (!HandleOverflow(Info, E, Result, E->getType()))
return false;
}
@@ -15480,12 +15464,12 @@ bool FixedPointExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class FloatExprEvaluator
- : public ExprEvaluatorBase<FloatExprEvaluator> {
+class FloatExprEvaluator : public ExprEvaluatorBase<FloatExprEvaluator> {
APFloat &Result;
+
public:
FloatExprEvaluator(EvalInfo &info, APFloat &result)
- : ExprEvaluatorBaseTy(info), Result(result) {}
+ : ExprEvaluatorBaseTy(info), Result(result) {}
bool Success(const APValue &V, const Expr *e) {
Result = V.getFloat();
@@ -15511,19 +15495,18 @@ class FloatExprEvaluator
};
} // end anonymous namespace
-static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
+static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info) {
assert(!E->isValueDependent());
assert(E->isPRValue() && E->getType()->isRealFloatingType());
return FloatExprEvaluator(Info, Result).Visit(E);
}
-static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
- QualType ResultTy,
- const Expr *Arg,
- bool SNaN,
+static bool TryEvaluateBuiltinNaN(const ASTContext &Context, QualType ResultTy,
+ const Expr *Arg, bool SNaN,
llvm::APFloat &Result) {
const StringLiteral *S = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
- if (!S) return false;
+ if (!S)
+ return false;
const llvm::fltSemantics &Sem = Context.getFloatTypeSemantics(ResultTy);
@@ -15574,7 +15557,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_inff16:
case Builtin::BI__builtin_inff128: {
const llvm::fltSemantics &Sem =
- Info.Ctx.getFloatTypeSemantics(E->getType());
+ Info.Ctx.getFloatTypeSemantics(E->getType());
Result = llvm::APFloat::getInf(Sem);
return true;
}
@@ -15584,8 +15567,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
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))
+ if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), true,
+ Result))
return Error(E);
return true;
@@ -15596,8 +15579,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_nanf128:
// If this is __builtin_nan() turn this into a nan, otherwise we
// can't constant fold it.
- if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0),
- false, Result))
+ if (!TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), false,
+ Result))
return Error(E);
return true;
@@ -15620,9 +15603,9 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__arithmetic_fence:
return EvaluateFloat(E->getArg(0), Result, Info);
- // FIXME: Builtin::BI__builtin_powi
- // FIXME: Builtin::BI__builtin_powif
- // FIXME: Builtin::BI__builtin_powil
+ // FIXME: Builtin::BI__builtin_powi
+ // FIXME: Builtin::BI__builtin_powif
+ // FIXME: Builtin::BI__builtin_powil
case Builtin::BI__builtin_copysign:
case Builtin::BI__builtin_copysignf:
@@ -15719,7 +15702,8 @@ bool FloatExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
switch (E->getOpcode()) {
- default: return Error(E);
+ default:
+ return Error(E);
case UO_Plus:
return EvaluateFloat(E->getSubExpr(), Result, Info);
case UO_Minus:
@@ -15751,7 +15735,7 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
}
bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
- const Expr* SubExpr = E->getSubExpr();
+ const Expr *SubExpr = E->getSubExpr();
switch (E->getCastKind()) {
default:
@@ -15759,11 +15743,10 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralToFloating: {
APSInt IntResult;
- const FPOptions FPO = E->getFPFeaturesInEffect(
- Info.Ctx.getLangOpts());
+ const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
return EvaluateInteger(SubExpr, IntResult, Info) &&
- HandleIntToFloatCast(Info, E, FPO, SubExpr->getType(),
- IntResult, E->getType(), Result);
+ HandleIntToFloatCast(Info, E, FPO, SubExpr->getType(), IntResult,
+ E->getType(), Result);
}
case CK_FixedPointToFloating: {
@@ -15803,13 +15786,12 @@ bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class ComplexExprEvaluator
- : public ExprEvaluatorBase<ComplexExprEvaluator> {
+class ComplexExprEvaluator : public ExprEvaluatorBase<ComplexExprEvaluator> {
ComplexValue &Result;
public:
ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result)
- : ExprEvaluatorBaseTy(info), Result(Result) {}
+ : ExprEvaluatorBaseTy(info), Result(Result) {}
bool Success(const APValue &V, const Expr *e) {
Result.setFrom(V);
@@ -15855,7 +15837,7 @@ bool ComplexExprEvaluator::ZeroInitialization(const Expr *E) {
}
bool ComplexExprEvaluator::VisitImaginaryLiteral(const ImaginaryLiteral *E) {
- const Expr* SubExpr = E->getSubExpr();
+ const Expr *SubExpr = E->getSubExpr();
if (SubExpr->getType()->isRealFloatingType()) {
Result.makeComplexFloat();
@@ -15966,8 +15948,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From
- = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From =
+ E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
return HandleFloatToFloatCast(Info, E, From, To, Result.FloatReal) &&
HandleFloatToFloatCast(Info, E, From, To, Result.FloatImag);
@@ -15978,13 +15960,13 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From
- = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From =
+ E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexInt();
- return HandleFloatToIntCast(Info, E, From, Result.FloatReal,
- To, Result.IntReal) &&
- HandleFloatToIntCast(Info, E, From, Result.FloatImag,
- To, Result.IntImag);
+ return HandleFloatToIntCast(Info, E, From, Result.FloatReal, To,
+ Result.IntReal) &&
+ HandleFloatToIntCast(Info, E, From, Result.FloatImag, To,
+ Result.IntImag);
}
case CK_IntegralRealToComplex: {
@@ -16002,8 +15984,8 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
return false;
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From
- = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From =
+ E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.IntReal = HandleIntToIntCast(Info, E, To, From, Result.IntReal);
Result.IntImag = HandleIntToIntCast(Info, E, To, From, Result.IntImag);
@@ -16014,16 +15996,15 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!Visit(E->getSubExpr()))
return false;
- const FPOptions FPO = E->getFPFeaturesInEffect(
- Info.Ctx.getLangOpts());
+ const FPOptions FPO = E->getFPFeaturesInEffect(Info.Ctx.getLangOpts());
QualType To = E->getType()->castAs<ComplexType>()->getElementType();
- QualType From
- = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
+ QualType From =
+ E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType();
Result.makeComplexFloat();
- return HandleIntToFloatCast(Info, E, FPO, From, Result.IntReal,
- To, Result.FloatReal) &&
- HandleIntToFloatCast(Info, E, FPO, From, Result.IntImag,
- To, Result.FloatImag);
+ return HandleIntToFloatCast(Info, E, FPO, From, Result.IntReal, To,
+ Result.FloatReal) &&
+ HandleIntToFloatCast(Info, E, FPO, From, Result.IntImag, To,
+ Result.FloatImag);
}
}
@@ -16165,7 +16146,8 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
assert(!(LHSReal && RHSReal) &&
"Cannot have both operands of a complex operation be real.");
switch (E->getOpcode()) {
- default: return Error(E);
+ default:
+ return Error(E);
case BO_Add:
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().add(RHS.getComplexFloatReal(),
@@ -16232,11 +16214,11 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
} else {
ComplexValue LHS = Result;
Result.getComplexIntReal() =
- (LHS.getComplexIntReal() * RHS.getComplexIntReal() -
- LHS.getComplexIntImag() * RHS.getComplexIntImag());
+ (LHS.getComplexIntReal() * RHS.getComplexIntReal() -
+ LHS.getComplexIntImag() * RHS.getComplexIntImag());
Result.getComplexIntImag() =
- (LHS.getComplexIntReal() * RHS.getComplexIntImag() +
- LHS.getComplexIntImag() * RHS.getComplexIntReal());
+ (LHS.getComplexIntReal() * RHS.getComplexIntImag() +
+ LHS.getComplexIntImag() * RHS.getComplexIntReal());
}
break;
case BO_Div:
@@ -16270,16 +16252,18 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
} else {
ComplexValue LHS = Result;
APSInt Den = RHS.getComplexIntReal() * RHS.getComplexIntReal() +
- RHS.getComplexIntImag() * RHS.getComplexIntImag();
+ RHS.getComplexIntImag() * RHS.getComplexIntImag();
if (Den.isZero())
return Error(E, diag::note_expr_divide_by_zero);
Result.getComplexIntReal() =
- (LHS.getComplexIntReal() * RHS.getComplexIntReal() +
- LHS.getComplexIntImag() * RHS.getComplexIntImag()) / Den;
+ (LHS.getComplexIntReal() * RHS.getComplexIntReal() +
+ LHS.getComplexIntImag() * RHS.getComplexIntImag()) /
+ Den;
Result.getComplexIntImag() =
- (LHS.getComplexIntImag() * RHS.getComplexIntReal() -
- LHS.getComplexIntReal() * RHS.getComplexIntImag()) / Den;
+ (LHS.getComplexIntImag() * RHS.getComplexIntReal() -
+ LHS.getComplexIntReal() * RHS.getComplexIntImag()) /
+ Den;
}
break;
}
@@ -16304,8 +16288,7 @@ bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
if (Result.isComplexFloat()) {
Result.getComplexFloatReal().changeSign();
Result.getComplexFloatImag().changeSign();
- }
- else {
+ } else {
Result.getComplexIntReal() = -Result.getComplexIntReal();
Result.getComplexIntImag() = -Result.getComplexIntImag();
}
@@ -16363,10 +16346,10 @@ bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class AtomicExprEvaluator :
- public ExprEvaluatorBase<AtomicExprEvaluator> {
+class AtomicExprEvaluator : public ExprEvaluatorBase<AtomicExprEvaluator> {
const LValue *This;
APValue &Result;
+
public:
AtomicExprEvaluator(EvalInfo &Info, const LValue *This, APValue &Result)
: ExprEvaluatorBaseTy(Info), This(This), Result(Result) {}
@@ -16413,8 +16396,7 @@ static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
//===----------------------------------------------------------------------===//
namespace {
-class VoidExprEvaluator
- : public ExprEvaluatorBase<VoidExprEvaluator> {
+class VoidExprEvaluator : public ExprEvaluatorBase<VoidExprEvaluator> {
public:
VoidExprEvaluator(EvalInfo &Info) : ExprEvaluatorBaseTy(Info) {}
@@ -16569,7 +16551,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
return false;
C.moveInto(Result);
} else if (T->isFixedPointType()) {
- if (!FixedPointExprEvaluator(Info, Result).Visit(E)) return false;
+ if (!FixedPointExprEvaluator(Info, Result).Visit(E))
+ return false;
} else if (T->isMemberPointerType()) {
MemberPtr P;
if (!EvaluateMemberPointer(E, P, Info))
@@ -16592,8 +16575,7 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
Result = Value;
} else if (T->isVoidType()) {
if (!Info.getLangOpts().CPlusPlus11)
- Info.CCEDiag(E, diag::note_constexpr_nonliteral)
- << E->getType();
+ Info.CCEDiag(E, diag::note_constexpr_nonliteral) << E->getType();
if (!EvaluateVoid(E, Info))
return false;
} else if (T->isAtomicType()) {
@@ -16689,8 +16671,8 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
// Fast-path evaluations of integer literals, since we sometimes see files
// containing vast quantities of these.
if (const auto *L = dyn_cast<IntegerLiteral>(Exp)) {
- Result.Val = APValue(APSInt(L->getValue(),
- L->getType()->isUnsignedIntegerType()));
+ Result.Val =
+ APValue(APSInt(L->getValue(), L->getType()->isUnsignedIntegerType()));
IsConst = true;
return true;
}
@@ -16927,7 +16909,7 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
// If we're evaluating a prvalue, fake up a MaterializeTemporaryExpr to
// represent the result of the evaluation. CheckConstantExpression ensures
// this doesn't escape.
- MaterializeTemporaryExpr BaseMTE(T, const_cast<Expr*>(this), true);
+ MaterializeTemporaryExpr BaseMTE(T, const_cast<Expr *>(this), true);
APValue::LValueBase Base(&BaseMTE);
Info.setEvaluatingDecl(Base, Result.Val);
@@ -17073,8 +17055,9 @@ bool Expr::isEvaluatable(const ASTContext &Ctx, SideEffectsKind SEK) const {
!hasUnacceptableSideEffect(Result, SEK);
}
-APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
- SmallVectorImpl<PartialDiagnosticAt> *Diag) const {
+APSInt
+Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diag) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
@@ -17166,13 +17149,13 @@ struct ICEDiag {
ICEDiag(ICEKind IK, SourceLocation l) : Kind(IK), Loc(l) {}
};
-}
+} // namespace
static ICEDiag NoDiag() { return ICEDiag(IK_ICE, SourceLocation()); }
static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; }
-static ICEDiag CheckEvalInICE(const Expr* E, const ASTContext &Ctx) {
+static ICEDiag CheckEvalInICE(const Expr *E, const ASTContext &Ctx) {
Expr::EvalResult EVResult;
Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
@@ -17185,7 +17168,7 @@ static ICEDiag CheckEvalInICE(const Expr* E, const ASTContext &Ctx) {
return NoDiag();
}
-static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
+static ICEDiag CheckICE(const Expr *E, const ASTContext &Ctx) {
assert(!E->isValueDependent() && "Should not see value dependent exprs!");
if (!E->getType()->isIntegralOrEnumerationType())
return ICEDiag(IK_NotICE, E->getBeginLoc());
@@ -17304,8 +17287,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
return CheckICE(cast<PackIndexingExpr>(E)->getSelectedExpr(), Ctx);
case Expr::SubstNonTypeTemplateParmExprClass:
- return
- CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Ctx);
+ return CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
+ Ctx);
case Expr::ConstantExprClass:
return CheckICE(cast<ConstantExpr>(E)->getSubExpr(), Ctx);
@@ -17397,7 +17380,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
}
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E);
- if ((Exp->getKind() == UETT_SizeOf) &&
+ if ((Exp->getKind() == UETT_SizeOf) &&
Exp->getTypeOfArgument()->isVariableArrayType())
return ICEDiag(IK_NotICE, E->getBeginLoc());
return NoDiag();
@@ -17443,8 +17426,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case BO_Cmp: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
- if (Exp->getOpcode() == BO_Div ||
- Exp->getOpcode() == BO_Rem) {
+ if (Exp->getOpcode() == BO_Div || Exp->getOpcode() == BO_Rem) {
// EvaluateAsRValue gives an error for undefined Div/Rem, so make sure
// we don't evaluate one.
if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE) {
@@ -17499,8 +17481,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::ObjCBridgedCastExprClass: {
const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
if (isa<ExplicitCastExpr>(E)) {
- if (const FloatingLiteral *FL
- = dyn_cast<FloatingLiteral>(SubExpr->IgnoreParenImpCasts())) {
+ if (const FloatingLiteral *FL =
+ dyn_cast<FloatingLiteral>(SubExpr->IgnoreParenImpCasts())) {
unsigned DestWidth = Ctx.getIntWidth(E->getType());
bool DestSigned = E->getType()->isSignedIntegerOrEnumerationType();
APSInt IgnoredVal(DestWidth, !DestSigned);
@@ -17508,9 +17490,9 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
// If the value does not fit in the destination type, the behavior is
// undefined, so we are not required to treat it as a constant
// expression.
- if (FL->getValue().convertToInteger(IgnoredVal,
- llvm::APFloat::rmTowardZero,
- &Ignored) & APFloat::opInvalidOp)
+ if (FL->getValue().convertToInteger(
+ IgnoredVal, llvm::APFloat::rmTowardZero, &Ignored) &
+ APFloat::opInvalidOp)
return ICEDiag(IK_NotICE, E->getBeginLoc());
return NoDiag();
}
@@ -17530,12 +17512,16 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::BinaryConditionalOperatorClass: {
const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E);
ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx);
- if (CommonResult.Kind == IK_NotICE) return CommonResult;
+ if (CommonResult.Kind == IK_NotICE)
+ return CommonResult;
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (FalseResult.Kind == IK_NotICE) return FalseResult;
- if (CommonResult.Kind == IK_ICEIfUnevaluated) return CommonResult;
+ if (FalseResult.Kind == IK_NotICE)
+ return FalseResult;
+ if (CommonResult.Kind == IK_ICEIfUnevaluated)
+ return CommonResult;
if (FalseResult.Kind == IK_ICEIfUnevaluated &&
- Exp->getCommon()->EvaluateKnownConstInt(Ctx) != 0) return NoDiag();
+ Exp->getCommon()->EvaluateKnownConstInt(Ctx) != 0)
+ return NoDiag();
return FalseResult;
}
case Expr::ConditionalOperatorClass: {
@@ -17544,8 +17530,8 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
// then only the true side is actually considered in an integer constant
// expression, and it is fully evaluated. This is an important GNU
// extension. See GCC PR38377 for discussion.
- if (const CallExpr *CallCE
- = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
+ if (const CallExpr *CallCE =
+ dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
if (CallCE->getBuiltinCallee() == Builtin::BI__builtin_constant_p)
return CheckEvalInICE(E, Ctx);
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
@@ -17593,7 +17579,8 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
llvm::APSInt *Value,
SourceLocation *Loc) {
if (!E->getType()->isIntegralOrUnscopedEnumerationType()) {
- if (Loc) *Loc = E->getExprLoc();
+ if (Loc)
+ *Loc = E->getExprLoc();
return false;
}
@@ -17602,11 +17589,13 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
return false;
if (!Result.isInt()) {
- if (Loc) *Loc = E->getExprLoc();
+ if (Loc)
+ *Loc = E->getExprLoc();
return false;
}
- if (Value) *Value = Result.getInt();
+ if (Value)
+ *Value = Result.getInt();
return true;
}
@@ -17622,7 +17611,8 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
ICEDiag D = CheckICE(this, Ctx);
if (D.Kind != IK_ICE) {
- if (Loc) *Loc = D.Loc;
+ if (Loc)
+ *Loc = D.Loc;
return false;
}
return true;
@@ -17692,10 +17682,12 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
if (!Diags.empty()) {
IsConstExpr = false;
- if (Loc) *Loc = Diags[0].first;
+ if (Loc)
+ *Loc = Diags[0].first;
} else if (!IsConstExpr) {
// FIXME: This shouldn't happen.
- if (Loc) *Loc = getExprLoc();
+ if (Loc)
+ *Loc = getExprLoc();
}
return IsConstExpr;
@@ -17703,7 +17695,7 @@ bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
const FunctionDecl *Callee,
- ArrayRef<const Expr*> Args,
+ ArrayRef<const Expr *> Args,
const Expr *This) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
@@ -17740,14 +17732,13 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
}
CallRef Call = Info.CurrentCall->createCall(Callee);
- for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
+ for (ArrayRef<const Expr *>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
unsigned Idx = I - Args.begin();
if (Idx >= Callee->getNumParams())
break;
const ParmVarDecl *PVD = Callee->getParamDecl(Idx);
- if ((*I)->isValueDependent() ||
- !EvaluateCallArg(PVD, *I, Call, Info) ||
+ if ((*I)->isValueDependent() || !EvaluateCallArg(PVD, *I, Call, Info) ||
Info.EvalStatus.HasSideEffects) {
// If evaluation fails, throw away the argument entirely.
if (APValue *Slot = Info.getParamSlot(Call, PVD))
@@ -17773,9 +17764,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
!Info.EvalStatus.HasSideEffects;
}
-bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
- SmallVectorImpl<
- PartialDiagnosticAt> &Diags) {
+bool Expr::isPotentialConstantExpr(
+ const FunctionDecl *FD, SmallVectorImpl<PartialDiagnosticAt> &Diags) {
// FIXME: It would be useful to check constexpr function templates, but at the
// moment the constant expression evaluator cannot cope with the non-rigorous
// ASTs which we build for dependent expressions.
@@ -17812,7 +17802,7 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy);
This.set({&VIE, Info.CurrentCall->Index});
- ArrayRef<const Expr*> Args;
+ ArrayRef<const Expr *> Args;
APValue Scratch;
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
@@ -17831,10 +17821,9 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
return Diags.empty();
}
-bool Expr::isPotentialConstantExprUnevaluated(Expr *E,
- const FunctionDecl *FD,
- SmallVectorImpl<
- PartialDiagnosticAt> &Diags) {
+bool Expr::isPotentialConstantExprUnevaluated(
+ Expr *E, const FunctionDecl *FD,
+ SmallVectorImpl<PartialDiagnosticAt> &Diags) {
assert(!E->isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
More information about the cfe-commits
mailing list