summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/AST/ExprConstant.cpp115
-rw-r--r--clang/lib/Sema/SemaChecking.cpp2
-rw-r--r--clang/test/CXX/expr/expr.const/p2-0x.cpp4
-rw-r--r--clang/test/CodeGen/complex-init-list.c4
-rw-r--r--clang/test/CodeGen/ubsan-conditional.c10
-rw-r--r--clang/test/PCH/floating-literal.c4
-rw-r--r--clang/test/Sema/const-eval.c2
-rw-r--r--clang/test/Sema/integer-overflow.c1
-rw-r--r--clang/test/Sema/switch-1.c3
-rw-r--r--clang/test/SemaCXX/constant-expression-cxx11.cpp7
-rw-r--r--clang/test/SemaCXX/constexpr-printing.cpp4
11 files changed, 92 insertions, 64 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index a4d6a8950e4..d80f466d99f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -473,6 +473,10 @@ namespace {
/// notes attached to it will also be stored, otherwise they will not be.
bool HasActiveDiagnostic;
+ /// \brief Have we emitted a diagnostic explaining why we couldn't constant
+ /// fold (not just why it's not strictly a constant expression)?
+ bool HasFoldFailureDiagnostic;
+
enum EvaluationMode {
/// Evaluate as a constant expression. Stop if we find that the expression
/// is not a constant expression.
@@ -537,7 +541,7 @@ namespace {
BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- EvalMode(Mode) {}
+ HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
EvaluatingDecl = Base;
@@ -597,7 +601,7 @@ namespace {
/// Diagnose that the evaluation cannot be folded.
OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
+ unsigned ExtraNotes = 0, bool IsCCEDiag = false) {
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,
@@ -610,10 +614,9 @@ namespace {
case EM_ConstantFold:
case EM_IgnoreSideEffects:
case EM_EvaluateForOverflow:
- if (!EvalStatus.HasSideEffects)
+ if (!HasFoldFailureDiagnostic)
break;
- // We've had side-effects; we want the diagnostic from them, not
- // some later problem.
+ // We've already failed to fold something. Keep that diagnostic.
case EM_ConstantExpression:
case EM_PotentialConstantExpression:
case EM_ConstantExpressionUnevaluated:
@@ -632,6 +635,7 @@ namespace {
CallStackNotes = 0;
HasActiveDiagnostic = true;
+ HasFoldFailureDiagnostic = !IsCCEDiag;
EvalStatus.Diag->clear();
EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
addDiag(Loc, DiagId);
@@ -645,9 +649,9 @@ namespace {
OptionalDiagnostic Diag(const Expr *E, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
- unsigned ExtraNotes = 0) {
+ unsigned ExtraNotes = 0, bool IsCCEDiag = false) {
if (EvalStatus.Diag)
- return Diag(E->getExprLoc(), DiagId, ExtraNotes);
+ return Diag(E->getExprLoc(), DiagId, ExtraNotes, IsCCEDiag);
HasActiveDiagnostic = false;
return OptionalDiagnostic();
}
@@ -667,7 +671,7 @@ namespace {
HasActiveDiagnostic = false;
return OptionalDiagnostic();
}
- return Diag(Loc, DiagId, ExtraNotes);
+ return Diag(Loc, DiagId, ExtraNotes, true);
}
/// Add a note to a prior diagnostic.
@@ -1541,10 +1545,11 @@ static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result,
}
template<typename T>
-static void HandleOverflow(EvalInfo &Info, const Expr *E,
+static bool HandleOverflow(EvalInfo &Info, const Expr *E,
const T &SrcValue, QualType DestType) {
Info.CCEDiag(E, diag::note_constexpr_overflow)
<< SrcValue << DestType;
+ return Info.noteSideEffect();
}
static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E,
@@ -1558,7 +1563,7 @@ static bool HandleFloatToIntCast(EvalInfo &Info, const Expr *E,
bool ignored;
if (Value.convertToInteger(Result, llvm::APFloat::rmTowardZero, &ignored)
& APFloat::opInvalidOp)
- HandleOverflow(Info, E, Value, DestType);
+ return HandleOverflow(Info, E, Value, DestType);
return true;
}
@@ -1570,7 +1575,7 @@ static bool HandleFloatToFloatCast(EvalInfo &Info, const Expr *E,
if (Result.convert(Info.Ctx.getFloatTypeSemantics(DestType),
APFloat::rmNearestTiesToEven, &ignored)
& APFloat::opOverflow)
- HandleOverflow(Info, E, Value, DestType);
+ return HandleOverflow(Info, E, Value, DestType);
return true;
}
@@ -1593,7 +1598,7 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
if (Result.convertFromAPInt(Value, Value.isSigned(),
APFloat::rmNearestTiesToEven)
& APFloat::opOverflow)
- HandleOverflow(Info, E, Value, DestType);
+ return HandleOverflow(Info, E, Value, DestType);
return true;
}
@@ -1669,23 +1674,26 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
/// bits, and check for overflow in the original type (if that type was not an
/// unsigned type).
template<typename Operation>
-static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
- const APSInt &LHS, const APSInt &RHS,
- unsigned BitWidth, Operation Op) {
- if (LHS.isUnsigned())
- return Op(LHS, RHS);
+static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
+ const APSInt &LHS, const APSInt &RHS,
+ unsigned BitWidth, Operation Op,
+ APSInt &Result) {
+ if (LHS.isUnsigned()) {
+ Result = Op(LHS, RHS);
+ return true;
+ }
APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
- APSInt Result = Value.trunc(LHS.getBitWidth());
+ Result = Value.trunc(LHS.getBitWidth());
if (Result.extend(BitWidth) != Value) {
if (Info.checkingForOverflow())
Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
- diag::warn_integer_constant_overflow)
+ diag::warn_integer_constant_overflow)
<< Result.toString(10) << E->getType();
else
- HandleOverflow(Info, E, Value, E->getType());
+ return HandleOverflow(Info, E, Value, E->getType());
}
- return Result;
+ return true;
}
/// Perform the given binary integer operation.
@@ -1697,17 +1705,14 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
Info.Diag(E);
return false;
case BO_Mul:
- Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2,
- std::multiplies<APSInt>());
- return true;
+ return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2,
+ std::multiplies<APSInt>(), Result);
case BO_Add:
- Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
- std::plus<APSInt>());
- return true;
+ return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
+ std::plus<APSInt>(), Result);
case BO_Sub:
- Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
- std::minus<APSInt>());
- return true;
+ return CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
+ std::minus<APSInt>(), Result);
case BO_And: Result = LHS & RHS; return true;
case BO_Xor: Result = LHS ^ RHS; return true;
case BO_Or: Result = LHS | RHS; return true;
@@ -1717,11 +1722,13 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
Info.Diag(E, diag::note_expr_divide_by_zero);
return false;
}
- // Check for overflow case: INT_MIN / -1 or INT_MIN % -1.
+ Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
+ // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. APSInt supports
+ // this operation and gives the two's complement result.
if (RHS.isNegative() && RHS.isAllOnesValue() &&
LHS.isSigned() && LHS.isMinSignedValue())
- HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
- Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
+ return HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1),
+ E->getType());
return true;
case BO_Shl: {
if (Info.getLangOpts().OpenCL)
@@ -1809,8 +1816,11 @@ static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
break;
}
- if (LHS.isInfinity() || LHS.isNaN())
+ if (LHS.isInfinity() || LHS.isNaN()) {
Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
+ // Undefined behavior is a side-effect.
+ return Info.noteSideEffect();
+ }
return true;
}
@@ -3009,7 +3019,7 @@ struct IncDecSubobjectHandler {
if (!WasNegative && Value.isNegative() &&
isOverflowingIntegerType(Info.Ctx, SubobjType)) {
APSInt ActualValue(Value, /*IsUnsigned*/true);
- HandleOverflow(Info, E, ActualValue, SubobjType);
+ return HandleOverflow(Info, E, ActualValue, SubobjType);
}
} else {
--Value;
@@ -3019,7 +3029,7 @@ struct IncDecSubobjectHandler {
unsigned BitWidth = Value.getBitWidth();
APSInt ActualValue(Value.sext(BitWidth + 1), /*IsUnsigned*/false);
ActualValue.setBit(BitWidth);
- HandleOverflow(Info, E, ActualValue, SubobjType);
+ return HandleOverflow(Info, E, ActualValue, SubobjType);
}
}
return true;
@@ -6240,8 +6250,8 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) {
APValue &V = Result.Val;
if (V.getKind() == APValue::Int)
return true;
-
- return EvaluateBuiltinConstantPForLValue(V);
+ if (V.getKind() == APValue::LValue)
+ return EvaluateBuiltinConstantPForLValue(V);
} else if (ArgType->isFloatingType() || ArgType->isAnyComplexType()) {
return Arg->isEvaluatable(Ctx);
} else if (ArgType->isPointerType() || Arg->isGLValue()) {
@@ -7258,7 +7268,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
LValue LHSValue, RHSValue;
bool LHSOK = EvaluatePointer(E->getLHS(), LHSValue, Info);
- if (!LHSOK && Info.keepEvaluatingAfterFailure())
+ if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK)
@@ -7270,21 +7280,20 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (E->getOpcode() == BO_Sub) {
// Handle &&A - &&B.
if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero())
- return false;
+ return Error(E);
const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>();
const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr*>();
if (!LHSExpr || !RHSExpr)
- return false;
+ return Error(E);
const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr);
const AddrLabelExpr *RHSAddrExpr = dyn_cast<AddrLabelExpr>(RHSExpr);
if (!LHSAddrExpr || !RHSAddrExpr)
- return false;
+ return Error(E);
// Make sure both labels come from the same function.
if (LHSAddrExpr->getLabel()->getDeclContext() !=
RHSAddrExpr->getLabel()->getDeclContext())
- return false;
- Result = APValue(LHSAddrExpr, RHSAddrExpr);
- return true;
+ return Error(E);
+ return Success(APValue(LHSAddrExpr, RHSAddrExpr), E);
}
// Inequalities and subtractions between unrelated pointers have
// unspecified or undefined behavior.
@@ -7375,8 +7384,9 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
APSInt TrueResult = (LHS - RHS) / ElemSize;
APSInt Result = TrueResult.trunc(Info.Ctx.getIntWidth(E->getType()));
- if (Result.extend(65) != TrueResult)
- HandleOverflow(Info, E, TrueResult, E->getType());
+ if (Result.extend(65) != TrueResult &&
+ !HandleOverflow(Info, E, TrueResult, E->getType()))
+ return false;
return Success(Result, E);
}
@@ -7662,9 +7672,10 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
return false;
if (!Result.isInt()) return Error(E);
const APSInt &Value = Result.getInt();
- if (Value.isSigned() && Value.isMinSignedValue())
- HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
- E->getType());
+ if (Value.isSigned() && Value.isMinSignedValue() &&
+ !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
+ E->getType()))
+ return false;
return Success(-Value, E);
}
case UO_Not: {
@@ -8863,7 +8874,9 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
Expr::EvalStatus EStatus;
EStatus.Diag = &Notes;
- EvalInfo InitInfo(Ctx, EStatus, EvalInfo::EM_ConstantFold);
+ EvalInfo InitInfo(Ctx, EStatus, VD->isConstexpr()
+ ? EvalInfo::EM_ConstantExpression
+ : EvalInfo::EM_ConstantFold);
InitInfo.setEvaluatingDecl(VD, Value);
LValue LVal;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 31e952cef21..9d8a3f5240d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -8547,7 +8547,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
return;
llvm::APSInt index;
- if (!IndexExpr->EvaluateAsInt(index, Context))
+ if (!IndexExpr->EvaluateAsInt(index, Context, Expr::SE_AllowSideEffects))
return;
if (IndexNegated)
index = -index;
diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp
index 2adefd928af..c519ecbda22 100644
--- a/clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -601,11 +601,11 @@ namespace rdar13090123 {
typedef __INTPTR_TYPE__ intptr_t;
constexpr intptr_t f(intptr_t x) {
- return (((x) >> 21) * 8); // expected-note{{subexpression not valid in a constant expression}}
+ return (((x) >> 21) * 8);
}
extern "C" int foo;
constexpr intptr_t i = f((intptr_t)&foo - 10); // expected-error{{constexpr variable 'i' must be initialized by a constant expression}} \
- // expected-note{{in call to 'f((char*)&foo + -10)'}}
+ // expected-note{{reinterpret_cast}}
}
diff --git a/clang/test/CodeGen/complex-init-list.c b/clang/test/CodeGen/complex-init-list.c
index bc38e2caf21..fa266b26bb9 100644
--- a/clang/test/CodeGen/complex-init-list.c
+++ b/clang/test/CodeGen/complex-init-list.c
@@ -4,8 +4,8 @@
// of a complex number individually using an initialization list. (There is a
// extensive description and test in test/Sema/complex-init-list.c.)
-_Complex float x = { 1.0f, 1.0f/0.0f };
-// CHECK: @x = global { float, float } { float 1.000000e+00, float 0x7FF0000000000000 }, align 4
+_Complex float x = { 1.0f, -1.0f };
+// CHECK: @x = global { float, float } { float 1.000000e+00, float -1.000000e+00 }, align 4
_Complex float f(float x, float y) { _Complex float z = { x, y }; return z; }
// CHECK-LABEL: define <2 x float> @f
diff --git a/clang/test/CodeGen/ubsan-conditional.c b/clang/test/CodeGen/ubsan-conditional.c
new file mode 100644
index 00000000000..7f63b39a230
--- /dev/null
+++ b/clang/test/CodeGen/ubsan-conditional.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 %s -emit-llvm -fsanitize=float-divide-by-zero -o - | FileCheck %s
+
+_Bool b;
+// CHECK: @f(
+double f() {
+ // CHECK: %[[B:.*]] = load {{.*}} @b
+ // CHECK: %[[COND:.*]] = trunc {{.*}} %[[B]] to i1
+ // CHECK: br i1 %[[COND]]
+ return b ? 0.0 / 0.0 : 0.0;
+}
diff --git a/clang/test/PCH/floating-literal.c b/clang/test/PCH/floating-literal.c
index b5ff6fe84b8..9037deaf4e9 100644
--- a/clang/test/PCH/floating-literal.c
+++ b/clang/test/PCH/floating-literal.c
@@ -15,5 +15,5 @@ long double foo = 1.0E4000L;
double bar = 1.0E300;
// CHECK: double bar = 1.0000000000000001E+300;
-float wibble = 1.0E40;
-// CHECK: float wibble = 1.0E+40;
+float wibble = 2.0E38;
+// CHECK: float wibble = 2.0E+38;
diff --git a/clang/test/Sema/const-eval.c b/clang/test/Sema/const-eval.c
index bfb58bc573e..7c2cd0efd5e 100644
--- a/clang/test/Sema/const-eval.c
+++ b/clang/test/Sema/const-eval.c
@@ -129,7 +129,7 @@ extern struct Test50S Test50;
EVAL_EXPR(50, &Test50 < (struct Test50S*)((unsigned)&Test50 + 10)) // expected-error {{must have a constant size}}
// <rdar://problem/11874571>
-EVAL_EXPR(51, 0 != (float)1e99)
+EVAL_EXPR(51, 0 != (float)1e38)
// PR21945
void PR21945() { int i = (({}), 0l); }
diff --git a/clang/test/Sema/integer-overflow.c b/clang/test/Sema/integer-overflow.c
index 44fbcd4c818..8f74873ed94 100644
--- a/clang/test/Sema/integer-overflow.c
+++ b/clang/test/Sema/integer-overflow.c
@@ -7,6 +7,7 @@ uint64_t f1(uint64_t, uint32_t);
uint64_t f2(uint64_t, ...);
static const uint64_t overflow = 1 * 4608 * 1024 * 1024; // expected-warning {{overflow in expression; result is 536870912 with type 'int'}}
+// expected-error@-1 {{not a compile-time constant}}
uint64_t check_integer_overflows(int i) {
// expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}}
diff --git a/clang/test/Sema/switch-1.c b/clang/test/Sema/switch-1.c
index 144c3607f57..0d31a191c4f 100644
--- a/clang/test/Sema/switch-1.c
+++ b/clang/test/Sema/switch-1.c
@@ -55,5 +55,8 @@ int f(int i) {
// rdar://18405357
unsigned long long l = 65536 * 65536; // expected-warning {{overflow in expression; result is 0 with type 'int'}}
+#ifndef __cplusplus
+// expected-error@-2 {{not a compile-time constant}}
+#endif
unsigned long long l2 = 65536 * (unsigned)65536;
unsigned long long l3 = 65536 * 65536ULL;
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index 794932df409..7b9d0150e1e 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -327,7 +327,7 @@ struct Str {
};
extern char externalvar[];
-constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}}
+constexpr bool constaddress = (void *)externalvar == (void *)0x4000UL; // expected-error {{must be initialized by a constant expression}} expected-note {{reinterpret_cast}}
constexpr bool litaddress = "foo" == "foo"; // expected-error {{must be initialized by a constant expression}} expected-warning {{unspecified}}
static_assert(0 != "foo", "");
@@ -1874,10 +1874,9 @@ namespace NeverConstantTwoWays {
0;
}
- // FIXME: We should diagnose the cast to long here, not the division by zero.
constexpr int n = // expected-error {{must be initialized by a constant expression}}
- (int *)(long)&n == &n ?
- 1 / 0 : // expected-warning {{division by zero}} expected-note {{division by zero}}
+ (int *)(long)&n == &n ? // expected-note {{reinterpret_cast}}
+ 1 / 0 : // expected-warning {{division by zero}}
0;
}
diff --git a/clang/test/SemaCXX/constexpr-printing.cpp b/clang/test/SemaCXX/constexpr-printing.cpp
index e545f45d601..7f6a9c6a82f 100644
--- a/clang/test/SemaCXX/constexpr-printing.cpp
+++ b/clang/test/SemaCXX/constexpr-printing.cpp
@@ -90,10 +90,12 @@ constexpr wchar_t wc = get(L"test\0\\\"\t\a\b\234\u1234\xffffffff"); // \
constexpr char32_t c32_err = get(U"\U00110000"); // expected-error {{invalid universal character}}
+#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
+
typedef decltype(sizeof(int)) LabelDiffTy;
constexpr LabelDiffTy mulBy3(LabelDiffTy x) { return x * 3; } // expected-note {{subexpression}}
void LabelDiffTest() {
- static_assert(mulBy3((LabelDiffTy)&&a-(LabelDiffTy)&&b) == 3, ""); // expected-error {{constant expression}} expected-note {{call to 'mulBy3(&&a - &&b)'}}
+ static_assert(mulBy3(fold((LabelDiffTy)&&a-(LabelDiffTy)&&b)) == 3, ""); // expected-error {{constant expression}} expected-note {{call to 'mulBy3(&&a - &&b)'}}
a:b:return;
}
OpenPOWER on IntegriCloud