[clang] 136b293 - [c++2b] Implement P0849R8 auto(x)

Zhihao Yuan via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 28 17:21:20 PST 2022


Author: Zhihao Yuan
Date: 2022-02-28T19:21:08-06:00
New Revision: 136b2931292083c8d69c09de9b952c86417b2c5d

URL: https://github.com/llvm/llvm-project/commit/136b2931292083c8d69c09de9b952c86417b2c5d
DIFF: https://github.com/llvm/llvm-project/commit/136b2931292083c8d69c09de9b952c86417b2c5d.diff

LOG: [c++2b] Implement P0849R8 auto(x)

https://wg21.link/p0849

Reviewed By: aaron.ballman, erichkeane

Differential Revision: https://reviews.llvm.org/D113393

Added: 
    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/Parser/cxx2b-auto-x.cpp
    clang/test/SemaCXX/cxx2b-ast-print.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/AST/StmtPrinter.cpp
    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/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/www/cxx_status.html

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 4131c022f5944..d5f6c2d730f59 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -123,6 +123,7 @@ C++2b Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
 - 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
 ------------------------------

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8f631b7c1a8a2..945d4e2976503 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2320,13 +2320,23 @@ def ext_auto_new_list_init : Extension<
   "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">;
@@ -2340,6 +2350,8 @@ def err_auto_var_deduction_failure : Error<
   "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<

diff  --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 5ad935591ecd9..677181f925a54 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -1940,14 +1940,23 @@ void StmtPrinter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Node) {
 }
 
 void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
-  Node->getType().print(OS, Policy);
-  // If there are no parens, this is list-initialization, and the braces are
-  // part of the syntax of the inner construct.
-  if (Node->getLParenLoc().isValid())
-    OS << "(";
+  auto TargetType = Node->getType();
+  auto *Auto = TargetType->getContainedDeducedType();
+  bool Bare = Auto && Auto->isDeduced();
+
+  // Parenthesize deduced casts.
+  if (Bare)
+    OS << '(';
+  TargetType.print(OS, Policy);
+  if (Bare)
+    OS << ')';
+
+  // No extra braces surrounding the inner construct.
+  if (!Node->isListInitialization())
+    OS << '(';
   PrintExpr(Node->getSubExpr());
-  if (Node->getLParenLoc().isValid())
-    OS << ")";
+  if (!Node->isListInitialization())
+    OS << ')';
 }
 
 void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {

diff  --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index c08a586604b1f..5781b1aed1625 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1030,10 +1030,9 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) {
     }
 
     // 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

diff  --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 97dcbd311092f..fefb2932c07c1 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1524,6 +1524,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
   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:

diff  --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 2d38891c723f8..24f049fac8354 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -2231,6 +2231,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
   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;

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 0a8612a2bc049..5cf718cb6d25d 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1468,6 +1468,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
   // 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,41 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
     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 (Ty->getAs<AutoType>())
+        Diag(TyBeginLoc, 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;
+    Entity = InitializedEntity::InitializeTemporary(TInfo, Ty);
   }
 
   if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) {
@@ -1937,12 +1975,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
     initStyle = CXXNewExpr::NoInit;
   }
 
-  Expr **Inits = &Initializer;
-  unsigned NumInits = Initializer ? 1 : 0;
+  MultiExprArg Exprs(&Initializer, Initializer ? 1 : 0);
   if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) {
     assert(initStyle == CXXNewExpr::CallInit && "paren init for non-call init");
-    Inits = List->getExprs();
-    NumInits = List->getNumExprs();
+    Exprs = MultiExprArg(List->getExprs(), List->getNumExprs());
   }
 
   // C++11 [expr.new]p15:
@@ -1978,23 +2014,21 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
     InitializedEntity Entity
       = InitializedEntity::InitializeNew(StartLoc, AllocType);
     AllocType = DeduceTemplateSpecializationFromInitializer(
-        AllocTypeInfo, Entity, Kind, MultiExprArg(Inits, NumInits));
+        AllocTypeInfo, Entity, Kind, Exprs);
     if (AllocType.isNull())
       return ExprError();
   } else if (Deduced) {
+    MultiExprArg Inits = Exprs;
     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>(Exprs[0]);
+      Inits = MultiExprArg(ILE->getInits(), ILE->getNumInits());
     }
 
-    if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
+    if (initStyle == CXXNewExpr::NoInit || Inits.empty())
       return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
                        << AllocType << TypeRange);
