lichray updated this revision to Diff 410915.
lichray added a comment.

- Add more tests to diagnose other forms of casts


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D113393/new/

https://reviews.llvm.org/D113393

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Parse/ParseDeclCXX.cpp
  clang/lib/Parse/ParseExpr.cpp
  clang/lib/Parse/ParseExprCXX.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
  clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp
  clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
  clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
  clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp
  clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp
  clang/test/Parser/cxx2b-auto-x.cpp
  clang/test/SemaCXX/deduced-return-type-cxx14.cpp
  clang/www/cxx_status.html

Index: clang/www/cxx_status.html
===================================================================
--- clang/www/cxx_status.html
+++ clang/www/cxx_status.html
@@ -1388,6 +1388,11 @@
       <td><a href="https://wg21.link/P2360R0";>P2360R0</a></td>
       <td class="unreleased" align="center">Clang 14</td>
     </tr>
+    <tr>
+      <td>auto(x): decay-copy in the language</td>
+      <td><a href="https://wg21.link/P0849R8";>P0849R8</a></td>
+      <td class="unreleased" align="center">Clang 15</td>
+    </tr>
     <!-- February 2022 papers -->
     <tr>
       <td>Attributes on Lambda-Expressions</td>
Index: clang/test/SemaCXX/deduced-return-type-cxx14.cpp
===================================================================
--- clang/test/SemaCXX/deduced-return-type-cxx14.cpp
+++ clang/test/SemaCXX/deduced-return-type-cxx14.cpp
@@ -442,6 +442,15 @@
       B() : decltype(auto)() {} // expected-error {{'decltype(auto)' not allowed here}}
     };
   }
+
+  namespace Cast {
+    void foo() {
+      (void)decltype(auto)(0); // cxx14_20-error{{'decltype(auto)' not allowed here}} \
+                                  cxx2b-warning{{functional-style cast to 'decltype(auto)' is a Clang extension}}
+      (void)decltype(auto){0}; // cxx14_20-error{{'decltype(auto)' not allowed here}} \
+                                  cxx2b-warning{{functional-style cast to 'decltype(auto)' is a Clang extension}}
+    }
+  }
 }
 
 namespace CurrentInstantiation {
Index: clang/test/Parser/cxx2b-auto-x.cpp
===================================================================
--- /dev/null
+++ clang/test/Parser/cxx2b-auto-x.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx2b -std=c++2b -Wpre-c++2b-compat %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 -std=c++20 %s
+
+void looks_like_decltype_auto() {
+  decltype(auto(42)) b = 42; // cxx20-error {{'auto' not allowed here}} \
+                                cxx2b-warning {{'auto' as a functional-style cast is incompatible with C++ standards before C++2b}}
+  decltype(long *) a = 42;   // expected-error {{expected '(' for function-style cast or type construction}} \
+                                expected-error {{expected expression}}
+  decltype(auto *) a = 42;   // expected-error {{expected '(' for function-style cast or type construction}} \
+                                expected-error {{expected expression}}
+  decltype(auto()) c = 42;   // cxx2b-error {{initializer for functional-style cast to 'auto' is empty}} \
+                                cxx20-error {{'auto' not allowed here}}
+}
+
+struct looks_like_declaration {
+  int n;
+} a;
+
+using T = looks_like_declaration *;
+void f() { T(&a)->n = 1; }
+// FIXME: They should be deemed expressions without breaking function pointer
+//        parameter declarations with trailing return types.
+// void g() { auto(&a)->n = 0; }
+// void h() { auto{&a}->n = 0; }
Index: clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp
===================================================================
--- clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp
+++ clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp
@@ -1,11 +1,30 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++17 -pedantic
 
+// [expr.new]p2 ... the invented declaration: T x init ;
+// C++2b [dcl.type.auto.deduct]p2.2
+// For a variable declared with a type that contains a placeholder type, T is the declared type of the variable.
 void f() {
+  // - If the initializer is a parenthesized expression-list, the expression-list shall be a single assignmentexpression and E is the assignment-expression.
   new auto('a');
-  new auto {2};
-  new auto {1, 2}; // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
-  new auto {}; // expected-error{{new expression for type 'auto' requires a constructor argument}}
-  new decltype(auto)({1});
-  new decltype(auto)({1, 2}); // expected-error{{new expression for type 'decltype(auto)' contains multiple constructor arguments}}
+  new decltype(auto)('a');
+  // - If the initializer is a braced-init-list, it shall consist of a single brace-enclosed assignment-expression and E is the assignment-expression.
+  new auto{2};
+  new decltype(auto){2};
+
+  new auto{};   // expected-error{{new expression for type 'auto' requires a constructor argument}}
+  new auto({}); // expected-error{{cannot deduce actual type for 'auto' from parenthesized initializer list}}
+  new auto{{}}; // expected-error{{cannot deduce actual type for 'auto' from nested initializer list}}
+
+  new auto({2});  // expected-error{{cannot deduce actual type for 'auto' from parenthesized initializer list}}
+  new auto{{2}};  // expected-error{{cannot deduce actual type for 'auto' from nested initializer list}}
+  new auto{1, 2}; // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
+
+  new decltype(auto){};   // expected-error{{new expression for type 'decltype(auto)' requires a constructor argument}}
+  new decltype(auto)({}); // expected-error{{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
+  new decltype(auto){{}}; // expected-error{{cannot deduce actual type for 'decltype(auto)' from nested initializer list}}
+
+  new decltype(auto)({1});    // expected-error{{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
+  new decltype(auto){1, 2};   // expected-error{{new expression for type 'decltype(auto)' contains multiple constructor arguments}}
+  new decltype(auto)({1, 2}); // expected-error{{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
 }
Index: clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp
===================================================================
--- clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp
+++ clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp
@@ -5,6 +5,6 @@
   new auto {2}; // expected-warning {{ISO C++ standards before C++17 do not allow new expression for type 'auto' to use list-initialization}}
   new auto {1, 2}; // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
   new auto {}; // expected-error{{new expression for type 'auto' requires a constructor argument}}
-  new decltype(auto)({1}); // expected-warning {{ISO C++ standards before C++17 do not allow new expression for type 'decltype(auto)' to use list-initialization}}
-  new decltype(auto)({1, 2}); // expected-error{{new expression for type 'decltype(auto)' contains multiple constructor arguments}}
+  new decltype(auto)({1}); // expected-error{{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
+  new decltype(auto)({1, 2}); // expected-error{{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
 }
