Index: cfe/trunk/include/clang/AST/Expr.h =================================================================== --- cfe/trunk/include/clang/AST/Expr.h +++ cfe/trunk/include/clang/AST/Expr.h @@ -599,7 +599,8 @@ /// which we can fold and convert to a boolean condition using /// any crazy technique that we want to, even if the expression has /// side-effects. - bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const; + bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, + bool InConstantContext = false) const; enum SideEffectsKind { SE_NoSideEffects, ///< Strictly evaluate the expression. @@ -611,20 +612,21 @@ /// EvaluateAsInt - Return true if this is a constant which we can fold and /// convert to an integer, using any crazy technique that we want to. bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, - SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; + SideEffectsKind AllowSideEffects = SE_NoSideEffects, + bool InConstantContext = false) const; /// EvaluateAsFloat - Return true if this is a constant which we can fold and /// convert to a floating point value, using any crazy technique that we /// want to. - bool - EvaluateAsFloat(llvm::APFloat &Result, const ASTContext &Ctx, - SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; + bool EvaluateAsFloat(llvm::APFloat &Result, const ASTContext &Ctx, + SideEffectsKind AllowSideEffects = SE_NoSideEffects, + bool InConstantContext = false) const; /// EvaluateAsFloat - Return true if this is a constant which we can fold and /// convert to a fixed point value. - bool EvaluateAsFixedPoint( - EvalResult &Result, const ASTContext &Ctx, - SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; + bool EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx, + SideEffectsKind AllowSideEffects = SE_NoSideEffects, + bool InConstantContext = false) const; /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be /// constant folded without side-effects, but discard the result. @@ -660,7 +662,8 @@ /// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an /// lvalue with link time known address, with no side-effects. - bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const; + bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx, + bool InConstantContext = false) const; /// EvaluateAsInitializer - Evaluate an expression as if it were the /// initializer of the given declaration. Returns true if the initializer Index: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td @@ -85,6 +85,8 @@ "access array element of|ERROR|" "access real component of|access imaginary component of}0 " "pointer past the end of object">; +def note_non_null_attribute_failed : Note< + "null passed to a callee that requires a non-null argument">; def note_constexpr_null_subobject : Note< "cannot %select{access base class of|access derived class of|access field of|" "access array element of|perform pointer arithmetic on|" Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -797,6 +797,15 @@ } }; + /// Used to change context to isConstantEvaluated without pushing a heavy + /// ExpressionEvaluationContextRecord object. + bool isConstantEvaluatedOverride; + + bool isConstantEvaluated() { + return ExprEvalContexts.back().isConstantEvaluated() || + isConstantEvaluatedOverride; + } + /// RAII object to handle the state changes required to synthesize /// a function body. class SynthesizedFunctionScope { Index: cfe/trunk/lib/AST/ExprConstant.cpp =================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp +++ cfe/trunk/lib/AST/ExprConstant.cpp @@ -47,6 +47,7 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/FixedPoint.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" #include @@ -5091,9 +5092,25 @@ } /// EvaluateArgs - Evaluate the arguments to a function call. -static bool EvaluateArgs(ArrayRef Args, ArgVector &ArgValues, - EvalInfo &Info) { +static bool EvaluateArgs(ArrayRef Args, ArgVector &ArgValues, + EvalInfo &Info, const FunctionDecl *Callee) { bool Success = true; + llvm::SmallBitVector ForbiddenNullArgs; + if (Callee->hasAttr()) { + ForbiddenNullArgs.resize(Args.size()); + for (const auto *Attr : Callee->specific_attrs()) { + if (!Attr->args_size()) { + ForbiddenNullArgs.set(); + break; + } else + for (auto Idx : Attr->args()) { + unsigned ASTIdx = Idx.getASTIndex(); + if (ASTIdx >= Args.size()) + continue; + ForbiddenNullArgs[ASTIdx] = 1; + } + } + } for (ArrayRef::iterator I = Args.begin(), E = Args.end(); I != E; ++I) { if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) { @@ -5102,6 +5119,13 @@ if (!Info.noteFailure()) return false; Success = false; + } else if (!ForbiddenNullArgs.empty() && + ForbiddenNullArgs[I - Args.begin()] && + ArgValues[I - Args.begin()].isNullPointer()) { + Info.CCEDiag(*I, diag::note_non_null_attribute_failed); + if (!Info.noteFailure()) + return false; + Success = false; } } return Success; @@ -5114,7 +5138,7 @@ EvalInfo &Info, APValue &Result, const LValue *ResultSlot) { ArgVector ArgValues(Args.size()); - if (!EvaluateArgs(Args, ArgValues, Info)) + if (!EvaluateArgs(Args, ArgValues, Info, Callee)) return false; if (!Info.CheckCallLimit(CallLoc)) @@ -5338,7 +5362,7 @@ const CXXConstructorDecl *Definition, EvalInfo &Info, APValue &Result) { ArgVector ArgValues(Args.size()); - if (!EvaluateArgs(Args, ArgValues, Info)) + if (!EvaluateArgs(Args, ArgValues, Info, Definition)) return false; return HandleConstructorCall(E, This, ArgValues.data(), Definition, @@ -11855,33 +11879,38 @@ return ::EvaluateAsRValue(this, Result, Ctx, Info); } -bool Expr::EvaluateAsBooleanCondition(bool &Result, - const ASTContext &Ctx) const { +bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx, + bool InConstantContext) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); EvalResult Scratch; - return EvaluateAsRValue(Scratch, Ctx) && + return EvaluateAsRValue(Scratch, Ctx, InConstantContext) && HandleConversionToBool(Scratch.Val, Result); } bool Expr::EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, - SideEffectsKind AllowSideEffects) const { + SideEffectsKind AllowSideEffects, + bool InConstantContext) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); + Info.InConstantContext = InConstantContext; return ::EvaluateAsInt(this, Result, Ctx, AllowSideEffects, Info); } bool Expr::EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx, - SideEffectsKind AllowSideEffects) const { + SideEffectsKind AllowSideEffects, + bool InConstantContext) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); + Info.InConstantContext = InConstantContext; return ::EvaluateAsFixedPoint(this, Result, Ctx, AllowSideEffects, Info); } bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx, - SideEffectsKind AllowSideEffects) const { + SideEffectsKind AllowSideEffects, + bool InConstantContext) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); @@ -11889,7 +11918,8 @@ return false; EvalResult ExprResult; - if (!EvaluateAsRValue(ExprResult, Ctx) || !ExprResult.Val.isFloat() || + if (!EvaluateAsRValue(ExprResult, Ctx, InConstantContext) || + !ExprResult.Val.isFloat() || hasUnacceptableSideEffect(ExprResult, AllowSideEffects)) return false; @@ -11897,12 +11927,13 @@ return true; } -bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { +bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx, + bool InConstantContext) const { assert(!isValueDependent() && "Expression evaluator can't be called on a dependent expression."); EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold); - + Info.InConstantContext = InConstantContext; LValue LV; if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects || !CheckLValueConstantExpression(Info, getExprLoc(), @@ -12685,7 +12716,7 @@ // Fabricate a call stack frame to give the arguments a plausible cover story. ArrayRef Args; ArgVector ArgValues(0); - bool Success = EvaluateArgs(Args, ArgValues, Info); + bool Success = EvaluateArgs(Args, ArgValues, Info, FD); (void)Success; assert(Success && "Failed to set up arguments for potential constant evaluation"); Index: cfe/trunk/lib/Sema/Sema.cpp =================================================================== --- cfe/trunk/lib/Sema/Sema.cpp +++ cfe/trunk/lib/Sema/Sema.cpp @@ -158,6 +158,7 @@ ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr), CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) { TUScope = nullptr; + isConstantEvaluatedOverride = false; LoadedExternalKnownNamespaces = false; for (unsigned I = 0; I != NSAPI::NumNSNumberLiteralMethods; ++I) Index: cfe/trunk/lib/Sema/SemaChecking.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp +++ cfe/trunk/lib/Sema/SemaChecking.cpp @@ -84,6 +84,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/Locale.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -307,7 +308,8 @@ // - Analyze the format string of sprintf to see how much of buffer is used. // - Evaluate strlen of strcpy arguments, use as object size. - if (TheCall->isValueDependent() || TheCall->isTypeDependent()) + if (TheCall->isValueDependent() || TheCall->isTypeDependent() || + isConstantEvaluated()) return; unsigned BuiltinID = FD->getBuiltinID(/*ConsiderWrappers=*/true); @@ -4059,7 +4061,8 @@ SourceLocation CallSiteLoc) { if (CheckNonNullExpr(S, ArgExpr)) S.DiagRuntimeBehavior(CallSiteLoc, ArgExpr, - S.PDiag(diag::warn_null_arg) << ArgExpr->getSourceRange()); + S.PDiag(diag::warn_null_arg) + << ArgExpr->getSourceRange()); } bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { @@ -4129,6 +4132,9 @@ SourceLocation CallSiteLoc) { assert((FDecl || Proto) && "Need a function declaration or prototype"); + // Already checked by by constant evaluator. + if (S.isConstantEvaluated()) + return; // Check the attributes attached to the method/function itself. llvm::SmallBitVector NonNullArgs; if (FDecl) { @@ -6059,6 +6065,8 @@ /// TheCall is a constant expression in the range [Low, High]. bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High, bool RangeIsError) { + if (isConstantEvaluated()) + return false; llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -6565,6 +6573,8 @@ llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, llvm::APSInt Offset) { + if (S.isConstantEvaluated()) + return SLCT_NotALiteral; tryAgain: assert(Offset.isSigned() && "invalid offset"); @@ -6594,7 +6604,8 @@ bool CheckLeft = true, CheckRight = true; bool Cond; - if (C->getCond()->EvaluateAsBooleanCondition(Cond, S.getASTContext())) { + if (C->getCond()->EvaluateAsBooleanCondition(Cond, S.getASTContext(), + S.isConstantEvaluated())) { if (Cond) CheckRight = false; else @@ -6795,8 +6806,10 @@ if (BinOp->isAdditiveOp()) { Expr::EvalResult LResult, RResult; - bool LIsInt = BinOp->getLHS()->EvaluateAsInt(LResult, S.Context); - bool RIsInt = BinOp->getRHS()->EvaluateAsInt(RResult, S.Context); + bool LIsInt = BinOp->getLHS()->EvaluateAsInt( + LResult, S.Context, Expr::SE_NoSideEffects, S.isConstantEvaluated()); + bool RIsInt = BinOp->getRHS()->EvaluateAsInt( + RResult, S.Context, Expr::SE_NoSideEffects, S.isConstantEvaluated()); if (LIsInt != RIsInt) { BinaryOperatorKind BinOpKind = BinOp->getOpcode(); @@ -6822,7 +6835,9 @@ auto ASE = dyn_cast(UnaOp->getSubExpr()); if (UnaOp->getOpcode() == UO_AddrOf && ASE) { Expr::EvalResult IndexResult; - if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context)) { + if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context, + Expr::SE_NoSideEffects, + S.isConstantEvaluated())) { sumOffsets(Offset, IndexResult.Val.getInt(), BO_Add, /*RHS is int*/ true); E = ASE->getBase(); @@ -9902,12 +9917,13 @@ /// range of values it might take. /// /// \param MaxWidth - the width to which the value will be truncated -static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { +static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, + bool InConstantContext) { E = E->IgnoreParens(); // Try a full evaluation first. Expr::EvalResult result; - if (E->EvaluateAsRValue(result, C)) + if (E->EvaluateAsRValue(result, C, InConstantContext)) return GetValueRange(C, result.Val, GetExprType(E), MaxWidth); // I think we only want to look through implicit casts here; if the @@ -9915,7 +9931,7 @@ // being of the new, wider type. if (const auto *CE = dyn_cast(E)) { if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue) - return GetExprRange(C, CE->getSubExpr(), MaxWidth); + return GetExprRange(C, CE->getSubExpr(), MaxWidth, InConstantContext); IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE)); @@ -9926,9 +9942,9 @@ if (!isIntegerCast) return OutputTypeRange; - IntRange SubRange - = GetExprRange(C, CE->getSubExpr(), - std::min(MaxWidth, OutputTypeRange.Width)); + IntRange SubRange = GetExprRange(C, CE->getSubExpr(), + std::min(MaxWidth, OutputTypeRange.Width), + InConstantContext); // Bail out if the subexpr's range is as wide as the cast type. if (SubRange.Width >= OutputTypeRange.Width) @@ -9944,13 +9960,15 @@ // If we can fold the condition, just take that operand. bool CondResult; if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C)) - return GetExprRange(C, CondResult ? CO->getTrueExpr() - : CO->getFalseExpr(), - MaxWidth); + return GetExprRange(C, + CondResult ? CO->getTrueExpr() : CO->getFalseExpr(), + MaxWidth, InConstantContext); // Otherwise, conservatively merge. - IntRange L = GetExprRange(C, CO->getTrueExpr(), MaxWidth); - IntRange R = GetExprRange(C, CO->getFalseExpr(), MaxWidth); + IntRange L = + GetExprRange(C, CO->getTrueExpr(), MaxWidth, InConstantContext); + IntRange R = + GetExprRange(C, CO->getFalseExpr(), MaxWidth, InConstantContext); return IntRange::join(L, R); } @@ -9986,7 +10004,7 @@ // been coerced to the LHS type. case BO_Assign: // TODO: bitfields? - return GetExprRange(C, BO->getRHS(), MaxWidth); + return GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext); // Operations with opaque sources are black-listed. case BO_PtrMemD: @@ -9996,8 +10014,9 @@ // Bitwise-and uses the *infinum* of the two source ranges. case BO_And: case BO_AndAssign: - return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth), - GetExprRange(C, BO->getRHS(), MaxWidth)); + return IntRange::meet( + GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext), + GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext)); // Left shift gets black-listed based on a judgement call. case BO_Shl: @@ -10018,7 +10037,7 @@ // Right shift by a constant can narrow its left argument. case BO_Shr: case BO_ShrAssign: { - IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); + IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext); // If the shift amount is a positive constant, drop the width by // that much. @@ -10037,7 +10056,7 @@ // Comma acts as its right operand. case BO_Comma: - return GetExprRange(C, BO->getRHS(), MaxWidth); + return GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext); // Black-list pointer subtractions. case BO_Sub: @@ -10050,7 +10069,7 @@ case BO_Div: { // Don't 'pre-truncate' the operands. unsigned opWidth = C.getIntWidth(GetExprType(E)); - IntRange L = GetExprRange(C, BO->getLHS(), opWidth); + IntRange L = GetExprRange(C, BO->getLHS(), opWidth, InConstantContext); // If the divisor is constant, use that. llvm::APSInt divisor; @@ -10064,7 +10083,7 @@ } // Otherwise, just use the LHS's width. - IntRange R = GetExprRange(C, BO->getRHS(), opWidth); + IntRange R = GetExprRange(C, BO->getRHS(), opWidth, InConstantContext); return IntRange(L.Width, L.NonNegative && R.NonNegative); } @@ -10073,8 +10092,8 @@ case BO_Rem: { // Don't 'pre-truncate' the operands. unsigned opWidth = C.getIntWidth(GetExprType(E)); - IntRange L = GetExprRange(C, BO->getLHS(), opWidth); - IntRange R = GetExprRange(C, BO->getRHS(), opWidth); + IntRange L = GetExprRange(C, BO->getLHS(), opWidth, InConstantContext); + IntRange R = GetExprRange(C, BO->getRHS(), opWidth, InConstantContext); IntRange meet = IntRange::meet(L, R); meet.Width = std::min(meet.Width, MaxWidth); @@ -10091,8 +10110,8 @@ // The default case is to treat the operation as if it were closed // on the narrowest type that encompasses both operands. - IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); - IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth); + IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth, InConstantContext); + IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth, InConstantContext); return IntRange::join(L, R); } @@ -10108,12 +10127,12 @@ return IntRange::forValueOfType(C, GetExprType(E)); default: - return GetExprRange(C, UO->getSubExpr(), MaxWidth); + return GetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext); } } if (const auto *OVE = dyn_cast(E)) - return GetExprRange(C, OVE->getSourceExpr(), MaxWidth); + return GetExprRange(C, OVE->getSourceExpr(), MaxWidth, InConstantContext); if (const auto *BitField = E->getSourceBitField()) return IntRange(BitField->getBitWidthValue(C), @@ -10122,8 +10141,9 @@ return IntRange::forValueOfType(C, GetExprType(E)); } -static IntRange GetExprRange(ASTContext &C, const Expr *E) { - return GetExprRange(C, E, C.getIntWidth(GetExprType(E))); +static IntRange GetExprRange(ASTContext &C, const Expr *E, + bool InConstantContext) { + return GetExprRange(C, E, C.getIntWidth(GetExprType(E)), InConstantContext); } /// Checks whether the given value, which currently has the given @@ -10411,13 +10431,14 @@ // cases involving boolean values for historical reasons. We should pick a // consistent way of presenting these diagnostics. if (!InRange || Other->isKnownToHaveBooleanValue()) { + S.DiagRuntimeBehavior( - E->getOperatorLoc(), E, - S.PDiag(!InRange ? diag::warn_out_of_range_compare - : diag::warn_tautological_bool_compare) - << OS.str() << classifyConstantValue(Constant) - << OtherT << OtherIsBooleanDespiteType << *Result - << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange()); + E->getOperatorLoc(), E, + S.PDiag(!InRange ? diag::warn_out_of_range_compare + : diag::warn_tautological_bool_compare) + << OS.str() << classifyConstantValue(Constant) << OtherT + << OtherIsBooleanDespiteType << *Result + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange()); } else { unsigned Diag = (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0) ? (HasEnumType(OriginalOther) @@ -10521,7 +10542,8 @@ } // Otherwise, calculate the effective range of the signed operand. - IntRange signedRange = GetExprRange(S.Context, signedOperand); + IntRange signedRange = + GetExprRange(S.Context, signedOperand, S.isConstantEvaluated()); // Go ahead and analyze implicit conversions in the operands. Note // that we skip the implicit conversions on both sides. @@ -10538,7 +10560,8 @@ // change the result of the comparison. if (E->isEqualityOp()) { unsigned comparisonWidth = S.Context.getIntWidth(T); - IntRange unsignedRange = GetExprRange(S.Context, unsignedOperand); + IntRange unsignedRange = + GetExprRange(S.Context, unsignedOperand, S.isConstantEvaluated()); // We should never be unable to prove that the unsigned operand is // non-negative. @@ -10549,9 +10572,9 @@ } S.DiagRuntimeBehavior(E->getOperatorLoc(), E, - S.PDiag(diag::warn_mixed_sign_comparison) - << LHS->getType() << RHS->getType() - << LHS->getSourceRange() << RHS->getSourceRange()); + S.PDiag(diag::warn_mixed_sign_comparison) + << LHS->getType() << RHS->getType() + << LHS->getSourceRange() << RHS->getSourceRange()); } /// Analyzes an attempt to assign the given value to a bitfield. @@ -10719,8 +10742,8 @@ if (pruneControlFlow) { S.DiagRuntimeBehavior(E->getExprLoc(), E, S.PDiag(diag) - << SourceType << T << E->getSourceRange() - << SourceRange(CContext)); + << SourceType << T << E->getSourceRange() + << SourceRange(CContext)); return; } S.Diag(E->getExprLoc(), diag) @@ -11255,8 +11278,8 @@ if (Source->isFixedPointType()) { if (Target->isUnsaturatedFixedPointType()) { Expr::EvalResult Result; - if (E->EvaluateAsFixedPoint(Result, S.Context, - Expr::SE_AllowSideEffects)) { + if (E->EvaluateAsFixedPoint(Result, S.Context, Expr::SE_AllowSideEffects, + S.isConstantEvaluated())) { APFixedPoint Value = Result.Val.getFixedPoint(); APFixedPoint MaxVal = S.Context.getFixedPointMax(T); APFixedPoint MinVal = S.Context.getFixedPointMin(T); @@ -11271,7 +11294,8 @@ } } else if (Target->isIntegerType()) { Expr::EvalResult Result; - if (E->EvaluateAsFixedPoint(Result, S.Context, + if (!S.isConstantEvaluated() && + E->EvaluateAsFixedPoint(Result, S.Context, Expr::SE_AllowSideEffects)) { APFixedPoint FXResult = Result.Val.getFixedPoint(); @@ -11293,7 +11317,8 @@ } else if (Target->isUnsaturatedFixedPointType()) { if (Source->isIntegerType()) { Expr::EvalResult Result; - if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) { + if (!S.isConstantEvaluated() && + E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) { llvm::APSInt Value = Result.Val.getInt(); bool Overflowed; @@ -11324,14 +11349,15 @@ if (Target->isSpecificBuiltinType(BuiltinType::Bool)) return; - IntRange SourceRange = GetExprRange(S.Context, E); + IntRange SourceRange = GetExprRange(S.Context, E, S.isConstantEvaluated()); IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); if (SourceRange.Width > TargetRange.Width) { // If the source is a constant, use a default-on diagnostic. // TODO: this should happen for bitfield stores, too. Expr::EvalResult Result; - if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects)) { + if (E->EvaluateAsInt(Result, S.Context, Expr::SE_AllowSideEffects, + S.isConstantEvaluated())) { llvm::APSInt Value(32); Value = Result.Val.getInt(); @@ -11341,11 +11367,11 @@ std::string PrettySourceValue = Value.toString(10); std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); - S.DiagRuntimeBehavior(E->getExprLoc(), E, - S.PDiag(diag::warn_impcast_integer_precision_constant) - << PrettySourceValue << PrettyTargetValue - << E->getType() << T << E->getSourceRange() - << clang::SourceRange(CC)); + S.DiagRuntimeBehavior( + E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_integer_precision_constant) + << PrettySourceValue << PrettyTargetValue << E->getType() << T + << E->getSourceRange() << clang::SourceRange(CC)); return; } @@ -12093,7 +12119,8 @@ bool evaluate(const Expr *E, bool &Result) { if (!EvalOK || E->isValueDependent()) return false; - EvalOK = E->EvaluateAsBooleanCondition(Result, Self.SemaRef.Context); + EvalOK = E->EvaluateAsBooleanCondition( + Result, Self.SemaRef.Context, Self.SemaRef.isConstantEvaluated()); return EvalOK; } @@ -12446,6 +12473,8 @@ void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, bool IsConstexpr) { + llvm::SaveAndRestore ConstantContext( + isConstantEvaluatedOverride, IsConstexpr || isa(E)); CheckImplicitConversions(E, CheckLoc); if (!E->isInstantiationDependent()) CheckUnsequencedOperations(E); @@ -12684,6 +12713,10 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE, bool AllowOnePastEnd, bool IndexNegated) { + // Already diagnosed by the constant evaluator. + if (isConstantEvaluated()) + return; + IndexExpr = IndexExpr->IgnoreParenImpCasts(); if (IndexExpr->isValueDependent()) return; @@ -13821,8 +13854,13 @@ /// \param VD Declaration of an identifier that appears in a type tag. /// /// \param MagicValue Type tag magic value. +/// +/// \param isConstantEvaluated wether the evalaution should be performed in + +/// constant context. static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, - const ValueDecl **VD, uint64_t *MagicValue) { + const ValueDecl **VD, uint64_t *MagicValue, + bool isConstantEvaluated) { while(true) { if (!TypeExpr) return false; @@ -13860,7 +13898,8 @@ const AbstractConditionalOperator *ACO = cast(TypeExpr); bool Result; - if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx)) { + if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx, + isConstantEvaluated)) { if (Result) TypeExpr = ACO->getTrueExpr(); else @@ -13896,14 +13935,17 @@ /// /// \param TypeInfo Information about the corresponding C type. /// +/// \param isConstantEvaluated wether the evalaution should be performed in +/// constant context. +/// /// \returns true if the corresponding C type was found. static bool GetMatchingCType( - const IdentifierInfo *ArgumentKind, - const Expr *TypeExpr, const ASTContext &Ctx, - const llvm::DenseMap *MagicValues, - bool &FoundWrongKind, - Sema::TypeTagData &TypeInfo) { + const IdentifierInfo *ArgumentKind, const Expr *TypeExpr, + const ASTContext &Ctx, + const llvm::DenseMap + *MagicValues, + bool &FoundWrongKind, Sema::TypeTagData &TypeInfo, + bool isConstantEvaluated) { FoundWrongKind = false; // Variable declaration that has type_tag_for_datatype attribute. @@ -13911,7 +13953,7 @@ uint64_t MagicValue; - if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue)) + if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue, isConstantEvaluated)) return false; if (VD) { @@ -13989,8 +14031,8 @@ bool FoundWrongKind; TypeTagData TypeInfo; if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context, - TypeTagForDatatypeMagicValues.get(), - FoundWrongKind, TypeInfo)) { + TypeTagForDatatypeMagicValues.get(), FoundWrongKind, + TypeInfo, isConstantEvaluated())) { if (FoundWrongKind) Diag(TypeTagExpr->getExprLoc(), diag::warn_type_tag_for_datatype_wrong_kind) Index: cfe/trunk/test/SemaCXX/attr-nonnull.cpp =================================================================== --- cfe/trunk/test/SemaCXX/attr-nonnull.cpp +++ cfe/trunk/test/SemaCXX/attr-nonnull.cpp @@ -52,3 +52,35 @@ (void)(x != 0); // expected-warning{{null passed}} } } + +namespace test5 { + +constexpr int c = 0; + +__attribute__((nonnull)) +constexpr int f1(const int*, const int*) { + return 0; +} +constexpr int i1 = f1(&c, &c); +constexpr int i12 = f1(&c, 0); //expected-error {{constant expression}} expected-note {{null passed}} + +constexpr int f2(const int*, const int*) { + return 0; +} +constexpr int i2 = f2(0, 0); + +__attribute__((nonnull(2))) +constexpr int f3(const int*, const int*) { + return 0; +} +constexpr int i3 = f3(&c, 0); //expected-error {{constant expression}} expected-note {{null passed}} +constexpr int i32 = f3(0, &c); + +__attribute__((nonnull(4))) __attribute__((nonnull)) //expected-error {{out of bounds}} +constexpr int f4(const int*, const int*) { + return 0; +} +constexpr int i4 = f4(&c, 0); //expected-error {{constant expression}} expected-note {{null passed}} +constexpr int i42 = f4(0, &c); //expected-error {{constant expression}} expected-note {{null passed}} + +} \ No newline at end of file Index: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp =================================================================== --- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp +++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp @@ -438,8 +438,8 @@ constexpr char c0 = "nought index"[0]; constexpr char c1 = "nice index"[10]; -constexpr char c2 = "nasty index"[12]; // expected-error {{must be initialized by a constant expression}} expected-warning {{is past the end}} expected-note {{read of dereferenced one-past-the-end pointer}} -constexpr char c3 = "negative index"[-1]; // expected-error {{must be initialized by a constant expression}} expected-warning {{is before the beginning}} expected-note {{cannot refer to element -1 of array of 15 elements}} +constexpr char c2 = "nasty index"[12]; // expected-error {{must be initialized by a constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}} +constexpr char c3 = "negative index"[-1]; // expected-error {{must be initialized by a constant expression}} expected-note {{cannot refer to element -1 of array of 15 elements}} constexpr char c4 = ((char*)(int*)"no reinterpret_casts allowed")[14]; // expected-error {{must be initialized by a constant expression}} expected-note {{cast that performs the conversions of a reinterpret_cast}} constexpr const char *p = "test" + 2; @@ -547,7 +547,7 @@ constexpr int xs0 = p[-3]; // ok constexpr int xs_1 = p[-4]; // expected-error {{constant expression}} expected-note {{cannot refer to element -1}} -constexpr int zs[2][2][2][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; // expected-note {{array 'zs' declared here}} +constexpr int zs[2][2][2][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; static_assert(zs[0][0][0][0] == 1, ""); static_assert(zs[1][1][1][1] == 16, ""); static_assert(zs[0][0][0][2] == 3, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}} @@ -557,8 +557,7 @@ static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2) == 11, ""); constexpr int err_zs_1_2_0_0 = zs[1][2][0][0]; // \ expected-error {{constant expression}} \ -expected-note {{cannot access array element of pointer past the end}} \ -expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}} +expected-note {{cannot access array element of pointer past the end}} constexpr int fail(const int &p) { return (&p)[64]; // expected-note {{cannot refer to element 64 of array of 2 elements}}