<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>