r363488 - [clang] perform semantic checking in constant context
Gauthier Harnisch via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 15 01:32:56 PDT 2019
Author: tyker
Date: Sat Jun 15 01:32:56 2019
New Revision: 363488
URL: http://llvm.org/viewvc/llvm-project?rev=363488&view=rev
Log:
[clang] perform semantic checking in constant context
Summary:
Since the addition of __builtin_is_constant_evaluated the result of an expression can change based on whether it is evaluated in constant context. a lot of semantic checking performs evaluations with out specifying context. which can lead to wrong diagnostics.
for example:
```
constexpr int i0 = (long long)__builtin_is_constant_evaluated() * (1ll << 33); //#1
constexpr int i1 = (long long)!__builtin_is_constant_evaluated() * (1ll << 33); //#2
```
before the patch, #2 was diagnosed incorrectly and #1 wasn't diagnosed.
after the patch #1 is diagnosed as it should and #2 isn't.
Changes:
- add a flag to Sema to passe in constant context mode.
- in SemaChecking.cpp calls to Expr::Evaluate* are now done in constant context when they should.
- in SemaChecking.cpp diagnostics for UB are not checked for in constant context because an error will be emitted by the constant evaluator.
- in SemaChecking.cpp diagnostics for construct that cannot appear in constant context are not checked for in constant context.
- in SemaChecking.cpp diagnostics on constant expression are always emitted because constant expression are always evaluated.
- semantic checking for initialization of constexpr variables is now done in constant context.
- adapt test that were depending on warning changes.
- add test.
Reviewers: rsmith
Reviewed By: rsmith
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D62009
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/lib/Sema/Sema.cpp
cfe/trunk/lib/Sema/SemaChecking.cpp
cfe/trunk/test/SemaCXX/attr-nonnull.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=363488&r1=363487&r2=363488&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Sat Jun 15 01:32:56 2019
@@ -599,7 +599,8 @@ public:
/// 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 @@ public:
/// 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 @@ public:
/// 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
Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=363488&r1=363487&r2=363488&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Sat Jun 15 01:32:56 2019
@@ -85,6 +85,8 @@ def note_constexpr_past_end_subobject :
"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|"
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=363488&r1=363487&r2=363488&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Jun 15 01:32:56 2019
@@ -797,6 +797,15 @@ public:
}
};
+ /// 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 {
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=363488&r1=363487&r2=363488&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sat Jun 15 01:32:56 2019
@@ -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 <cstring>
@@ -5091,9 +5092,25 @@ typedef SmallVector<APValue, 8> ArgVecto
}
/// EvaluateArgs - Evaluate the arguments to a function call.
-static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
- EvalInfo &Info) {
+static bool EvaluateArgs(ArrayRef<const Expr *> Args, ArgVector &ArgValues,
+ EvalInfo &Info, const FunctionDecl *Callee) {
bool Success = true;
+ llvm::SmallBitVector ForbiddenNullArgs;
+ if (Callee->hasAttr<NonNullAttr>()) {
+ ForbiddenNullArgs.resize(Args.size());
+ for (const auto *Attr : Callee->specific_attrs<NonNullAttr>()) {
+ 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<const Expr*>::iterator I = Args.begin(), E = Args.end();
I != E; ++I) {
if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) {
@@ -5102,6 +5119,13 @@ static bool EvaluateArgs(ArrayRef<const
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 @@ static bool HandleFunctionCall(SourceLoc
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 @@ static bool HandleConstructorCall(const
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 @@ bool Expr::EvaluateAsRValue(EvalResult &
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 @@ bool Expr::EvaluateAsFloat(APFloat &Resu
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 @@ bool Expr::EvaluateAsFloat(APFloat &Resu
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 @@ bool Expr::isPotentialConstantExprUneval
// Fabricate a call stack frame to give the arguments a plausible cover story.
ArrayRef<const Expr*> 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");
Modified: cfe/trunk/lib/Sema/Sema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.cpp?rev=363488&r1=363487&r2=363488&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.cpp (original)
+++ cfe/trunk/lib/Sema/Sema.cpp Sat Jun 15 01:32:56 2019
@@ -158,6 +158,7 @@ Sema::Sema(Preprocessor &pp, ASTContext
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)
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=363488&r1=363487&r2=363488&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Sat Jun 15 01:32:56 2019
@@ -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 <algorithm>
#include <cassert>
@@ -307,7 +308,8 @@ void Sema::checkFortifiedBuiltinMemoryFu
// - 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 @@ static void CheckNonNullArgument(Sema &S
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 @@ static void CheckNonNullArguments(Sema &
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 @@ bool Sema::SemaBuiltinConstantArg(CallEx
/// 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 @@ checkFormatStringExpr(Sema &S, const Exp
llvm::SmallBitVector &CheckedVarArgs,
UncoveredArgHandler &UncoveredArg,
llvm::APSInt Offset) {
+ if (S.isConstantEvaluated())
+ return SLCT_NotALiteral;
tryAgain:
assert(Offset.isSigned() && "invalid offset");
@@ -6594,7 +6604,8 @@ checkFormatStringExpr(Sema &S, const Exp
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 @@ checkFormatStringExpr(Sema &S, const Exp
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 @@ checkFormatStringExpr(Sema &S, const Exp
auto ASE = dyn_cast<ArraySubscriptExpr>(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 @@ static QualType GetExprType(const Expr *
/// 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 @@ static IntRange GetExprRange(ASTContext
// being of the new, wider type.
if (const auto *CE = dyn_cast<ImplicitCastExpr>(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 @@ static IntRange GetExprRange(ASTContext
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 @@ static IntRange GetExprRange(ASTContext
// 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 @@ static IntRange GetExprRange(ASTContext
// 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 @@ static IntRange GetExprRange(ASTContext
// 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 @@ static IntRange GetExprRange(ASTContext
// 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 @@ static IntRange GetExprRange(ASTContext
// 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 @@ static IntRange GetExprRange(ASTContext
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 @@ static IntRange GetExprRange(ASTContext
}
// 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 @@ static IntRange GetExprRange(ASTContext
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 @@ static IntRange GetExprRange(ASTContext
// 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 @@ static IntRange GetExprRange(ASTContext
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<OpaqueValueExpr>(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 @@ static IntRange GetExprRange(ASTContext
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 @@ static bool CheckTautologicalComparison(
// 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 @@ static void AnalyzeComparison(Sema &S, B
}
// 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 @@ static void AnalyzeComparison(Sema &S, B
// 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 @@ static void AnalyzeComparison(Sema &S, B
}
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 @@ static void DiagnoseImpCast(Sema &S, Exp
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 @@ CheckImplicitConversion(Sema &S, Expr *E
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 @@ CheckImplicitConversion(Sema &S, Expr *E
}
} 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 @@ CheckImplicitConversion(Sema &S, Expr *E
} 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 @@ CheckImplicitConversion(Sema &S, Expr *E
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 @@ CheckImplicitConversion(Sema &S, Expr *E
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 @@ class SequenceChecker : public Evaluated
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::CheckUnsequencedOperations(Ex
void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc,
bool IsConstexpr) {
+ llvm::SaveAndRestore<bool> ConstantContext(
+ isConstantEvaluatedOverride, IsConstexpr || isa<ConstantExpr>(E));
CheckImplicitConversions(E, CheckLoc);
if (!E->isInstantiationDependent())
CheckUnsequencedOperations(E);
@@ -12684,6 +12713,10 @@ static bool IsTailPaddedMemberArray(Sema
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 @@ static bool isLayoutCompatible(ASTContex
/// \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 @@ static bool FindTypeTagExpr(const Expr *
const AbstractConditionalOperator *ACO =
cast<AbstractConditionalOperator>(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 @@ static bool FindTypeTagExpr(const Expr *
///
/// \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<Sema::TypeTagMagicValue,
- Sema::TypeTagData> *MagicValues,
- bool &FoundWrongKind,
- Sema::TypeTagData &TypeInfo) {
+ const IdentifierInfo *ArgumentKind, const Expr *TypeExpr,
+ const ASTContext &Ctx,
+ const llvm::DenseMap<Sema::TypeTagMagicValue, Sema::TypeTagData>
+ *MagicValues,
+ bool &FoundWrongKind, Sema::TypeTagData &TypeInfo,
+ bool isConstantEvaluated) {
FoundWrongKind = false;
// Variable declaration that has type_tag_for_datatype attribute.
@@ -13911,7 +13953,7 @@ static bool GetMatchingCType(
uint64_t MagicValue;
- if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue))
+ if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue, isConstantEvaluated))
return false;
if (VD) {
@@ -13989,8 +14031,8 @@ void Sema::CheckArgumentWithTypeTag(cons
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)
Modified: cfe/trunk/test/SemaCXX/attr-nonnull.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/attr-nonnull.cpp?rev=363488&r1=363487&r2=363488&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/attr-nonnull.cpp (original)
+++ cfe/trunk/test/SemaCXX/attr-nonnull.cpp Sat Jun 15 01:32:56 2019
@@ -52,3 +52,35 @@ void test(const X& x) {
(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
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=363488&r1=363487&r2=363488&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Sat Jun 15 01:32:56 2019
@@ -438,8 +438,8 @@ static_assert(MangleChars(U"constexpr!")
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 xs6 = p[3]; // expected-er
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]
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}}
More information about the cfe-commits
mailing list