<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 2 May 2017 at 12:21, Daniel Jasper via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: djasper<br>
Date: Tue May 2 14:21:42 2017<br>
New Revision: 301963<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=301963&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=301963&view=rev</a><br>
Log:<br>
Revert r301822 (and dependent r301825), which tried to improve the<br>
handling of constexprs with unknown bounds.<br>
<br>
This triggers a corner case of the language where it's not yet clear<br>
whether this should be an error:<br>
<br>
struct A {<br>
static void *const a[];<br>
static void *const b[];<br>
};<br>
constexpr void *A::a[] = {&b[0]};<br>
constexpr void *A::b[] = {&a[0]};<br>
<br>
When discovering the initializer for A::a, the bounds of A::b aren't known yet.<br>
It is unclear whether warning about errors should be deferred until the end of<br>
the translation unit, possibly resolving errors that can be resolved. In<br>
practice, the compiler can know the bounds of all arrays in this example.<br></blockquote><div><br></div><div>I've started a discussion on the C++ core reflector about this.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Credits for reproducers and explanation go to Richard Smith. Richard, please<br>
add more info in case my explanation is wrong.<br>
<br>
Removed:<br>
cfe/trunk/test/SemaCXX/<wbr>constexpr-array-unknown-bound.<wbr>cpp<br>
Modified:<br>
cfe/trunk/include/clang/Basic/<wbr>DiagnosticASTKinds.td<br>
cfe/trunk/lib/AST/<wbr>ExprConstant.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>DiagnosticASTKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=301963&r1=301962&r2=301963&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/<wbr>DiagnosticASTKinds.td?rev=<wbr>301963&r1=301962&r2=301963&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>DiagnosticASTKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>DiagnosticASTKinds.td Tue May 2 14:21:42 2017<br>
@@ -154,14 +154,12 @@ def note_constexpr_baa_<wbr>insufficient_alig<br>
def note_constexpr_baa_value_<wbr>insufficient_alignment : Note<<br>
"value of the aligned pointer (%0) is not a multiple of the asserted %1 "<br>
"%plural{1:byte|:bytes}1">;<br>
-def note_constexpr_array_unknown_<wbr>bound_arithmetic : Note<<br>
- "cannot perform pointer arithmetic on pointer to array without constant bound">;<br>
<br>
def warn_integer_constant_overflow : Warning<<br>
"overflow in expression; result is %0 with type %1">,<br>
InGroup<DiagGroup<"integer-<wbr>overflow">>;<br>
<br>
-// This is a temporary diagnostic, and shall be removed once our<br>
+// This is a temporary diagnostic, and shall be removed once our<br>
// implementation is complete, and like the preceding constexpr notes belongs<br>
// in Sema.<br>
def note_unimplemented_constexpr_<wbr>lambda_feature_ast : Note<<br>
<br>
Modified: cfe/trunk/lib/AST/<wbr>ExprConstant.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=301963&r1=301962&r2=301963&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>ExprConstant.cpp?rev=301963&<wbr>r1=301962&r2=301963&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/<wbr>ExprConstant.cpp (original)<br>
+++ cfe/trunk/lib/AST/<wbr>ExprConstant.cpp Tue May 2 14:21:42 2017<br>
@@ -148,8 +148,7 @@ namespace {<br>
static unsigned<br>
findMostDerivedSubobject(<wbr>ASTContext &Ctx, APValue::LValueBase Base,<br>
ArrayRef<APValue::<wbr>LValuePathEntry> Path,<br>
- uint64_t &ArraySize, QualType &Type, bool &IsArray,<br>
- bool &IsUnsizedArray) {<br>
+ uint64_t &ArraySize, QualType &Type, bool &IsArray) {<br>
// This only accepts LValueBases from APValues, and APValues don't support<br>
// arrays that lack size info.<br>
assert(!isBaseAnAllocSizeCall(<wbr>Base) &&<br>
@@ -158,34 +157,28 @@ namespace {<br>
Type = getType(Base);<br>
<br>
for (unsigned I = 0, N = Path.size(); I != N; ++I) {<br>
- if (auto AT = Ctx.getAsArrayType(Type)) {<br>
+ if (Type->isArrayType()) {<br>
+ const ConstantArrayType *CAT =<br>
+ cast<ConstantArrayType>(Ctx.<wbr>getAsArrayType(Type));<br>
+ Type = CAT->getElementType();<br>
+ ArraySize = CAT->getSize().getZExtValue();<br>
MostDerivedLength = I + 1;<br>
IsArray = true;<br>
- if (auto CAT = Ctx.getAsConstantArrayType(<wbr>Type))<br>
- ArraySize = CAT->getSize().getZExtValue();<br>
- else {<br>
- ArraySize = 0;<br>
- IsUnsizedArray = true;<br>
- }<br>
- Type = AT->getElementType();<br>
} else if (Type->isAnyComplexType()) {<br>
const ComplexType *CT = Type->castAs<ComplexType>();<br>
Type = CT->getElementType();<br>
ArraySize = 2;<br>
MostDerivedLength = I + 1;<br>
IsArray = true;<br>
- IsUnsizedArray = false;<br>
} else if (const FieldDecl *FD = getAsField(Path[I])) {<br>
Type = FD->getType();<br>
ArraySize = 0;<br>
MostDerivedLength = I + 1;<br>
IsArray = false;<br>
- IsUnsizedArray = false;<br>
} else {<br>
// Path[I] describes a base class.<br>
ArraySize = 0;<br>
IsArray = false;<br>
- IsUnsizedArray = false;<br>
}<br>
}<br>
return MostDerivedLength;<br>
@@ -207,9 +200,8 @@ namespace {<br>
/// Is this a pointer one past the end of an object?<br>
unsigned IsOnePastTheEnd : 1;<br>
<br>
- /// Indicator of whether the most-derived object is an unsized array (e.g.<br>
- /// of unknown bound).<br>
- unsigned MostDerivedIsAnUnsizedArray : 1;<br>
+ /// Indicator of whether the first entry is an unsized array.<br>
+ unsigned FirstEntryIsAnUnsizedArray : 1;<br>
<br>
/// Indicator of whether the most-derived object is an array element.<br>
unsigned MostDerivedIsArrayElement : 1;<br>
@@ -239,28 +231,25 @@ namespace {<br>
<br>
explicit SubobjectDesignator(QualType T)<br>
: Invalid(false), IsOnePastTheEnd(false),<br>
- MostDerivedIsAnUnsizedArray(<wbr>false), MostDerivedIsArrayElement(<wbr>false),<br>
+ FirstEntryIsAnUnsizedArray(<wbr>false), MostDerivedIsArrayElement(<wbr>false),<br>
MostDerivedPathLength(0), MostDerivedArraySize(0),<br>
MostDerivedType(T) {}<br>
<br>
SubobjectDesignator(ASTContext &Ctx, const APValue &V)<br>
: Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),<br>
- MostDerivedIsAnUnsizedArray(<wbr>false), MostDerivedIsArrayElement(<wbr>false),<br>
+ FirstEntryIsAnUnsizedArray(<wbr>false), MostDerivedIsArrayElement(<wbr>false),<br>
MostDerivedPathLength(0), MostDerivedArraySize(0) {<br>
assert(V.isLValue() && "Non-LValue used to make an LValue designator?");<br>
if (!Invalid) {<br>
IsOnePastTheEnd = V.isLValueOnePastTheEnd();<br>
ArrayRef<PathEntry> VEntries = V.getLValuePath();<br>
Entries.insert(Entries.end(), VEntries.begin(), VEntries.end());<br>
- if (auto Base = V.getLValueBase()) {<br>
- if (auto Decl = Base.dyn_cast<ValueDecl const*>())<br>
- Base = cast<ValueDecl>(Decl-><wbr>getMostRecentDecl());<br>
- bool IsArray = false, IsUnsizedArray = false;<br>
+ if (V.getLValueBase()) {<br>
+ bool IsArray = false;<br>
MostDerivedPathLength = findMostDerivedSubobject(<br>
- Ctx, Base, V.getLValuePath(), MostDerivedArraySize,<br>
- MostDerivedType, IsArray, IsUnsizedArray);<br>
- MostDerivedIsArrayElement = IsArray;<br>
- MostDerivedIsAnUnsizedArray = IsUnsizedArray;<br>
+ Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize,<br>
+ MostDerivedType, IsArray);<br>
+ MostDerivedIsArrayElement = IsArray;<br>
}<br>
}<br>
}<br>
@@ -274,7 +263,7 @@ namespace {<br>
/// known bound.<br>
bool isMostDerivedAnUnsizedArray() const {<br>
assert(!Invalid && "Calling this makes no sense on invalid designators");<br>
- return MostDerivedIsAnUnsizedArray;<br>
+ return Entries.size() == 1 && FirstEntryIsAnUnsizedArray;<br>
}<br>
<br>
/// Determine what the most derived array's size is. Results in an assertion<br>
@@ -314,7 +303,6 @@ namespace {<br>
// This is a most-derived object.<br>
MostDerivedType = CAT->getElementType();<br>
MostDerivedIsArrayElement = true;<br>
- MostDerivedIsAnUnsizedArray = false;<br>
MostDerivedArraySize = CAT->getSize().getZExtValue();<br>
MostDerivedPathLength = Entries.size();<br>
}<br>
@@ -327,7 +315,6 @@ namespace {<br>
<br>
MostDerivedType = ElemTy;<br>
MostDerivedIsArrayElement = true;<br>
- MostDerivedIsAnUnsizedArray = true;<br>
// The value in MostDerivedArraySize is undefined in this case. So, set it<br>
// to an arbitrary value that's likely to loudly break things if it's<br>
// used.<br>
@@ -346,7 +333,6 @@ namespace {<br>
if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {<br>
MostDerivedType = FD->getType();<br>
MostDerivedIsArrayElement = false;<br>
- MostDerivedIsAnUnsizedArray = false;<br>
MostDerivedArraySize = 0;<br>
MostDerivedPathLength = Entries.size();<br>
}<br>
@@ -361,14 +347,53 @@ namespace {<br>
// is unlikely to matter.<br>
MostDerivedType = EltTy;<br>
MostDerivedIsArrayElement = true;<br>
- MostDerivedIsAnUnsizedArray = false;<br>
MostDerivedArraySize = 2;<br>
MostDerivedPathLength = Entries.size();<br>
}<br>
void diagnosePointerArithmetic(<wbr>EvalInfo &Info, const Expr *E,<br>
const APSInt &N);<br>
/// Add N to the address of this subobject.<br>
- void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N);<br>
+ void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) {<br>
+ if (Invalid || !N) return;<br>
+ uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(<wbr>);<br>
+ if (isMostDerivedAnUnsizedArray()<wbr>) {<br>
+ // Can't verify -- trust that the user is doing the right thing (or if<br>
+ // not, trust that the caller will catch the bad behavior).<br>
+ // FIXME: Should we reject if this overflows, at least?<br>
+ Entries.back().ArrayIndex += TruncatedN;<br>
+ return;<br>
+ }<br>
+<br>
+ // [expr.add]p4: For the purposes of these operators, a pointer to a<br>
+ // nonarray object behaves the same as a pointer to the first element of<br>
+ // an array of length one with the type of the object as its element type.<br>
+ bool IsArray = MostDerivedPathLength == Entries.size() &&<br>
+ MostDerivedIsArrayElement;<br>
+ uint64_t ArrayIndex =<br>
+ IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd;<br>
+ uint64_t ArraySize =<br>
+ IsArray ? getMostDerivedArraySize() : (uint64_t)1;<br>
+<br>
+ if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) {<br>
+ // Calculate the actual index in a wide enough type, so we can include<br>
+ // it in the note.<br>
+ N = N.extend(std::max<unsigned>(N.<wbr>getBitWidth() + 1, 65));<br>
+ (llvm::APInt&)N += ArrayIndex;<br>
+ assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index");<br>
+ diagnosePointerArithmetic(<wbr>Info, E, N);<br>
+ setInvalid();<br>
+ return;<br>
+ }<br>
+<br>
+ ArrayIndex += TruncatedN;<br>
+ assert(ArrayIndex <= ArraySize &&<br>
+ "bounds check succeeded for out-of-bounds index");<br>
+<br>
+ if (IsArray)<br>
+ Entries.back().ArrayIndex = ArrayIndex;<br>
+ else<br>
+ IsOnePastTheEnd = (ArrayIndex != 0);<br>
+ }<br>
};<br>
<br>
/// A stack frame in the constexpr call stack.<br>
@@ -470,7 +495,7 @@ namespace {<br>
// FIXME: Force the precision of the source value down so we don't<br>
// print digits which are usually useless (we don't really care here if<br>
// we truncate a digit by accident in edge cases). Ideally,<br>
- // APFloat::toString would automatically print the shortest<br>
+ // APFloat::toString would automatically print the shortest<br>
// representation which rounds to the correct value, but it's a bit<br>
// tricky to implement.<br>
unsigned precision =<br>
@@ -695,7 +720,7 @@ namespace {<br>
private:<br>
OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId,<br>
unsigned ExtraNotes, bool IsCCEDiag) {<br>
-<br>
+<br>
if (EvalStatus.Diag) {<br>
// If we have a prior diagnostic, it will be noting that the expression<br>
// isn't a constant expression. This diagnostic is more important,<br>
@@ -748,7 +773,7 @@ namespace {<br>
unsigned ExtraNotes = 0) {<br>
return Diag(Loc, DiagId, ExtraNotes, false);<br>
}<br>
-<br>
+<br>
OptionalDiagnostic FFDiag(const Expr *E, diag::kind DiagId<br>
= diag::note_invalid_subexpr_in_<wbr>const_expr,<br>
unsigned ExtraNotes = 0) {<br>
@@ -1061,53 +1086,6 @@ void SubobjectDesignator::<wbr>diagnosePointe<br>
setInvalid();<br>
}<br>
<br>
-void SubobjectDesignator::<wbr>adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) {<br>
- if (Invalid || !N) return;<br>
-<br>
- uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue(<wbr>);<br>
- if (isMostDerivedAnUnsizedArray()<wbr>) {<br>
- // If we're dealing with an array without constant bound, the expression is<br>
- // not a constant expression.<br>
- if (!Info.<wbr>checkingPotentialConstantExpre<wbr>ssion())<br>
- Info.CCEDiag(E, diag::note_constexpr_array_<wbr>unknown_bound_arithmetic);<br>
- // Can't verify -- trust that the user is doing the right thing (or if<br>
- // not, trust that the caller will catch the bad behavior).<br>
- // FIXME: Should we reject if this overflows, at least?<br>
- Entries.back().ArrayIndex += TruncatedN;<br>
- return;<br>
- }<br>
-<br>
- // [expr.add]p4: For the purposes of these operators, a pointer to a<br>
- // nonarray object behaves the same as a pointer to the first element of<br>
- // an array of length one with the type of the object as its element type.<br>
- bool IsArray = MostDerivedPathLength == Entries.size() &&<br>
- MostDerivedIsArrayElement;<br>
- uint64_t ArrayIndex =<br>
- IsArray ? Entries.back().ArrayIndex : (uint64_t)IsOnePastTheEnd;<br>
- uint64_t ArraySize =<br>
- IsArray ? getMostDerivedArraySize() : (uint64_t)1;<br>
-<br>
- if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) {<br>
- // Calculate the actual index in a wide enough type, so we can include<br>
- // it in the note.<br>
- N = N.extend(std::max<unsigned>(N.<wbr>getBitWidth() + 1, 65));<br>
- (llvm::APInt&)N += ArrayIndex;<br>
- assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index");<br>
- diagnosePointerArithmetic(<wbr>Info, E, N);<br>
- setInvalid();<br>
- return;<br>
- }<br>
-<br>
- ArrayIndex += TruncatedN;<br>
- assert(ArrayIndex <= ArraySize &&<br>
- "bounds check succeeded for out-of-bounds index");<br>
-<br>
- if (IsArray)<br>
- Entries.back().ArrayIndex = ArrayIndex;<br>
- else<br>
- IsOnePastTheEnd = (ArrayIndex != 0);<br>
-}<br>
-<br>
CallStackFrame::<wbr>CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,<br>
const FunctionDecl *Callee, const LValue *This,<br>
APValue *Arguments)<br>
@@ -1236,6 +1214,8 @@ namespace {<br>
IsNullPtr);<br>
else {<br>
assert(!InvalidBase && "APValues can't handle invalid LValue bases");<br>
+ assert(!Designator.<wbr>FirstEntryIsAnUnsizedArray &&<br>
+ "Unsized array with a valid base?");<br>
V = APValue(Base, Offset, Designator.Entries,<br>
Designator.IsOnePastTheEnd, CallIndex, IsNullPtr);<br>
}<br>
@@ -1300,9 +1280,12 @@ namespace {<br>
if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))<br>
Designator.addDeclUnchecked(D, Virtual);<br>
}<br>
- void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) {<br>
- if (checkSubobject(Info, E, CSK_ArrayToPointer))<br>
- Designator.<wbr>addUnsizedArrayUnchecked(<wbr>ElemTy);<br>
+ void addUnsizedArray(EvalInfo &Info, QualType ElemTy) {<br>
+ assert(Designator.Entries.<wbr>empty() && getType(Base)->isPointerType()<wbr>);<br>
+ assert(isBaseAnAllocSizeCall(<wbr>Base) &&<br>
+ "Only alloc_size bases can have unsized arrays");<br>
+ Designator.<wbr>FirstEntryIsAnUnsizedArray = true;<br>
+ Designator.<wbr>addUnsizedArrayUnchecked(<wbr>ElemTy);<br>
}<br>
void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) {<br>
if (checkSubobject(Info, E, CSK_ArrayToPointer))<br>
@@ -3033,15 +3016,6 @@ static CompleteObject findCompleteObject<br>
<br>
if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal))<br>
return CompleteObject();<br>
-<br>
- // The complete object can be an array of unknown bound, in which case we<br>
- // have to find the most recent declaration and adjust the type accordingly.<br>
- if (Info.Ctx.<wbr>getAsIncompleteArrayType(<wbr>BaseType)) {<br>
- QualType MostRecentType =<br>
- cast<ValueDecl const>(D->getMostRecentDecl())<wbr>->getType();<br>
- if (Info.Ctx.<wbr>getAsConstantArrayType(<wbr>MostRecentType))<br>
- BaseType = MostRecentType;<br>
- }<br>
} else {<br>
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();<br>
<br>
@@ -4124,13 +4098,13 @@ static bool CheckConstexprFunction(EvalI<br>
<br>
if (Info.getLangOpts().<wbr>CPlusPlus11) {<br>
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;<br>
-<br>
+<br>
// If this function is not constexpr because it is an inherited<br>
// non-constexpr constructor, diagnose that directly.<br>
auto *CD = dyn_cast<CXXConstructorDecl>(<wbr>DiagDecl);<br>
if (CD && CD->isInheritingConstructor()) {<br>
auto *Inherited = CD->getInheritedConstructor().<wbr>getConstructor();<br>
- if (!Inherited->isConstexpr())<br>
+ if (!Inherited->isConstexpr())<br>
DiagDecl = CD = Inherited;<br>
}<br>
<br>
@@ -4667,7 +4641,7 @@ public:<br>
return false;<br>
This = &ThisVal;<br>
Args = Args.slice(1);<br>
- } else if (MD && MD->isLambdaStaticInvoker()) {<br>
+ } else if (MD && MD->isLambdaStaticInvoker()) {<br>
// Map the static invoker for the lambda back to the call operator.<br>
// Conveniently, we don't have to slice out the 'this' argument (as is<br>
// being done for the non-static case), since a static member function<br>
@@ -4702,7 +4676,7 @@ public:<br>
FD = LambdaCallOp;<br>
}<br>
<br>
-<br>
+<br>
} else<br>
return Error(E);<br>
<br>
@@ -5462,7 +5436,7 @@ static bool evaluateLValueAsAllocSize(Ev<br>
Result.setInvalid(E);<br>
<br>
QualType Pointee = E->getType()->castAs<<wbr>PointerType>()-><wbr>getPointeeType();<br>
- Result.addUnsizedArray(Info, E, Pointee);<br>
+ Result.addUnsizedArray(Info, Pointee);<br>
return true;<br>
}<br>
<br>
@@ -5541,7 +5515,7 @@ public:<br>
// Update 'Result' to refer to the data member/field of the closure object<br>
// that represents the '*this' capture.<br>
if (!HandleLValueMember(Info, E, Result,<br>
- Info.CurrentCall-><wbr>LambdaThisCaptureField))<br>
+ Info.CurrentCall-><wbr>LambdaThisCaptureField))<br>
return false;<br>
// If we captured '*this' by reference, replace the field with its referent.<br>
if (Info.CurrentCall-><wbr>LambdaThisCaptureField-><wbr>getType()<br>
@@ -5682,18 +5656,12 @@ bool PointerExprEvaluator::<wbr>VisitCastExpr<br>
Info, Result, SubExpr))<br>
return false;<br>
}<br>
-<br>
// The result is a pointer to the first element of the array.<br>
if (const ConstantArrayType *CAT<br>
= Info.Ctx.<wbr>getAsConstantArrayType(<wbr>SubExpr->getType()))<br>
Result.addArray(Info, E, CAT);<br>
- // If the array hasn't been given a bound yet, add it as an unsized one.<br>
- else {<br>
- auto AT = Info.Ctx.getAsArrayType(<wbr>SubExpr->getType());<br>
- assert(AT && "Array to pointer decay on non-array object?");<br>
- Result.addUnsizedArray(Info, E, AT->getElementType());<br>
- }<br>
-<br>
+ else<br>
+ Result.Designator.setInvalid()<wbr>;<br>
return true;<br>
<br>
case CK_FunctionToPointerDecay:<br>
@@ -5761,7 +5729,7 @@ bool PointerExprEvaluator::<wbr>visitNonBuilt<br>
<br>
Result.setInvalid(E);<br>
QualType PointeeTy = E->getType()->castAs<<wbr>PointerType>()-><wbr>getPointeeType();<br>
- Result.addUnsizedArray(Info, E, PointeeTy);<br>
+ Result.addUnsizedArray(Info, PointeeTy);<br>
return true;<br>
}<br>
<br>
@@ -6395,7 +6363,7 @@ bool RecordExprEvaluator::<wbr>VisitLambdaExp<br>
if (ClosureClass->isInvalidDecl()<wbr>) return false;<br>
<br>
if (Info.<wbr>checkingPotentialConstantExpre<wbr>ssion()) return true;<br>
-<br>
+<br>
const size_t NumFields =<br>
std::distance(ClosureClass-><wbr>field_begin(), ClosureClass->field_end());<br>
<br>
@@ -6414,7 +6382,7 @@ bool RecordExprEvaluator::<wbr>VisitLambdaExp<br>
assert(CaptureInitIt != E->capture_init_end());<br>
// Get the initializer for this field<br>
Expr *const CurFieldInit = *CaptureInitIt++;<br>
-<br>
+<br>
// If there is no initializer, either this is a VLA or an error has<br>
// occurred.<br>
if (!CurFieldInit)<br>
@@ -6615,18 +6583,18 @@ VectorExprEvaluator::<wbr>VisitInitListExpr(c<br>
<br>
// The number of initializers can be less than the number of<br>
// vector elements. For OpenCL, this can be due to nested vector<br>
- // initialization. For GCC compatibility, missing trailing elements<br>
+ // initialization. For GCC compatibility, missing trailing elements<br>
// should be initialized with zeroes.<br>
unsigned CountInits = 0, CountElts = 0;<br>
while (CountElts < NumElements) {<br>
// Handle nested vector initialization.<br>
- if (CountInits < NumInits<br>
+ if (CountInits < NumInits<br>
&& E->getInit(CountInits)-><wbr>getType()->isVectorType()) {<br>
APValue v;<br>
if (!EvaluateVector(E->getInit(<wbr>CountInits), v, Info))<br>
return Error(E);<br>
unsigned vlen = v.getVectorLength();<br>
- for (unsigned j = 0; j < vlen; j++)<br>
+ for (unsigned j = 0; j < vlen; j++)<br>
Elements.push_back(v.<wbr>getVectorElt(j));<br>
CountElts += vlen;<br>
} else if (EltTy->isIntegerType()) {<br>
@@ -6902,7 +6870,7 @@ public:<br>
}<br>
<br>
bool Success(const llvm::APInt &I, const Expr *E, APValue &Result) {<br>
- assert(E->getType()-><wbr>isIntegralOrEnumerationType() &&<br>
+ assert(E->getType()-><wbr>isIntegralOrEnumerationType() &&<br>
"Invalid evaluation result.");<br>
assert(I.getBitWidth() == Info.Ctx.getIntWidth(E-><wbr>getType()) &&<br>
"Invalid evaluation result.");<br>
@@ -6916,7 +6884,7 @@ public:<br>
}<br>
<br>
bool Success(uint64_t Value, const Expr *E, APValue &Result) {<br>
- assert(E->getType()-><wbr>isIntegralOrEnumerationType() &&<br>
+ assert(E->getType()-><wbr>isIntegralOrEnumerationType() &&<br>
"Invalid evaluation result.");<br>
Result = APValue(Info.Ctx.MakeIntValue(<wbr>Value, E->getType()));<br>
return true;<br>
@@ -6992,7 +6960,7 @@ public:<br>
}<br>
return Success(Info.ArrayInitIndex, E);<br>
}<br>
-<br>
+<br>
// Note, GNU defines __null as an integer, not a pointer.<br>
bool VisitGNUNullExpr(const GNUNullExpr *E) {<br>
return ZeroInitialization(E);<br>
@@ -7356,8 +7324,10 @@ static bool isDesignatorAtObjectEnd(cons<br>
<br>
unsigned I = 0;<br>
QualType BaseType = getType(Base);<br>
- // If this is an alloc_size base, we should ignore the initial array index<br>
- if (isBaseAnAllocSizeCall(Base)) {<br>
+ if (LVal.Designator.<wbr>FirstEntryIsAnUnsizedArray) {<br>
+ assert(isBaseAnAllocSizeCall(<wbr>Base) &&<br>
+ "Unsized array in non-alloc_size call?");<br>
+ // If this is an alloc_size base, we should ignore the initial array index<br>
++I;<br>
BaseType = BaseType->castAs<PointerType>(<wbr>)->getPointeeType();<br>
}<br>
@@ -8144,12 +8114,12 @@ bool DataRecursiveIntBinOpEvaluator<wbr>::<br>
Result = RHSResult.Val;<br>
return true;<br>
}<br>
-<br>
+<br>
if (E->isLogicalOp()) {<br>
bool lhsResult, rhsResult;<br>
bool LHSIsOK = HandleConversionToBool(<wbr>LHSResult.Val, lhsResult);<br>
bool RHSIsOK = HandleConversionToBool(<wbr>RHSResult.Val, rhsResult);<br>
-<br>
+<br>
if (LHSIsOK) {<br>
if (RHSIsOK) {<br>
if (E->getOpcode() == BO_LOr)<br>
@@ -8165,26 +8135,26 @@ bool DataRecursiveIntBinOpEvaluator<wbr>::<br>
return Success(rhsResult, E, Result);<br>
}<br>
}<br>
-<br>
+<br>
return false;<br>
}<br>
-<br>
+<br>
assert(E->getLHS()->getType()-<wbr>>isIntegralOrEnumerationType() &&<br>
E->getRHS()->getType()-><wbr>isIntegralOrEnumerationType())<wbr>;<br>
-<br>
+<br>
if (LHSResult.Failed || RHSResult.Failed)<br>
return false;<br>
-<br>
+<br>
const APValue &LHSVal = LHSResult.Val;<br>
const APValue &RHSVal = RHSResult.Val;<br>
-<br>
+<br>
// Handle cases like (unsigned long)&a + 4.<br>
if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) {<br>
Result = LHSVal;<br>
addOrSubLValueAsInteger(<wbr>Result, RHSVal.getInt(), E->getOpcode() == BO_Sub);<br>
return true;<br>
}<br>
-<br>
+<br>
// Handle cases like 4 + (unsigned long)&a<br>
if (E->getOpcode() == BO_Add &&<br>
RHSVal.isLValue() && LHSVal.isInt()) {<br>
@@ -8192,7 +8162,7 @@ bool DataRecursiveIntBinOpEvaluator<wbr>::<br>
addOrSubLValueAsInteger(<wbr>Result, LHSVal.getInt(), /*IsSub*/false);<br>
return true;<br>
}<br>
-<br>
+<br>
if (E->getOpcode() == BO_Sub && LHSVal.isLValue() && RHSVal.isLValue()) {<br>
// Handle (intptr_t)&&A - (intptr_t)&&B.<br>
if (!LHSVal.getLValueOffset().<wbr>isZero() ||<br>
@@ -8231,7 +8201,7 @@ bool DataRecursiveIntBinOpEvaluator<wbr>::<br>
<br>
void DataRecursiveIntBinOpEvaluator<wbr>::process(EvalResult &Result) {<br>
Job &job = Queue.back();<br>
-<br>
+<br>
switch (job.Kind) {<br>
case Job::AnyExprKind: {<br>
if (const BinaryOperator *Bop = dyn_cast<BinaryOperator>(job.<wbr>E)) {<br>
@@ -8241,12 +8211,12 @@ void DataRecursiveIntBinOpEvaluator<wbr>::pro<br>
return;<br>
}<br>
}<br>
-<br>
+<br>
EvaluateExpr(job.E, Result);<br>
Queue.pop_back();<br>
return;<br>
}<br>
-<br>
+<br>
case Job::BinOpKind: {<br>
const BinaryOperator *Bop = cast<BinaryOperator>(job.E);<br>
bool SuppressRHSDiags = false;<br>
@@ -8261,7 +8231,7 @@ void DataRecursiveIntBinOpEvaluator<wbr>::pro<br>
enqueue(Bop->getRHS());<br>
return;<br>
}<br>
-<br>
+<br>
case Job::BinOpVisitedLHSKind: {<br>
const BinaryOperator *Bop = cast<BinaryOperator>(job.E);<br>
EvalResult RHS;<br>
@@ -8271,7 +8241,7 @@ void DataRecursiveIntBinOpEvaluator<wbr>::pro<br>
return;<br>
}<br>
}<br>
-<br>
+<br>
llvm_unreachable("Invalid Job::Kind!");<br>
}<br>
<br>
@@ -8783,7 +8753,7 @@ bool IntExprEvaluator::<wbr>VisitOffsetOfExpr<br>
const RecordType *BaseRT = CurrentType->getAs<RecordType><wbr>();<br>
if (!BaseRT)<br>
return Error(OOE);<br>
-<br>
+<br>
// Add the offset to the base.<br>
Result += RL.getBaseClassOffset(cast<<wbr>CXXRecordDecl>(BaseRT-><wbr>getDecl()));<br>
break;<br>
@@ -9978,7 +9948,7 @@ static bool FastEvaluateAsRValue(const E<br>
IsConst = false;<br>
return true;<br>
}<br>
-<br>
+<br>
// FIXME: Evaluating values of large array and record types can cause<br>
// performance problems. Only do so in C++11 for now.<br>
if (Exp->isRValue() && (Exp->getType()->isArrayType() ||<br>
@@ -10000,7 +9970,7 @@ bool Expr::EvaluateAsRValue(<wbr>EvalResult &<br>
bool IsConst;<br>
if (FastEvaluateAsRValue(this, Result, Ctx, IsConst, false))<br>
return IsConst;<br>
-<br>
+<br>
EvalInfo Info(Ctx, Result, EvalInfo::EM_<wbr>IgnoreSideEffects);<br>
return ::EvaluateAsRValue(Info, this, Result.Val);<br>
}<br>
<br>
Removed: cfe/trunk/test/SemaCXX/<wbr>constexpr-array-unknown-bound.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-array-unknown-bound.cpp?rev=301962&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/<wbr>SemaCXX/constexpr-array-<wbr>unknown-bound.cpp?rev=301962&<wbr>view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/SemaCXX/<wbr>constexpr-array-unknown-bound.<wbr>cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/<wbr>constexpr-array-unknown-bound.<wbr>cpp (removed)<br>
@@ -1,25 +0,0 @@<br>
-// RUN: %clang_cc1 %s -Wno-uninitialized -std=c++1z -fsyntax-only -verify<br>
-<br>
-const extern int arr[];<br>
-constexpr auto p = arr; // ok<br>
-constexpr int f(int i) {return p[i];} // expected-note {{read of dereferenced one-past-the-end pointer}}<br>
-<br>
-constexpr int arr[] {1, 2, 3};<br>
-constexpr auto p2 = arr + 2; // ok<br>
-constexpr int x = f(2); // ok<br>
-constexpr int y = f(3); // expected-error {{constant expression}}<br>
-// expected-note-re@-1 {{in call to 'f({{.*}})'}}<br>
-<br>
-struct A {int m[];} a;<br>
-constexpr auto p3 = a.m; // ok<br>
-constexpr auto p4 = a.m + 1; // expected-error {{constant expression}} expected-note {{constant bound}}<br>
-<br>
-void g(int i) {<br>
- int arr[i];<br>
- constexpr auto *p = arr + 2; // expected-error {{constant expression}} expected-note {{constant bound}}<br>
-<br>
- // FIXME: Give a better diagnostic here. The issue is that computing<br>
- // sizeof(*arr2) within the array indexing fails due to the VLA.<br>
- int arr2[2][i];<br>
- constexpr int m = ((void)arr2[2], 0); // expected-error {{constant expression}}<br>
-}<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></div>