Index: include/clang/Basic/DiagnosticASTKinds.td =================================================================== --- include/clang/Basic/DiagnosticASTKinds.td +++ include/clang/Basic/DiagnosticASTKinds.td @@ -154,12 +154,14 @@ 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_decay : Note< + "cannot perform array to pointer conversion on array of unknown bound">; def warn_integer_constant_overflow : Warning< "overflow in expression; result is %0 with type %1">, InGroup>; -// 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< Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -495,7 +495,7 @@ // 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 = @@ -720,7 +720,7 @@ 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, @@ -773,7 +773,7 @@ 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) { @@ -2619,10 +2619,23 @@ LastField = nullptr; if (ObjType->isArrayType()) { // Next subobject is an array element. - const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType); - assert(CAT && "vla in literal type?"); + uint64_t actualIndex; + const ArrayType *AT = Info.Ctx.getAsArrayType(ObjType); // non-null by assumption + if (I == 0) { + /* we're dealing with the complete array object, which may have been declared + without a bound */ + actualIndex = Sub.MostDerivedArraySize; + assert(Sub.MostDerivedIsArrayElement && "Complete object is an array, but isn't?"); + } + else { + /* ... the array must have been given a bound + ([dcl.array]/3 for both subarrays and members). */ + auto CAT = dyn_cast(AT); + assert(CAT && "vla in literal type?"); + actualIndex = CAT->getSize().getZExtValue(); + } uint64_t Index = Sub.Entries[I].ArrayIndex; - if (CAT->getSize().ule(Index)) { + if (actualIndex <= Index) { // Note, it should not be possible to form a pointer with a valid // designator which points more than one past the end of the array. if (Info.getLangOpts().CPlusPlus11) @@ -2633,7 +2646,7 @@ return handler.failed(); } - ObjType = CAT->getElementType(); + ObjType = AT->getElementType(); // An array object is represented as either an Array APValue or as an // LValue which refers to a string literal. @@ -4098,13 +4111,13 @@ 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(DiagDecl); if (CD && CD->isInheritingConstructor()) { auto *Inherited = CD->getInheritedConstructor().getConstructor(); - if (!Inherited->isConstexpr()) + if (!Inherited->isConstexpr()) DiagDecl = CD = Inherited; } @@ -4635,7 +4648,7 @@ 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 @@ -4670,7 +4683,7 @@ FD = LambdaCallOp; } - + } else return Error(E); @@ -5501,7 +5514,7 @@ // 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() @@ -5636,7 +5649,8 @@ if (SubExpr->isGLValue()) { if (!evaluateLValue(SubExpr, Result)) return false; - } else { + } + else { Result.set(SubExpr, Info.CurrentCall->Index); if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false), Info, Result, SubExpr)) @@ -5646,6 +5660,18 @@ if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(SubExpr->getType())) Result.addArray(Info, E, CAT); + // If the type of the expression is an array of unknown bound, the lvalue must refer + // to a declared object. We must check whether its type has been completed. + else if (auto decl = Result.Base.dyn_cast()) { + // make sure to consider the completed type. + if (auto CAT = Info.Ctx.getAsConstantArrayType(cast( + decl->getMostRecentDecl())->getType())) + Result.addArray(Info, E, CAT); + else { + Result.Designator.setInvalid(); + CCEDiag(SubExpr, diag::note_constexpr_array_unknown_bound_decay); + } + } else Result.Designator.setInvalid(); return true; @@ -6345,7 +6371,7 @@ if (ClosureClass->isInvalidDecl()) return false; if (Info.checkingPotentialConstantExpression()) return true; - + const size_t NumFields = std::distance(ClosureClass->field_begin(), ClosureClass->field_end()); @@ -6364,7 +6390,7 @@ 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) @@ -6565,18 +6591,18 @@ // 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()) { @@ -6852,7 +6878,7 @@ } 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."); @@ -6866,7 +6892,7 @@ } 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; @@ -6942,7 +6968,7 @@ } return Success(Info.ArrayInitIndex, E); } - + // Note, GNU defines __null as an integer, not a pointer. bool VisitGNUNullExpr(const GNUNullExpr *E) { return ZeroInitialization(E); @@ -8096,12 +8122,12 @@ 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) @@ -8117,26 +8143,26 @@ 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()) { @@ -8144,7 +8170,7 @@ 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() || @@ -8183,7 +8209,7 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { Job &job = Queue.back(); - + switch (job.Kind) { case Job::AnyExprKind: { if (const BinaryOperator *Bop = dyn_cast(job.E)) { @@ -8193,12 +8219,12 @@ return; } } - + EvaluateExpr(job.E, Result); Queue.pop_back(); return; } - + case Job::BinOpKind: { const BinaryOperator *Bop = cast(job.E); bool SuppressRHSDiags = false; @@ -8213,7 +8239,7 @@ enqueue(Bop->getRHS()); return; } - + case Job::BinOpVisitedLHSKind: { const BinaryOperator *Bop = cast(job.E); EvalResult RHS; @@ -8223,7 +8249,7 @@ return; } } - + llvm_unreachable("Invalid Job::Kind!"); } @@ -8735,7 +8761,7 @@ const RecordType *BaseRT = CurrentType->getAs(); if (!BaseRT) return Error(OOE); - + // Add the offset to the base. Result += RL.getBaseClassOffset(cast(BaseRT->getDecl())); break; @@ -9929,7 +9955,7 @@ 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() || @@ -9951,7 +9977,7 @@ bool IsConst; if (FastEvaluateAsRValue(this, Result, Ctx, IsConst)) return IsConst; - + EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects); return ::EvaluateAsRValue(Info, this, Result.Val); }