Index: clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
===================================================================
--- clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
+++ clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
@@ -16,7 +16,7 @@
   new (auto) (1,2,3); // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
   new auto {}; // expected-error{{new expression for type 'auto' requires a constructor argument}}
   new auto {1,2,3}; // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
-  new auto ({1,2,3}); // expected-error{{new expression for type 'auto' contains multiple constructor arguments}}
+  new auto ({1,2,3}); // expected-error{{cannot deduce actual type for 'auto' from parenthesized initializer list}}
 }
 
 void p2example() {
Index: clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -std=c++2b -Wno-decltype-auto-cast -verify %s
+
+template <class T>
+void foo(T);
+
+struct A {
+  int m;
+  char g(int);
+  float g(double);
+} a{1};
+
+// C++2b [dcl.type.auto.deduct]p2.3
+// For an explicit type conversion, T is the specified type, which shall be auto.
+void diagnostics() {
+  foo(auto());   // expected-error {{initializer for functional-style cast to 'auto' is empty}}
+  foo(auto{});   // expected-error {{initializer for functional-style cast to 'auto' is empty}}
+  foo(auto({})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
+  foo(auto{{}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
+
+  // - If the initializer is a parenthesized expression-list, the expression-list shall be a single assignmentexpression and E is the assignment-expression.
+  foo(auto(a));
+  // - If the initializer is a braced-init-list, it shall consist of a single brace-enclosed assignment-expression and E is the assignment-expression.
+  foo(auto{a});
+  foo(auto({a})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
+  foo(auto{{a}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
+
+  foo(auto(&A::g)); // expected-error {{functional-style cast to 'auto' has incompatible initializer of type '<overloaded function type>'}}
+
+  foo(auto(a, 3.14));     // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
+  foo(auto{a, 3.14});     // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
+  foo(auto({a, 3.14}));   // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
+  foo(auto{{a, 3.14}});   // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
+  foo(auto({a}, {3.14})); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
+  foo(auto{{a}, {3.14}}); // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
+
+  foo(auto{1, 2});   // expected-error {{initializer for functional-style cast to 'auto' contains multiple expressions}}
+  foo(auto({1, 2})); // expected-error {{cannot deduce actual type for 'auto' from parenthesized initializer list}}
+  foo(auto{{1, 2}}); // expected-error {{cannot deduce actual type for 'auto' from nested initializer list}}
+}
+
+void diagnostics_extension() {
+  foo(decltype(auto)());   // expected-error {{initializer for functional-style cast to 'decltype(auto)' is empty}}
+  foo(decltype(auto){});   // expected-error {{initializer for functional-style cast to 'decltype(auto)' is empty}}
+  foo(decltype(auto)({})); // expected-error {{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
+  foo(decltype(auto){{}}); // expected-error {{cannot deduce actual type for 'decltype(auto)' from nested initializer list}}
+
+  foo(decltype(auto)({a})); // expected-error {{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
+  foo(decltype(auto){{a}}); // expected-error {{cannot deduce actual type for 'decltype(auto)' from nested initializer list}}
+
+  foo(decltype(auto)(&A::g)); // expected-error {{reference to overloaded function could not be resolved}}
+
+  foo(decltype(auto)(a, 3.14));     // expected-error {{initializer for functional-style cast to 'decltype(auto)' contains multiple expressions}}
+  foo(decltype(auto){a, 3.14});     // expected-error {{initializer for functional-style cast to 'decltype(auto)' contains multiple expressions}}
+  foo(decltype(auto)({a, 3.14}));   // expected-error {{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
+  foo(decltype(auto){{a, 3.14}});   // expected-error {{cannot deduce actual type for 'decltype(auto)' from nested initializer list}}
+  foo(decltype(auto)({a}, {3.14})); // expected-error {{initializer for functional-style cast to 'decltype(auto)' contains multiple expressions}}
+  foo(decltype(auto){{a}, {3.14}}); // expected-error {{initializer for functional-style cast to 'decltype(auto)' contains multiple expressions}}
+
+  foo(decltype(auto){1, 2});   // expected-error {{initializer for functional-style cast to 'decltype(auto)' contains multiple expressions}}
+  foo(decltype(auto)({1, 2})); // expected-error {{cannot deduce actual type for 'decltype(auto)' from parenthesized initializer list}}
+  foo(decltype(auto){{1, 2}}); // expected-error {{cannot deduce actual type for 'decltype(auto)' from nested initializer list}}
+}
Index: clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp
@@ -0,0 +1,185 @@
+// RUN: %clang_cc1 -std=c++2b -Wno-decltype-auto-cast -verify %s
+
+// p2.3 allows only T = auto in T(x).
+// As a Clang extension, we also allow T = decltype(auto) to match p2.2 (new T(x)).
+
+void test_decay() {
+  int v[3];
+  static_assert(__is_same(decltype(auto(v)), int *));
+  static_assert(__is_same(decltype(auto{v}), int *));
+  static_assert(__is_same(decltype(auto("lit")), char const *));
+  static_assert(__is_same(decltype(auto{"lit"}), char const *));
+
+  void(decltype(auto)(v)); // expected-error {{functional-style cast}}
+  void(decltype(auto){v}); // expected-error {{cannot initialize an array element}}
+  static_assert(__is_same(decltype(decltype(auto)("lit")), char const(&)[4]));
+  static_assert(__is_same(decltype(decltype(auto){"lit"}), char const(&)[4]));
+
+  int fn(char *);
+  static_assert(__is_same(decltype(auto(fn)), int (*)(char *)));
+  static_assert(__is_same(decltype(auto{fn}), int (*)(char *)));
+
+  void(decltype(auto)(fn)); // expected-error{{functional-style cast}}
+  void(decltype(auto){fn}); // expected-error{{cannot create object of function type}}
+
+  constexpr long i = 1;
+  static_assert(__is_same(decltype(i), long const));
+  static_assert(__is_same(decltype(auto(1L)), long));
+  static_assert(__is_same(decltype(auto{1L}), long));
+  static_assert(__is_same(decltype(auto(i)), long));
+  static_assert(__is_same(decltype(auto{i}), long));
+
+  // scalar prvalue is not cv-qualified
+  static_assert(__is_same(decltype(decltype(auto)(1L)), long));
+  static_assert(__is_same(decltype(decltype(auto){1L}), long));
+  static_assert(__is_same(decltype(decltype(auto)(i)), long));
+  static_assert(__is_same(decltype(decltype(auto){i}), long));
+
+  class A {
+  } a;
+  A const ac;
+
+  static_assert(__is_same(decltype(auto(a)), A));
+  static_assert(__is_same(decltype(auto(ac)), A));
+
+  static_assert(__is_same(decltype(decltype(auto)(a)), A));
+  static_assert(__is_same(decltype(decltype(auto)(ac)), A const));
+
+  static_assert(__is_same(decltype(decltype(auto)((a))), A &));
+  static_assert(__is_same(decltype(decltype(auto)((ac))), A const &));
+
+  static_assert(__is_same(decltype(decltype(auto){a}), A));
+  static_assert(__is_same(decltype(decltype(auto){ac}), A const));
+
+  static_assert(__is_same(decltype(decltype(auto){(a)}), A &));
+  static_assert(__is_same(decltype(decltype(auto){(ac)}), A const &));
+
+  A &lr = a;
+  A const &lrc = a;
+  A &&rr = static_cast<A &&>(a);
+  A const &&rrc = static_cast<A &&>(a);
+
+  static_assert(__is_same(decltype(auto(lr)), A));
+  static_assert(__is_same(decltype(auto(lrc)), A));
+  static_assert(__is_same(decltype(auto(rr)), A));
+  static_assert(__is_same(decltype(auto(rrc)), A));
+
+  static_assert(__is_same(decltype(decltype(auto)(lr)), A &));
+  static_assert(__is_same(decltype(decltype(auto)(lrc)), A const &));
+  static_assert(__is_same(decltype(decltype(auto)(rr)), A &&));
+  static_assert(__is_same(decltype(decltype(auto)(rrc)), A const &&));
+}
+
+class cmdline_parser {
+public:
+  cmdline_parser(char const *);
+  auto add_option(char const *, char const *) && -> cmdline_parser &&;
+};
+
+void test_rvalue_fluent_interface() {
+  auto cmdline = cmdline_parser("driver");
+  auto internal = auto{cmdline}.add_option("--dump-full", "do not minimize dump");
+}
+
+template <class T> constexpr auto decay_copy(T &&v) { return static_cast<T &&>(v); } // expected-error {{calling a protected constructor}}
+
+class A {
+  int x;
+  friend void f(A &&);
+
+public:
+  A();
+
+  auto test_access() {
+    static_assert(__is_same(decltype(auto(*this)), A));
+    static_assert(__is_same(decltype(auto(this)), A *));
+
+    f(A(*this));          // ok
+    f(auto(*this));       // ok in P0849
+    f(decay_copy(*this)); // expected-note {{in instantiation of function template specialization}}
+  }
+
+  auto test_access() const {
+    static_assert(__is_same(decltype(auto(*this)), A)); // ditto
+    static_assert(__is_same(decltype(auto(this)), A const *));
+  }
+
+protected:
+  A(const A &); // expected-note {{declared protected here}}
+};
+
+// post-C++17 semantics
+namespace auto_x {
+constexpr struct Uncopyable {
+  constexpr explicit Uncopyable(int) {}
+  constexpr Uncopyable(Uncopyable &&) = delete;
+} u = auto(Uncopyable(auto(Uncopyable(42))));
+} // namespace auto_x
+
+// decltype(auto) is no-op to prvalues
+namespace decltype_auto_x {
+constexpr struct Uncopyable {
+  constexpr explicit Uncopyable(int) {}
+  constexpr Uncopyable(Uncopyable &&) = delete;
+} u = decltype(auto)(Uncopyable(decltype(auto)(Uncopyable(42))));
+} // namespace decltype_auto_x
+
+// Forward with decltype(auto)
+constexpr auto invoke1 = [](auto &&x, auto &&y) {
+  return decltype(auto)(x)(decltype(auto)(y));
+};
+
+struct MoveOnly {
+  MoveOnly() = default;
+  MoveOnly(MoveOnly &&) = default;
+  MoveOnly(MoveOnly const &) = delete;
+};
+
+constexpr MoveOnly getMoveOnly() { return {}; }
+
+struct Fn {
+  constexpr int operator()(MoveOnly &) & { return 0; }
+  constexpr int operator()(MoveOnly &&) & { return 1; }
+
+  constexpr int operator()(MoveOnly &) && { return 2; }
+  constexpr int operator()(MoveOnly &&) && { return 3; }
+
+  constexpr int operator()(MoveOnly &) const & { return 4; }
+  constexpr int operator()(MoveOnly &&) const & { return 5; }
+
+  constexpr int operator()(MoveOnly &) const && { return 6; }
+  constexpr int operator()(MoveOnly &&) const && { return 7; }
+};
+
+constexpr void FwdWithDecltypeAuto() {
+  MoveOnly lv;
+  Fn f;
+  constexpr Fn cf;
+
+  static_assert(invoke1(f, lv) == 0);
+  static_assert(invoke1(f, getMoveOnly()) == 1);
+
+  static_assert(invoke1(Fn{}, lv) == 2);
+  static_assert(invoke1(Fn{}, getMoveOnly()) == 3);
+
+  static_assert(invoke1(cf, lv) == 4);
+  static_assert(invoke1(cf, getMoveOnly()) == 5);
+
+  static_assert(invoke1((Fn const){}, lv) == 6);
+  static_assert(invoke1((Fn const){}, getMoveOnly()) == 7);
+}
+
+struct FnArray {
+  template <class T, int N>
+  constexpr int operator()(T (&)[N]) const { return 0; }
+
+  template <class T, int N>
+  constexpr int operator()(T (&&)[N]) const { return 1; }
+};
+
+constexpr void FwdArrayWithDecltypeAuto() {
+  FnArray f;
+
+  static_assert(invoke1(f, "foo") == 0);
+  static_assert(invoke1(f, (int[]){1, 2, 3}) == 1);
+}
Index: clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
+++ clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
@@ -46,13 +46,18 @@
   U<auto> v; // expected-error{{'auto' not allowed in template argument}}
 
   int n;
-  (void)dynamic_cast<auto&>(n); // expected-error{{'auto' not allowed here}}
-  (void)static_cast<auto*>(&n); // expected-error{{'auto' not allowed here}}
-  (void)reinterpret_cast<auto*>(&n); // expected-error{{'auto' not allowed here}}
-  (void)const_cast<auto>(n); // expected-error{{'auto' not allowed here}}
-  (void)*(auto*)(&n); // expected-error{{'auto' not allowed here}}
-  (void)auto(n); // expected-error{{expected expression}}
-  (void)auto{n}; // expected-error{{expected expression}}
+  (void)dynamic_cast<auto &>(n);      // expected-error{{'auto' not allowed here}}
+  (void)static_cast<auto *>(&n);      // expected-error{{'auto' not allowed here}}
+  (void)reinterpret_cast<auto *>(&n); // expected-error{{'auto' not allowed here}}
+  (void)const_cast<auto const>(n);    // expected-error{{'auto' not allowed here}}
+  (void)*(auto *)(&n);                // expected-error{{'auto' not allowed here}}
+  (void)dynamic_cast<auto>(n);        // expected-error{{'auto' not allowed here}}
+  (void)static_cast<auto>(n);         // expected-error{{'auto' not allowed here}}
+  (void)reinterpret_cast<auto>(n);    // expected-error{{'auto' not allowed here}}
+  (void)const_cast<auto>(n);          // expected-error{{'auto' not allowed here}}
+  (void)(auto)(n);                    // expected-error{{'auto' not allowed here}}
+  (void)auto(n);                      // expected-error{{'auto' not allowed here}}
+  (void)auto {n};                     // expected-error{{'auto' not allowed here}}
 }
 
 template <auto a = 10> class C { }; // expected-error{{'auto' not allowed in template parameter}}
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -3506,6 +3506,8 @@
     case DeclaratorContext::FunctionalCast:
       if (isa<DeducedTemplateSpecializationType>(Deduced))
         break;
+      if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType)
+        break; // auto(x) and decltype(auto)(x)
       LLVM_FALLTHROUGH;
     case DeclaratorContext::TypeName:
       Error = 15; // Generic
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -1468,6 +1468,9 @@
   // C++1z [expr.type.conv]p1:
   //   If the type is a placeholder for a deduced class type, [...perform class
   //   template argument deduction...]
+  // C++2b:
+  //   Otherwise, if the type contains a placeholder type, it is replaced by the
+  //   type determined by placeholder type deduction.
   DeducedType *Deduced = Ty->getContainedDeducedType();
   if (Deduced && isa<DeducedTemplateSpecializationType>(Deduced)) {
     Ty = DeduceTemplateSpecializationFromInitializer(TInfo, Entity,
@@ -1475,6 +1478,50 @@
     if (Ty.isNull())
       return ExprError();
     Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
+  } else if (Deduced) {
+    MultiExprArg Inits = Exprs;
+    if (ListInitialization) {
+      auto *ILE = cast<InitListExpr>(Exprs[0]);
+      Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
+    }
+
+    if (Inits.empty())
+      return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_init_no_expression)
+                       << Ty << FullRange);
+    if (Inits.size() > 1) {
+      Expr *FirstBad = Inits[1];
+      return ExprError(Diag(FirstBad->getBeginLoc(),
+                            diag::err_auto_expr_init_multiple_expressions)
+                       << Ty << FullRange);
+    }
+    if (getLangOpts().CPlusPlus2b) {
+      if (auto *TyAuto = Ty->getAs<AutoType>())
+        Diag(TyBeginLoc, TyAuto->isDecltypeAuto()
+                             ? diag::ext_decltype_auto_expr
+                             : diag::warn_cxx20_compat_auto_expr)
+            << FullRange;
+    }
+    Expr *Deduce = Inits[0];
+    if (isa<InitListExpr>(Deduce))
+      return ExprError(
+          Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
+          << ListInitialization << Ty << FullRange);
+    QualType DeducedType;
+    if (DeduceAutoType(TInfo, Deduce, DeducedType) == DAR_Failed)
+      return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure)
+                       << Ty << Deduce->getType() << FullRange
+                       << Deduce->getSourceRange());
+    if (DeducedType.isNull())
+      return ExprError();
+
+    Ty = DeducedType;
+    if (Ty->isReferenceType()) {
+      // decltype(auto)(x) takes a shortcut; see also P0849R2.
+      return BuildCXXFunctionalCastExpr(SubstAutoTypeSourceInfo(TInfo, Ty), Ty,
+                                        LParenOrBraceLoc, Deduce,
+                                        RParenOrBraceLoc);
+    }
+    Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
   }
 
   if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) {
@@ -1983,12 +2030,10 @@
       return ExprError();
   } else if (Deduced) {
     bool Braced = (initStyle == CXXNewExpr::ListInit);
-    if (NumInits == 1) {
-      if (auto p = dyn_cast_or_null<InitListExpr>(Inits[0])) {
-        Inits = p->getInits();
-        NumInits = p->getNumInits();
-        Braced = true;
-      }
+    if (Braced) {
+      auto *ILE = cast<InitListExpr>(Inits[0]);
+      Inits = ILE->getInits();
+      NumInits = ILE->getNumInits();
     }
 
     if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
@@ -2004,6 +2049,10 @@
       Diag(Initializer->getBeginLoc(), diag::ext_auto_new_list_init)
           << AllocType << TypeRange;
     Expr *Deduce = Inits[0];
+    if (isa<InitListExpr>(Deduce))
+      return ExprError(
+          Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces)
+          << Braced << AllocType << TypeRange);
     QualType DeducedType;
     if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed)
       return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure)
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -2231,6 +2231,9 @@
   case tok::kw_void:
     DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec, DiagID, Policy);
     break;
