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

Restore the right diff


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D120589

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaType.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/SemaCXX/deduced-return-type-cxx14.cpp

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/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
===================================================================
--- clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
+++ clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++2b -verify %s
+// RUN: %clang_cc1 -std=c++2b -Wno-decltype-auto-cast -verify %s
 
 template <class T>
 void foo(T);
@@ -37,3 +37,26 @@
   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
===================================================================
--- clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp
+++ clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -std=c++2b -verify %s
+// 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];
@@ -9,6 +10,18 @@
   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));
@@ -16,6 +29,12 @@
   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;
@@ -23,6 +42,18 @@
   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);
@@ -32,6 +63,11 @@
   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 {
@@ -79,3 +115,71 @@
   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/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -3509,9 +3509,8 @@
     case DeclaratorContext::FunctionalCast:
       if (isa<DeducedTemplateSpecializationType>(Deduced))
         break;
-      if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType &&
-          !Auto->isDecltypeAuto())
-        break; // auto(x)
+      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
@@ -1495,8 +1495,11 @@
                        << Ty << FullRange);
     }
     if (getLangOpts().CPlusPlus2b) {
-      if (Ty->getAs<AutoType>())
-        Diag(TyBeginLoc, diag::warn_cxx20_compat_auto_expr) << FullRange;
+      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))
@@ -1512,6 +1515,14 @@
       return ExprError();
 
     Ty = DeducedType;
+    if (Ty->isReferenceType()) {
+      // decltype(auto)(x) takes a shortcut; see also P0849R2.
+      // FIXME: Substitute auto here to prevent a crash when diagnosing lifetime
+      // of array argument in constant evaluation. Shouldn't be done this way.
+      return BuildCXXFunctionalCastExpr(SubstAutoTypeSourceInfo(TInfo, Ty), Ty,
+                                        LParenOrBraceLoc, Deduce,
+                                        RParenOrBraceLoc);
+    }
     Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
   }
 
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2387,6 +2387,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<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to