Author: Richard Smith Date: 2020-08-19T15:45:51-07:00 New Revision: c1c1bed5d0828f1905f1e9a09a32c02f05de9b41
URL: https://github.com/llvm/llvm-project/commit/c1c1bed5d0828f1905f1e9a09a32c02f05de9b41 DIFF: https://github.com/llvm/llvm-project/commit/c1c1bed5d0828f1905f1e9a09a32c02f05de9b41.diff LOG: [c++14] Implement missed piece of N3323: use "converted constant" rules for array bounds, not "integer constant" rules. For an array bound of class type, this causes us to perform an implicit conversion to size_t, instead of looking for a unique conversion to integral or unscoped enumeration type. This affects which cases are valid when a class has multiple implicit conversion functions to different types. Added: Modified: clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaExprCXX.cpp clang/lib/Sema/SemaOverload.cpp clang/lib/Sema/SemaType.cpp clang/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fb9f442bc5bc..49ab94f9df14 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3213,7 +3213,7 @@ class Sema final { CCEK_CaseValue, ///< Expression in a case label. CCEK_Enumerator, ///< Enumerator value with fixed underlying type. CCEK_TemplateArg, ///< Value of a non-type template parameter. - CCEK_NewExpr, ///< Constant expression in a noptr-new-declarator. + CCEK_ArrayBound, ///< Array bound in array declarator or new-expression. CCEK_ConstexprIf, ///< Condition in a constexpr if statement. CCEK_ExplicitBool ///< Condition in an explicit(bool) specifier. }; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 335ee95715d0..132f5b0f1721 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1760,12 +1760,10 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, // C++1y [expr.new]p6: Every constant-expression in a noptr-new-declarator // shall be a converted constant expression (5.19) of type std::size_t // and shall evaluate to a strictly positive value. - unsigned IntWidth = Context.getTargetInfo().getIntWidth(); - assert(IntWidth && "Builtin type of size 0?"); - llvm::APSInt Value(IntWidth); + llvm::APSInt Value(Context.getIntWidth(Context.getSizeType())); Array.NumElts = CheckConvertedConstantExpression(NumElts, Context.getSizeType(), Value, - CCEK_NewExpr) + CCEK_ArrayBound) .get(); } else { Array.NumElts diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index bcf6aa7a310e..dc0098964be4 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -5628,6 +5628,7 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, return Result; // Check for a narrowing implicit conversion. + bool ReturnPreNarrowingValue = false; APValue PreNarrowingValue; QualType PreNarrowingType; switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue, @@ -5642,12 +5643,22 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, break; case NK_Constant_Narrowing: + if (CCE == Sema::CCEK_ArrayBound && + PreNarrowingType->isIntegralOrEnumerationType() && + PreNarrowingValue.isInt()) { + // Don't diagnose array bound narrowing here; we produce more precise + // errors by allowing the un-narrowed value through. + ReturnPreNarrowingValue = true; + break; + } S.Diag(From->getBeginLoc(), diag::ext_cce_narrowing) << CCE << /*Constant*/ 1 << PreNarrowingValue.getAsString(S.Context, PreNarrowingType) << T; break; case NK_Type_Narrowing: + // FIXME: It would be better to diagnose that the expression is not a + // constant expression. S.Diag(From->getBeginLoc(), diag::ext_cce_narrowing) << CCE << /*Constant*/ 0 << From->getType() << T; break; @@ -5676,7 +5687,10 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, if (Notes.empty()) { // It's a constant expression. - return ConstantExpr::Create(S.Context, Result.get(), Value); + Expr *E = ConstantExpr::Create(S.Context, Result.get(), Value); + if (ReturnPreNarrowingValue) + Value = std::move(PreNarrowingValue); + return E; } } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index fb62250564b5..c08d4426e5b8 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2229,6 +2229,21 @@ QualType Sema::BuildExtIntType(bool IsUnsigned, Expr *BitWidth, static ExprResult checkArraySize(Sema &S, Expr *&ArraySize, llvm::APSInt &SizeVal, unsigned VLADiag, bool VLAIsError) { + if (S.getLangOpts().CPlusPlus14 && + (VLAIsError || + !ArraySize->getType()->isIntegralOrUnscopedEnumerationType())) { + // C++14 [dcl.array]p1: + // The constant-expression shall be a converted constant expression of + // type std::size_t. + // + // Don't apply this rule if we might be forming a VLA: in that case, we + // allow non-constant expressions and constant-folding. We only need to use + // the converted constant expression rules (to properly convert the source) + // when the source expression is of class type. + return S.CheckConvertedConstantExpression( + ArraySize, S.Context.getSizeType(), SizeVal, Sema::CCEK_ArrayBound); + } + // If the size is an ICE, it certainly isn't a VLA. If we're in a GNU mode // (like gnu99, but not c99) accept any evaluatable value as an extension. class VLADiagnoser : public Sema::VerifyICEDiagnoser { diff --git a/clang/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp b/clang/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp index 7cb83c6f8876..19ad70de44fd 100644 --- a/clang/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp +++ b/clang/test/SemaCXX/cxx1y-contextual-conversion-tweaks.cpp @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only %s -// RUN: %clang_cc1 -std=c++1y %s -verify -DCXX1Y +// RUN: %clang_cc1 -std=c++11 -verify=expected,cxx11 -fsyntax-only -pedantic-errors %s +// RUN: %clang_cc1 -std=c++14 -verify=expected,cxx14 -fsyntax-only -pedantic-errors %s -DCXX1Y // Explicit member declarations behave as in C++11. @@ -155,23 +155,41 @@ namespace extended_examples_cxx1y { #endif namespace extended_examples_array_bounds { - + typedef decltype(sizeof(int)) size_t; - - struct Foo { - operator size_t(); // @162 - operator unsigned short(); // @163 + + struct X { + constexpr operator size_t() const { return 1; } // cxx11-note 3{{conversion}} + constexpr operator unsigned short() const { return 0; } // cxx11-note 3{{conversion}} }; - void bar() { - Foo x; - int *p = new int[x]; // @168 + void f() { + X x; + int *p = new int[x]; // cxx11-error {{ambiguous}} + + int arr[x]; // cxx11-error {{ambiguous}} + int (*q)[1] = new int[1][x]; // cxx11-error {{ambiguous}} } -} -#ifdef CXX1Y -#else -//expected-error@168 {{ambiguous conversion of array size expression of type 'extended_examples_array_bounds::Foo' to an integral or enumeration type}} -//expected-note@162 {{conversion to integral type 'extended_examples_array_bounds::size_t'}} -//expected-note@163 {{conversion to integral type 'unsigned short' declared here}} -#endif + struct Y { + constexpr operator float() const { return 0.0f; } // cxx14-note 3{{candidate}} + constexpr operator int() const { return 1; } // cxx14-note 3{{candidate}} + }; + + void g() { + Y y; + int *p = new int[y]; // cxx14-error {{ambiguous}} + + int arr[y]; // cxx14-error {{ambiguous}} + int (*q)[1] = new int[1][y]; // cxx14-error {{ambiguous}} + } + + template<int N> struct Z { + constexpr operator int() const { return N; } + }; + void h() { + int arrA[Z<1>()]; + int arrB[Z<0>()]; // expected-error {{zero size array}} + int arrC[Z<-1>()]; // expected-error {{'arrC' declared as an array with a negative size}} + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits