[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