diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:11:37 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:11:37 +0000 |
commit | 461a67fa15370a9ec88f8f8a240bf7c123bb2029 (patch) | |
tree | 6942083d7d56bba40ec790a453ca58ad3baf6832 /lib/AST/ExprConstant.cpp | |
parent | 75c3240472ba6ac2669ee72ca67eb72d4e2851fc (diff) |
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 139 |
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. |