diff options
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r-- | lib/AST/ExprConstant.cpp | 310 |
1 files changed, 230 insertions, 80 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index e69914f25da2b..44cf75dbd25b2 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -319,6 +319,25 @@ namespace { return false; } + /// 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().ArrayIndex : (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) @@ -329,6 +348,13 @@ namespace { /// 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 { + 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) { PathEntry Entry; @@ -572,7 +598,7 @@ namespace { // FIXME: Force the precision of the source value down so we don't // print digits which are usually useless (we don't really care here if // we truncate a digit by accident in edge cases). Ideally, - // APFloat::toString would automatically print the shortest + // APFloat::toString would automatically print the shortest // representation which rounds to the correct value, but it's a bit // tricky to implement. unsigned precision = @@ -826,7 +852,7 @@ namespace { private: OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId, unsigned ExtraNotes, bool IsCCEDiag) { - + if (EvalStatus.Diag) { // If we have a prior diagnostic, it will be noting that the expression // isn't a constant expression. This diagnostic is more important, @@ -880,7 +906,7 @@ namespace { unsigned ExtraNotes = 0) { return Diag(Loc, DiagId, ExtraNotes, false); } - + OptionalDiagnostic FFDiag(const Expr *E, diag::kind DiagId = diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes = 0) { @@ -1706,6 +1732,54 @@ static bool IsGlobalLValue(APValue::LValueBase B) { } } +static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { + return LVal.Base.dyn_cast<const ValueDecl*>(); +} + +static bool IsLiteralLValue(const LValue &Value) { + if (Value.getLValueCallIndex()) + return false; + const Expr *E = Value.Base.dyn_cast<const Expr*>(); + return E && !isa<MaterializeTemporaryExpr>(E); +} + +static bool IsWeakLValue(const LValue &Value) { + const ValueDecl *Decl = GetLValueBaseDecl(Value); + return Decl && Decl->isWeak(); +} + +static bool isZeroSized(const LValue &Value) { + const ValueDecl *Decl = GetLValueBaseDecl(Value); + if (Decl && isa<VarDecl>(Decl)) { + QualType Ty = Decl->getType(); + if (Ty->isArrayType()) + return Ty->isIncompleteType() || + Decl->getASTContext().getTypeSize(Ty) == 0; + } + return false; +} + +static bool HasSameBase(const LValue &A, const LValue &B) { + if (!A.getLValueBase()) + return !B.getLValueBase(); + if (!B.getLValueBase()) + return false; + + if (A.getLValueBase().getOpaqueValue() != + B.getLValueBase().getOpaqueValue()) { + const Decl *ADecl = GetLValueBaseDecl(A); + if (!ADecl) + return false; + const Decl *BDecl = GetLValueBaseDecl(B); + if (!BDecl || ADecl->getCanonicalDecl() != BDecl->getCanonicalDecl()) + return false; + } + + return IsGlobalLValue(A.getLValueBase()) || + (A.getLValueCallIndex() == B.getLValueCallIndex() && + A.getLValueVersion() == B.getLValueVersion()); +} + static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) { assert(Base && "no location for a null lvalue"); const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); @@ -1917,33 +1991,6 @@ CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, QualType Type, return true; } -static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { - return LVal.Base.dyn_cast<const ValueDecl*>(); -} - -static bool IsLiteralLValue(const LValue &Value) { - if (Value.getLValueCallIndex()) - return false; - const Expr *E = Value.Base.dyn_cast<const Expr*>(); - return E && !isa<MaterializeTemporaryExpr>(E); -} - -static bool IsWeakLValue(const LValue &Value) { - const ValueDecl *Decl = GetLValueBaseDecl(Value); - return Decl && Decl->isWeak(); -} - -static bool isZeroSized(const LValue &Value) { - const ValueDecl *Decl = GetLValueBaseDecl(Value); - if (Decl && isa<VarDecl>(Decl)) { - QualType Ty = Decl->getType(); - if (Ty->isArrayType()) - return Ty->isIncompleteType() || - Decl->getASTContext().getTypeSize(Ty) == 0; - } - return false; -} - static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) { // A null base expression indicates a null pointer. These are always // evaluatable, and they are false unless the offset is zero. @@ -4286,13 +4333,13 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, if (Info.getLangOpts().CPlusPlus11) { const FunctionDecl *DiagDecl = Definition ? Definition : Declaration; - + // If this function is not constexpr because it is an inherited // non-constexpr constructor, diagnose that directly. auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl); if (CD && CD->isInheritingConstructor()) { auto *Inherited = CD->getInheritedConstructor().getConstructor(); - if (!Inherited->isConstexpr()) + if (!Inherited->isConstexpr()) DiagDecl = CD = Inherited; } @@ -4853,7 +4900,7 @@ public: return false; This = &ThisVal; Args = Args.slice(1); - } else if (MD && MD->isLambdaStaticInvoker()) { + } else if (MD && MD->isLambdaStaticInvoker()) { // Map the static invoker for the lambda back to the call operator. // Conveniently, we don't have to slice out the 'this' argument (as is // being done for the non-static case), since a static member function @@ -4888,7 +4935,7 @@ public: FD = LambdaCallOp; } - + } else return Error(E); @@ -5732,7 +5779,7 @@ public: // Update 'Result' to refer to the data member/field of the closure object // that represents the '*this' capture. if (!HandleLValueMember(Info, E, Result, - Info.CurrentCall->LambdaThisCaptureField)) + Info.CurrentCall->LambdaThisCaptureField)) return false; // If we captured '*this' by reference, replace the field with its referent. if (Info.CurrentCall->LambdaThisCaptureField->getType() @@ -6117,6 +6164,130 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return ZeroInitialization(E); } + case Builtin::BImemcpy: + case Builtin::BImemmove: + case Builtin::BIwmemcpy: + case Builtin::BIwmemmove: + if (Info.getLangOpts().CPlusPlus11) + Info.CCEDiag(E, diag::note_constexpr_invalid_function) + << /*isConstexpr*/0 << /*isConstructor*/0 + << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'"); + else + Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); + LLVM_FALLTHROUGH; + case Builtin::BI__builtin_memcpy: + case Builtin::BI__builtin_memmove: + case Builtin::BI__builtin_wmemcpy: + case Builtin::BI__builtin_wmemmove: { + bool WChar = BuiltinOp == Builtin::BIwmemcpy || + BuiltinOp == Builtin::BIwmemmove || + BuiltinOp == Builtin::BI__builtin_wmemcpy || + BuiltinOp == Builtin::BI__builtin_wmemmove; + bool Move = BuiltinOp == Builtin::BImemmove || + BuiltinOp == Builtin::BIwmemmove || + BuiltinOp == Builtin::BI__builtin_memmove || + BuiltinOp == Builtin::BI__builtin_wmemmove; + + // The result of mem* is the first argument. + if (!Visit(E->getArg(0))) + return false; + LValue Dest = Result; + + LValue Src; + if (!EvaluatePointer(E->getArg(1), Src, Info)) + return false; + + APSInt N; + if (!EvaluateInteger(E->getArg(2), N, Info)) + return false; + assert(!N.isSigned() && "memcpy and friends take an unsigned size"); + + // If the size is zero, we treat this as always being a valid no-op. + // (Even if one of the src and dest pointers is null.) + if (!N) + return true; + + // We require that Src and Dest are both pointers to arrays of + // trivially-copyable type. (For the wide version, the designator will be + // invalid if the designated object is not a wchar_t.) + QualType T = Dest.Designator.getType(Info.Ctx); + QualType SrcT = Src.Designator.getType(Info.Ctx); + if (!Info.Ctx.hasSameUnqualifiedType(T, SrcT)) { + Info.FFDiag(E, diag::note_constexpr_memcpy_type_pun) << Move << SrcT << T; + return false; + } + if (!T.isTriviallyCopyableType(Info.Ctx)) { + Info.FFDiag(E, diag::note_constexpr_memcpy_nontrivial) << Move << T; + return false; + } + + // Figure out how many T's we're copying. + uint64_t TSize = Info.Ctx.getTypeSizeInChars(T).getQuantity(); + if (!WChar) { + uint64_t Remainder; + llvm::APInt OrigN = N; + llvm::APInt::udivrem(OrigN, TSize, N, Remainder); + if (Remainder) { + Info.FFDiag(E, diag::note_constexpr_memcpy_unsupported) + << Move << WChar << 0 << T << OrigN.toString(10, /*Signed*/false) + << (unsigned)TSize; + return false; + } + } + + // Check that the copying will remain within the arrays, just so that we + // can give a more meaningful diagnostic. This implicitly also checks that + // N fits into 64 bits. + uint64_t RemainingSrcSize = Src.Designator.validIndexAdjustments().second; + uint64_t RemainingDestSize = Dest.Designator.validIndexAdjustments().second; + if (N.ugt(RemainingSrcSize) || N.ugt(RemainingDestSize)) { + Info.FFDiag(E, diag::note_constexpr_memcpy_unsupported) + << Move << WChar << (N.ugt(RemainingSrcSize) ? 1 : 2) << T + << N.toString(10, /*Signed*/false); + return false; + } + uint64_t NElems = N.getZExtValue(); + uint64_t NBytes = NElems * TSize; + + // Check for overlap. + int Direction = 1; + if (HasSameBase(Src, Dest)) { + uint64_t SrcOffset = Src.getLValueOffset().getQuantity(); + uint64_t DestOffset = Dest.getLValueOffset().getQuantity(); + if (DestOffset >= SrcOffset && DestOffset - SrcOffset < NBytes) { + // Dest is inside the source region. + if (!Move) { + Info.FFDiag(E, diag::note_constexpr_memcpy_overlap) << WChar; + return false; + } + // For memmove and friends, copy backwards. + if (!HandleLValueArrayAdjustment(Info, E, Src, T, NElems - 1) || + !HandleLValueArrayAdjustment(Info, E, Dest, T, NElems - 1)) + return false; + Direction = -1; + } else if (!Move && SrcOffset >= DestOffset && + SrcOffset - DestOffset < NBytes) { + // Src is inside the destination region for memcpy: invalid. + Info.FFDiag(E, diag::note_constexpr_memcpy_overlap) << WChar; + return false; + } + } + + while (true) { + APValue Val; + if (!handleLValueToRValueConversion(Info, E, T, Src, Val) || + !handleAssignment(Info, E, Dest, T, Val)) + return false; + // Do not iterate past the last element; if we're copying backwards, that + // might take us off the start of the array. + if (--NElems == 0) + return true; + if (!HandleLValueArrayAdjustment(Info, E, Src, T, Direction) || + !HandleLValueArrayAdjustment(Info, E, Dest, T, Direction)) + return false; + } + } + default: return visitNonBuiltinCallExpr(E); } @@ -6583,7 +6754,7 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) { if (ClosureClass->isInvalidDecl()) return false; if (Info.checkingPotentialConstantExpression()) return true; - + const size_t NumFields = std::distance(ClosureClass->field_begin(), ClosureClass->field_end()); @@ -6602,7 +6773,7 @@ bool RecordExprEvaluator::VisitLambdaExpr(const LambdaExpr *E) { assert(CaptureInitIt != E->capture_init_end()); // Get the initializer for this field Expr *const CurFieldInit = *CaptureInitIt++; - + // If there is no initializer, either this is a VLA or an error has // occurred. if (!CurFieldInit) @@ -6802,18 +6973,18 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // The number of initializers can be less than the number of // vector elements. For OpenCL, this can be due to nested vector - // initialization. For GCC compatibility, missing trailing elements + // initialization. For GCC compatibility, missing trailing elements // should be initialized with zeroes. unsigned CountInits = 0, CountElts = 0; while (CountElts < NumElements) { // Handle nested vector initialization. - if (CountInits < NumInits + if (CountInits < NumInits && E->getInit(CountInits)->getType()->isVectorType()) { APValue v; if (!EvaluateVector(E->getInit(CountInits), v, Info)) return Error(E); unsigned vlen = v.getVectorLength(); - for (unsigned j = 0; j < vlen; j++) + for (unsigned j = 0; j < vlen; j++) Elements.push_back(v.getVectorElt(j)); CountElts += vlen; } else if (EltTy->isIntegerType()) { @@ -7108,7 +7279,7 @@ public: } bool Success(const llvm::APInt &I, const Expr *E, APValue &Result) { - assert(E->getType()->isIntegralOrEnumerationType() && + assert(E->getType()->isIntegralOrEnumerationType() && "Invalid evaluation result."); assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && "Invalid evaluation result."); @@ -7198,7 +7369,7 @@ public: } return Success(Info.ArrayInitIndex, E); } - + // Note, GNU defines __null as an integer, not a pointer. bool VisitGNUNullExpr(const GNUNullExpr *E) { return ZeroInitialization(E); @@ -8357,27 +8528,6 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, } } -static bool HasSameBase(const LValue &A, const LValue &B) { - if (!A.getLValueBase()) - return !B.getLValueBase(); - if (!B.getLValueBase()) - return false; - - if (A.getLValueBase().getOpaqueValue() != - B.getLValueBase().getOpaqueValue()) { - const Decl *ADecl = GetLValueBaseDecl(A); - if (!ADecl) - return false; - const Decl *BDecl = GetLValueBaseDecl(B); - if (!BDecl || ADecl->getCanonicalDecl() != BDecl->getCanonicalDecl()) - return false; - } - - return IsGlobalLValue(A.getLValueBase()) || - (A.getLValueCallIndex() == B.getLValueCallIndex() && - A.getLValueVersion() == B.getLValueVersion()); -} - /// Determine whether this is a pointer past the end of the complete /// object referred to by the lvalue. static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx, @@ -8585,12 +8735,12 @@ bool DataRecursiveIntBinOpEvaluator:: Result = RHSResult.Val; return true; } - + if (E->isLogicalOp()) { bool lhsResult, rhsResult; bool LHSIsOK = HandleConversionToBool(LHSResult.Val, lhsResult); bool RHSIsOK = HandleConversionToBool(RHSResult.Val, rhsResult); - + if (LHSIsOK) { if (RHSIsOK) { if (E->getOpcode() == BO_LOr) @@ -8606,26 +8756,26 @@ bool DataRecursiveIntBinOpEvaluator:: return Success(rhsResult, E, Result); } } - + return false; } - + assert(E->getLHS()->getType()->isIntegralOrEnumerationType() && E->getRHS()->getType()->isIntegralOrEnumerationType()); - + if (LHSResult.Failed || RHSResult.Failed) return false; - + const APValue &LHSVal = LHSResult.Val; const APValue &RHSVal = RHSResult.Val; - + // Handle cases like (unsigned long)&a + 4. if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) { Result = LHSVal; addOrSubLValueAsInteger(Result, RHSVal.getInt(), E->getOpcode() == BO_Sub); return true; } - + // Handle cases like 4 + (unsigned long)&a if (E->getOpcode() == BO_Add && RHSVal.isLValue() && LHSVal.isInt()) { @@ -8633,7 +8783,7 @@ bool DataRecursiveIntBinOpEvaluator:: addOrSubLValueAsInteger(Result, LHSVal.getInt(), /*IsSub*/false); return true; } - + if (E->getOpcode() == BO_Sub && LHSVal.isLValue() && RHSVal.isLValue()) { // Handle (intptr_t)&&A - (intptr_t)&&B. if (!LHSVal.getLValueOffset().isZero() || @@ -8672,7 +8822,7 @@ bool DataRecursiveIntBinOpEvaluator:: void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { Job &job = Queue.back(); - + switch (job.Kind) { case Job::AnyExprKind: { if (const BinaryOperator *Bop = dyn_cast<BinaryOperator>(job.E)) { @@ -8682,12 +8832,12 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { return; } } - + EvaluateExpr(job.E, Result); Queue.pop_back(); return; } - + case Job::BinOpKind: { const BinaryOperator *Bop = cast<BinaryOperator>(job.E); bool SuppressRHSDiags = false; @@ -8702,7 +8852,7 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { enqueue(Bop->getRHS()); return; } - + case Job::BinOpVisitedLHSKind: { const BinaryOperator *Bop = cast<BinaryOperator>(job.E); EvalResult RHS; @@ -8712,7 +8862,7 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { return; } } - + llvm_unreachable("Invalid Job::Kind!"); } @@ -9299,7 +9449,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { const RecordType *BaseRT = CurrentType->getAs<RecordType>(); if (!BaseRT) return Error(OOE); - + // Add the offset to the base. Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())); break; @@ -10531,7 +10681,7 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result, IsConst = false; return true; } - + // FIXME: Evaluating values of large array and record types can cause // performance problems. Only do so in C++11 for now. if (Exp->isRValue() && (Exp->getType()->isArrayType() || @@ -10553,7 +10703,7 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const { bool IsConst; if (FastEvaluateAsRValue(this, Result, Ctx, IsConst)) return IsConst; - + EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); return ::EvaluateAsRValue(Info, this, Result.Val); } |