-    if (NumInits > 1) {
+    if (Inits.size() > 1) {
       Expr *FirstBad = Inits[1];
       return ExprError(Diag(FirstBad->getBeginLoc(),
                             diag::err_auto_new_ctor_multiple_expressions)
@@ -2004,6 +2038,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
       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)
@@ -2304,8 +2342,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
   // Initializer lists are also allowed, in C++11. Rely on the parser for the
   // dialect distinction.
   if (ArraySize && !isLegalArrayNewInitializer(initStyle, Initializer)) {
-    SourceRange InitRange(Inits[0]->getBeginLoc(),
-                          Inits[NumInits - 1]->getEndLoc());
+    SourceRange InitRange(Exprs.front()->getBeginLoc(),
+                          Exprs.back()->getEndLoc());
     Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
     return ExprError();
   }
@@ -2313,8 +2351,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
   // If we can perform the initialization, and we've not already done so,
   // do it now.
   if (!AllocType->isDependentType() &&
-      !Expr::hasAnyTypeDependentArguments(
-          llvm::makeArrayRef(Inits, NumInits))) {
+      !Expr::hasAnyTypeDependentArguments(Exprs)) {
     // The type we initialize is the complete type, including the array bound.
     QualType InitType;
     if (KnownArraySize)
@@ -2331,10 +2368,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
 
     InitializedEntity Entity
       = InitializedEntity::InitializeNew(StartLoc, InitType);
-    InitializationSequence InitSeq(*this, Entity, Kind,
-                                   MultiExprArg(Inits, NumInits));
-    ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind,
-                                          MultiExprArg(Inits, NumInits));
+    InitializationSequence InitSeq(*this, Entity, Kind, Exprs);
+    ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, Exprs);
     if (FullInit.isInvalid())
       return ExprError();
 

diff  --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 35d4c386211e5..39d8c8711aa42 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -3509,6 +3509,9 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
     case DeclaratorContext::FunctionalCast:
       if (isa<DeducedTemplateSpecializationType>(Deduced))
         break;
+      if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType &&
+          !Auto->isDecltypeAuto())
+        break; // auto(x)
       LLVM_FALLTHROUGH;
     case DeclaratorContext::TypeName:
       Error = 15; // Generic

diff  --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
index a260f99f5cf16..9571d6670e70d 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p5.cpp
@@ -46,13 +46,18 @@ void j() {
   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}}

diff  --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp
new file mode 100644
index 0000000000000..49bd5e9168ac9
--- /dev/null
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.auto.deduct/p2.cpp
@@ -0,0 +1,81 @@
+// RUN: %clang_cc1 -std=c++2b -verify %s
+
+// p2.3 allows only T = auto in 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 *));
+
+  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));
+
+  class A {
+  } a;
+  A const ac;
+
+  static_assert(__is_same(decltype(auto(a)), A));
+  static_assert(__is_same(decltype(auto(ac)), A));
+
+  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));
+}
+
+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

diff  --git a/clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp b/clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
new file mode 100644
index 0000000000000..a7137447e506f
--- /dev/null
+++ b/clang/test/CXX/expr/expr.post/expr.type.conv/p1-2b.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c++2b -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}}
+}

diff  --git a/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp b/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
index a3a2f712c8009..8f321d800bf9d 100644
--- a/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
+++ b/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx0x.cpp
@@ -16,7 +16,7 @@ void f() {
   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() {

diff  --git a/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp b/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp
index 70bbc4805c437..8ae7eb435b547 100644
--- a/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp
+++ b/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx14.cpp
@@ -5,6 +5,6 @@ void f() {
   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}}
 }

diff  --git a/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp b/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp
index 6e76075ab16f5..b8383b83a589a 100644
--- a/clang/test/CXX/expr/expr.unary/expr.new/p2-cxx1z.cpp
+++ b/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}}
 }

diff  --git a/clang/test/Parser/cxx2b-auto-x.cpp b/clang/test/Parser/cxx2b-auto-x.cpp
new file mode 100644
index 0000000000000..28687dced5445
--- /dev/null
+++ b/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; }

diff  --git a/clang/test/SemaCXX/cxx2b-ast-print.cpp b/clang/test/SemaCXX/cxx2b-ast-print.cpp
new file mode 100644
index 0000000000000..4aa1b23280c39
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2b-ast-print.cpp
@@ -0,0 +1,30 @@
+// RUN: %clang_cc1 -std=c++2b -fsyntax-only -ast-print %s | FileCheck %s
+
+void test_auto_expr(long long y, auto &&z) {
+  int x[] = {3, 4};
+
+  // CHECK{LITERAL}: (int)(x[1])
+  void(auto(x[1]));
+  // CHECK{LITERAL}: (int){x[1]}
+  void(auto{x[1]});
+
+  // CHECK{LITERAL}: (int *)(x)
+  void(auto(x));
+  // CHECK{LITERAL}: (int *){x}
+  void(auto{x});
+
+  // CHECK{LITERAL}: auto(z)
+  void(auto(z));
+  // CHECK{LITERAL}: auto({z})
+  void(auto{z}); // T({z}) is legal unless T = auto
+
+  // CHECK{LITERAL}: new int *(x)
+  void(new auto(x));
+  // CHECK{LITERAL}: new int *{x}
+  void(new auto{x});
+
+  // CHECK{LITERAL}: new long long(y)
+  void(new decltype(auto)(y));
+  // CHECK{LITERAL}: new long long{y}
+  void(new decltype(auto){y});
+}

diff  --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index c1f65401df17c..afeaf8d7dffaf 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1388,6 +1388,11 @@ <h2 id="cxx23">C++2b implementation status</h2>
       <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>


        


More information about the cfe-commits mailing list