+  case tok::kw_auto:
+    DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID, Policy);
+    break;
   case tok::kw_char:
     DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec, DiagID, Policy);
     break;
Index: clang/lib/Parse/ParseExpr.cpp
===================================================================
--- clang/lib/Parse/ParseExpr.cpp
+++ clang/lib/Parse/ParseExpr.cpp
@@ -1524,6 +1524,7 @@
   case tok::kw___float128:
   case tok::kw___ibm128:
   case tok::kw_void:
+  case tok::kw_auto:
   case tok::kw_typename:
   case tok::kw_typeof:
   case tok::kw___vector:
Index: clang/lib/Parse/ParseDeclCXX.cpp
===================================================================
--- clang/lib/Parse/ParseDeclCXX.cpp
+++ clang/lib/Parse/ParseDeclCXX.cpp
@@ -1030,10 +1030,9 @@
     }
 
     // Check for C++1y 'decltype(auto)'.
-    if (Tok.is(tok::kw_auto)) {
-      // No need to disambiguate here: an expression can't start with 'auto',
-      // because the typename-specifier in a function-style cast operation can't
-      // be 'auto'.
+    if (Tok.is(tok::kw_auto) && NextToken().is(tok::r_paren)) {
+      // the typename-specifier in a function-style cast expression may
+      // be 'auto' since C++2b.
       Diag(Tok.getLocation(),
            getLangOpts().CPlusPlus14
              ? diag::warn_cxx11_compat_decltype_auto_type_specifier
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2325,13 +2325,23 @@
   "type %0 to use list-initialization">, InGroup<CXX17>;
 def err_auto_var_init_no_expression : Error<
   "initializer for variable %0 with type %1 is empty">;
+def err_auto_expr_init_no_expression : Error<
+  "initializer for functional-style cast to %0 is empty">;
 def err_auto_var_init_multiple_expressions : Error<
   "initializer for variable %0 with type %1 contains multiple expressions">;
+def err_auto_expr_init_multiple_expressions : Error<
+  "initializer for functional-style cast to %0 contains multiple expressions">;
 def err_auto_var_init_paren_braces : Error<
   "cannot deduce type for variable %1 with type %2 from "
   "%select{parenthesized|nested}0 initializer list">;
 def err_auto_new_ctor_multiple_expressions : Error<
   "new expression for type %0 contains multiple constructor arguments">;
+def err_auto_expr_init_paren_braces : Error<
+  "cannot deduce actual type for %1 from "
+  "%select{parenthesized|nested}0 initializer list">;
+def warn_cxx20_compat_auto_expr : Warning<
+  "'auto' as a functional-style cast is incompatible with C++ standards "
+  "before C++2b">, InGroup<CXXPre2bCompat>, DefaultIgnore;
 def err_auto_missing_trailing_return : Error<
   "'auto' return without trailing return type; deduced return types are a "
   "C++14 extension">;
@@ -2345,6 +2355,8 @@
   "variable %0 with type %1 has incompatible initializer of type %2">;
 def err_auto_var_deduction_failure_from_init_list : Error<
   "cannot deduce actual type for variable %0 with type %1 from initializer list">;
+def err_auto_expr_deduction_failure : Error<
+  "functional-style cast to %0 has incompatible initializer of type %1">;
 def err_auto_new_deduction_failure : Error<
   "new expression for type %0 has incompatible constructor argument of type %1">;
 def err_auto_inconsistent_deduction : Error<
@@ -2380,6 +2392,9 @@
   "cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">;
 def err_decltype_auto_initializer_list : Error<
   "cannot deduce 'decltype(auto)' from initializer list">;
+def ext_decltype_auto_expr : ExtWarn<
+  "functional-style cast to 'decltype(auto)' is a Clang extension">,
+  InGroup<DiagGroup<"decltype-auto-cast">>;
 
 // C++17 deduced class template specialization types
 def err_deduced_class_template_compound_type : Error<
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -114,6 +114,7 @@
 ^^^^^^^^^^^^^^^^^^^^^
 
 - Implemented `P2128R6: Multidimensional subscript operator <https://wg21.link/P2128R6>`_.
+- Implemented `P0849R8: auto(x): decay-copy in the language <https://wg21.link/P0849R8>`_.
 
 CUDA Language Changes in Clang
 ------------------------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to