[clang] c1c1bed - [c++14] Implement missed piece of N3323: use "converted constant" rules
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 19 15:46:07 PDT 2020
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 at 168 {{ambiguous conversion of array size expression of type 'extended_examples_array_bounds::Foo' to an integral or enumeration type}}
-//expected-note at 162 {{conversion to integral type 'extended_examples_array_bounds::size_t'}}
-//expected-note at 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}}
+ }
+}
More information about the cfe-commits
mailing list