/// Sign- or zero-extend a value to 64 bits. If it's already 64 bits, just
/// return its existing value.
-static int64_t getExtValue(const APSInt &Value) {
- return Value.isSigned() ? Value.getSExtValue()
- : static_cast<int64_t>(Value.getZExtValue());
+static bool getExtValue(EvalInfo &Info, const Expr *E, const APSInt &Value,
+ int64_t &Result) {
+ if (Value.isSigned() ? Value.getMinSignedBits() > 64
+ : Value.getActiveBits() > 64) {
+ Info.FFDiag(E);
+ return false;
+ }
+
+ Result = Value.isSigned() ? Value.getSExtValue()
+ : static_cast<int64_t>(Value.getZExtValue());
+ return true;
}
/// Should this call expression be treated as a string literal?
return false;
}
- int64_t Offset = getExtValue(RHS.getInt());
+ int64_t Offset;
+ if (!getExtValue(Info, E, RHS.getInt(), Offset))
+ return false;
if (Opcode == BO_Sub)
Offset = -Offset;
if (!EvaluateInteger(E->getIdx(), Index, Info))
return false;
- return HandleLValueArrayAdjustment(Info, E, Result, E->getType(),
- getExtValue(Index));
+ int64_t Offset;
+ if (!getExtValue(Info, E, Index, Offset))
+ return false;
+ return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), Offset);
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
if (!EvaluateInteger(IExp, Offset, Info) || !EvalPtrOK)
return false;
- int64_t AdditionalOffset = getExtValue(Offset);
+ int64_t AdditionalOffset;
+ if (!getExtValue(Info, E, Offset, AdditionalOffset))
+ return false;
if (E->getOpcode() == BO_Sub)
AdditionalOffset = -AdditionalOffset;
APSInt Alignment;
if (!EvaluateInteger(E->getArg(1), Alignment, Info))
return false;
- CharUnits Align = CharUnits::fromQuantity(getExtValue(Alignment));
+ CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue());
if (E->getNumArgs() > 2) {
APSInt Offset;
if (!EvaluateInteger(E->getArg(2), Offset, Info))
return false;
- int64_t AdditionalOffset = -getExtValue(Offset);
+ int64_t AdditionalOffset = -Offset.getZExtValue();
OffsetResult.Offset += CharUnits::fromQuantity(AdditionalOffset);
}
if (BaseAlignment < Align) {
Result.Designator.setInvalid();
- // FIXME: Quantities here cast to integers because the plural modifier
- // does not work on APSInts yet.
+ // FIXME: Add support to Diagnostic for long / long long.
CCEDiag(E->getArg(0),
diag::note_constexpr_baa_insufficient_alignment) << 0
- << (int) BaseAlignment.getQuantity()
- << (unsigned) getExtValue(Alignment);
+ << (unsigned)BaseAlignment.getQuantity()
+ << (unsigned)Align.getQuantity();
return false;
}
}
// The offset must also have the correct alignment.
if (OffsetResult.Offset.alignTo(Align) != OffsetResult.Offset) {
Result.Designator.setInvalid();
- APSInt Offset(64, false);
- Offset = OffsetResult.Offset.getQuantity();
-
- if (OffsetResult.Base)
- CCEDiag(E->getArg(0),
- diag::note_constexpr_baa_insufficient_alignment) << 1
- << (int) getExtValue(Offset) << (unsigned) getExtValue(Alignment);
- else
- CCEDiag(E->getArg(0),
- diag::note_constexpr_baa_value_insufficient_alignment)
- << Offset << (unsigned) getExtValue(Alignment);
+ (OffsetResult.Base
+ ? CCEDiag(E->getArg(0),
+ diag::note_constexpr_baa_insufficient_alignment) << 1
+ : CCEDiag(E->getArg(0),
+ diag::note_constexpr_baa_value_insufficient_alignment))
+ << (int)OffsetResult.Offset.getQuantity()
+ << (unsigned)Align.getQuantity();
return false;
}
// Handle cases like (unsigned long)&a + 4.
if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) {
Result = LHSVal;
- CharUnits AdditionalOffset =
- CharUnits::fromQuantity(RHSVal.getInt().getZExtValue());
+ int64_t Offset;
+ if (!getExtValue(Info, E, RHSVal.getInt(), Offset))
+ return false;
if (E->getOpcode() == BO_Add)
- Result.getLValueOffset() += AdditionalOffset;
+ Result.getLValueOffset() += CharUnits::fromQuantity(Offset);
else
- Result.getLValueOffset() -= AdditionalOffset;
+ Result.getLValueOffset() -= CharUnits::fromQuantity(Offset);
return true;
}
if (E->getOpcode() == BO_Add &&
RHSVal.isLValue() && LHSVal.isInt()) {
Result = RHSVal;
- Result.getLValueOffset() +=
- CharUnits::fromQuantity(LHSVal.getInt().getZExtValue());
+ int64_t Offset;
+ if (!getExtValue(Info, E, LHSVal.getInt(), Offset))
+ return false;
+ Result.getLValueOffset() += CharUnits::fromQuantity(Offset);
return true;
}
-// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux %s -Wno-tautological-pointer-compare
+// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux %s -Wno-tautological-pointer-compare
#define EVAL_EXPR(testno, expr) int test##testno = sizeof(struct{char qq[expr];});
int x;
EVAL_EXPR(49, &x < &x - 100 ? 1 : -1) // expected-error {{must have a constant size}}
extern struct Test50S Test50;
-EVAL_EXPR(50, &Test50 < (struct Test50S*)((unsigned)&Test50 + 10)) // expected-error {{must have a constant size}}
+EVAL_EXPR(50, &Test50 < (struct Test50S*)((unsigned long)&Test50 + 10)) // expected-error {{must have a constant size}}
// <rdar://problem/11874571>
EVAL_EXPR(51, 0 != (float)1e99)
void PR24622();
struct PR24622 {} pr24622;
EVAL_EXPR(52, &pr24622 == (void *)&PR24622); // expected-error {{must have a constant size}}
+
+// Reject cases that would require more than 64 bits of pointer offset to
+// represent.
+// FIXME: We don't check for all offset overflow, just immediate adjustments
+// that don't fit in 64 bits. We should consistently either check all offset
+// adjustments or truncate to 64 bits everywhere.
+void *PR28739a = (__int128)(unsigned long)-1 + &PR28739a; // expected-error {{not a compile-time constant}}
+void *PR28739b = &PR28739b + (__int128)(unsigned long)-1; // expected-error {{not a compile-time constant}}
+__int128 PR28739c = (&PR28739c + (__int128)(unsigned long)-1) - &PR28739c; // expected-error {{not a compile-time constant}}
+void *PR28739d = &(&PR28739d)[(__int128)(unsigned long)-1]; // expected-error {{not a compile-time constant}}
+__int128 PR28739e = (__int128)(unsigned long)-1 + (long)&PR28739e; // expected-error {{not a compile-time constant}}
+__int128 PR28739f = (long)&PR28739f + (__int128)(unsigned long)-1; // expected-error {{not a compile-time constant}}