summaryrefslogtreecommitdiff
path: root/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r--lib/AST/ExprConstant.cpp139
1 files changed, 107 insertions, 32 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 792e8cc4a518..9c9eeb79b40a 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -62,7 +62,13 @@ namespace {
static QualType getType(APValue::LValueBase B) {
if (!B) return QualType();
if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>())
- return D->getType();
+ // FIXME: It's unclear where we're supposed to take the type from, and
+ // this actually matters for arrays of unknown bound. Using the type of
+ // the most recent declaration isn't clearly correct in general. Eg:
+ //
+ // extern int arr[]; void f() { extern int arr[3]; };
+ // constexpr int *p = &arr[1]; // valid?
+ return cast<ValueDecl>(D->getMostRecentDecl())->getType();
const Expr *Base = B.get<const Expr*>();
@@ -141,6 +147,12 @@ namespace {
return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E);
}
+ /// 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
@@ -148,7 +160,8 @@ namespace {
static unsigned
findMostDerivedSubobject(ASTContext &Ctx, APValue::LValueBase Base,
ArrayRef<APValue::LValuePathEntry> Path,
- uint64_t &ArraySize, QualType &Type, bool &IsArray) {
+ 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) &&
@@ -158,12 +171,18 @@ namespace {
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
if (Type->isArrayType()) {
- const ConstantArrayType *CAT =
- cast<ConstantArrayType>(Ctx.getAsArrayType(Type));
- Type = CAT->getElementType();
- ArraySize = CAT->getSize().getZExtValue();
+ const ArrayType *AT = Ctx.getAsArrayType(Type);
+ Type = AT->getElementType();
MostDerivedLength = I + 1;
IsArray = true;
+
+ if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
+ ArraySize = CAT->getSize().getZExtValue();
+ } 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();
@@ -246,10 +265,12 @@ namespace {
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);
+ MostDerivedType, IsArray, FirstIsUnsizedArray);
MostDerivedIsArrayElement = IsArray;
+ FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
}
}
}
@@ -318,7 +339,7 @@ namespace {
// 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 = std::numeric_limits<uint64_t>::max() / 2;
+ MostDerivedArraySize = AssumedSizeForUnsizedArray;
MostDerivedPathLength = Entries.size();
}
/// Update this designator to refer to the given base or member of this
@@ -350,6 +371,7 @@ namespace {
MostDerivedArraySize = 2;
MostDerivedPathLength = Entries.size();
}
+ 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.
@@ -357,6 +379,7 @@ namespace {
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?
@@ -573,6 +596,31 @@ namespace {
/// declaration whose initializer is being evaluated, if any.
APValue *EvaluatingDeclValue;
+ /// EvaluatingObject - Pair of the AST node that an lvalue represents and
+ /// the call index that that lvalue was allocated in.
+ typedef std::pair<APValue::LValueBase, unsigned> EvaluatingObject;
+
+ /// EvaluatingConstructors - Set of objects that are currently being
+ /// constructed.
+ llvm::DenseSet<EvaluatingObject> EvaluatingConstructors;
+
+ struct EvaluatingConstructorRAII {
+ EvalInfo &EI;
+ EvaluatingObject Object;
+ bool DidInsert;
+ EvaluatingConstructorRAII(EvalInfo &EI, EvaluatingObject Object)
+ : EI(EI), Object(Object) {
+ DidInsert = EI.EvaluatingConstructors.insert(Object).second;
+ }
+ ~EvaluatingConstructorRAII() {
+ if (DidInsert) EI.EvaluatingConstructors.erase(Object);
+ }
+ };
+
+ bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex) {
+ return EvaluatingConstructors.count(EvaluatingObject(Decl, CallIndex));
+ }
+
/// The current array initialization index, if we're performing array
/// initialization.
uint64_t ArrayInitIndex = -1;
@@ -666,6 +714,7 @@ namespace {
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
EvaluatingDecl = Base;
EvaluatingDeclValue = &Value;
+ EvaluatingConstructors.insert({Base, 0});
}
const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
@@ -984,6 +1033,7 @@ namespace {
void moveFromAndCancel(SpeculativeEvaluationRAII &&Other) {
Info = Other.Info;
OldStatus = Other.OldStatus;
+ OldIsSpeculativelyEvaluating = Other.OldIsSpeculativelyEvaluating;
Other.Info = nullptr;
}
@@ -1067,9 +1117,19 @@ bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
setInvalid();
return false;
}
+ // Note, we do not diagnose if isMostDerivedAnUnsizedArray(), because there
+ // must actually be at least one array element; even a VLA cannot have a
+ // bound of zero. And if our index is nonzero, we already had a CCEDiag.
return true;
}
+void SubobjectDesignator::diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info,
+ const Expr *E) {
+ Info.CCEDiag(E, diag::note_constexpr_unsized_array_indexed);
+ // Do not set the designator as invalid: we can represent this situation,
+ // and correct handling of __builtin_object_size requires us to do so.
+}
+
void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
const Expr *E,
const APSInt &N) {
@@ -1213,8 +1273,6 @@ namespace {
IsNullPtr);
else {
assert(!InvalidBase && "APValues can't handle invalid LValue bases");
- assert(!Designator.FirstEntryIsAnUnsizedArray &&
- "Unsized array with a valid base?");
V = APValue(Base, Offset, Designator.Entries,
Designator.IsOnePastTheEnd, CallIndex, IsNullPtr);
}
@@ -1287,12 +1345,17 @@ namespace {
if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))
Designator.addDeclUnchecked(D, Virtual);
}
- void addUnsizedArray(EvalInfo &Info, QualType ElemTy) {
- assert(Designator.Entries.empty() && getType(Base)->isPointerType());
- assert(isBaseAnAllocSizeCall(Base) &&
- "Only alloc_size bases can have unsized arrays");
- Designator.FirstEntryIsAnUnsizedArray = true;
- Designator.addUnsizedArrayUnchecked(ElemTy);
+ 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))
@@ -1756,6 +1819,9 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
}
}
for (const auto *I : RD->fields()) {
+ if (I->isUnnamedBitfield())
+ continue;
+
if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
Value.getStructField(I->getFieldIndex())))
return false;
@@ -2597,10 +2663,12 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (Sub.Invalid)
// A diagnostic will have already been produced.
return handler.failed();
- if (Sub.isOnePastTheEnd()) {
+ if (Sub.isOnePastTheEnd() || Sub.isMostDerivedAnUnsizedArray()) {
if (Info.getLangOpts().CPlusPlus11)
- Info.FFDiag(E, diag::note_constexpr_access_past_end)
- << handler.AccessKind;
+ Info.FFDiag(E, Sub.isOnePastTheEnd()
+ ? diag::note_constexpr_access_past_end
+ : diag::note_constexpr_access_unsized_array)
+ << handler.AccessKind;
else
Info.FFDiag(E);
return handler.failed();
@@ -3097,10 +3165,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
// During the construction of an object, it is not yet 'const'.
- // FIXME: We don't set up EvaluatingDecl for local variables or temporaries,
- // and this doesn't do quite the right thing for const subobjects of the
+ // FIXME: This doesn't do quite the right thing for const subobjects of the
// object under construction.
- if (LVal.getLValueBase() == Info.EvaluatingDecl) {
+ if (Info.isEvaluatingConstructor(LVal.getLValueBase(), LVal.CallIndex)) {
BaseType = Info.Ctx.getCanonicalType(BaseType);
BaseType.removeLocalConst();
}
@@ -4253,6 +4320,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
return false;
}
+ EvalInfo::EvaluatingConstructorRAII EvalObj(
+ Info, {This.getLValueBase(), This.CallIndex});
CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues);
// FIXME: Creating an APValue just to hold a nonexistent return value is
@@ -5459,7 +5528,7 @@ static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base,
Result.setInvalid(E);
QualType Pointee = E->getType()->castAs<PointerType>()->getPointeeType();
- Result.addUnsizedArray(Info, Pointee);
+ Result.addUnsizedArray(Info, E, Pointee);
return true;
}
@@ -5669,7 +5738,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return true;
}
}
- case CK_ArrayToPointerDecay:
+
+ case CK_ArrayToPointerDecay: {
if (SubExpr->isGLValue()) {
if (!evaluateLValue(SubExpr, Result))
return false;
@@ -5680,12 +5750,13 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return false;
}
// The result is a pointer to the first element of the array.
- if (const ConstantArrayType *CAT
- = Info.Ctx.getAsConstantArrayType(SubExpr->getType()))
+ auto *AT = Info.Ctx.getAsArrayType(SubExpr->getType());
+ if (auto *CAT = dyn_cast<ConstantArrayType>(AT))
Result.addArray(Info, E, CAT);
else
- Result.Designator.setInvalid();
+ Result.addUnsizedArray(Info, E, AT->getElementType());
return true;
+ }
case CK_FunctionToPointerDecay:
return evaluateLValue(SubExpr, Result);
@@ -5752,7 +5823,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
Result.setInvalid(E);
QualType PointeeTy = E->getType()->castAs<PointerType>()->getPointeeType();
- Result.addUnsizedArray(Info, PointeeTy);
+ Result.addUnsizedArray(Info, E, PointeeTy);
return true;
}
@@ -7313,7 +7384,8 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) {
/// Please note: this function is specialized for how __builtin_object_size
/// views "objects".
///
-/// If this encounters an invalid RecordDecl, it will always return true.
+/// If this encounters an invalid RecordDecl or otherwise cannot determine the
+/// correct result, it will always return true.
static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
assert(!LVal.Designator.Invalid);
@@ -7344,9 +7416,8 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
unsigned I = 0;
QualType BaseType = getType(Base);
if (LVal.Designator.FirstEntryIsAnUnsizedArray) {
- assert(isBaseAnAllocSizeCall(Base) &&
- "Unsized array in non-alloc_size call?");
- // If this is an alloc_size base, we should ignore the initial array index
+ // If we don't know the array bound, conservatively assume we're looking at
+ // the final array element.
++I;
BaseType = BaseType->castAs<PointerType>()->getPointeeType();
}
@@ -7901,6 +7972,9 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return BuiltinOp == Builtin::BI__atomic_always_lock_free ?
Success(0, E) : Error(E);
}
+ case Builtin::BIomp_is_initial_device:
+ // We can decide statically which value the runtime would return if called.
+ return Success(Info.getLangOpts().OpenMPIsDevice ? 0 : 1, E);
}
}
@@ -10397,6 +10471,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
+ case BO_Cmp: // FIXME: Re-enable once we can evaluate this.
// C99 6.6/3 allows assignments within unevaluated subexpressions of
// constant expressions, but they can never be ICEs because an ICE cannot
// contain an lvalue operand.