r301963 - Revert r301822 (and dependent r301825), which tried to improve the

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Tue May 2 13:42:03 PDT 2017


On 2 May 2017 at 12:21, Daniel Jasper via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> Author: djasper
> Date: Tue May  2 14:21:42 2017
> New Revision: 301963
>
> URL: http://llvm.org/viewvc/llvm-project?rev=301963&view=rev
> Log:
> Revert r301822 (and dependent r301825), which tried to improve the
> handling of constexprs with unknown bounds.
>
> This triggers a corner case of the language where it's not yet clear
> whether this should be an error:
>
>   struct A {
>     static void *const a[];
>     static void *const b[];
>   };
>   constexpr void *A::a[] = {&b[0]};
>   constexpr void *A::b[] = {&a[0]};
>
> When discovering the initializer for A::a, the bounds of A::b aren't known
> yet.
> It is unclear whether warning about errors should be deferred until the
> end of
> the translation unit, possibly resolving errors that can be resolved. In
> practice, the compiler can know the bounds of all arrays in this example.
>

I've started a discussion on the C++ core reflector about this.


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


More information about the cfe-commits mailing list