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