riccibruno updated this revision to Diff 284718.

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85613

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp

Index: clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
===================================================================
--- clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
+++ clang/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
@@ -1,5 +1,20 @@
 // RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
 
+namespace std {
+using size_t = decltype(sizeof(int));
+template <typename> struct tuple_size;
+template <size_t, typename> struct tuple_element;
+} // namespace std
+using size_t = std::size_t;
+
+struct E {};
+template <size_t> int get(E);
+
+namespace std {
+template <> struct tuple_size<E> { static constexpr size_t value = 2; };
+template <size_t I> struct tuple_element<I, E> { using type = int; };
+}; // namespace std
+
 void h() {
   int i1 = 0;
   extern void h1(int x = i1);
@@ -24,8 +39,19 @@
   extern void h6(int = i5);
   // expected-error@-1 {{default argument references local variable '' of enclosing function}}
 
-  struct S { int i; };
-  auto [x] = S();
+  struct S {
+    int i, j;
+  };
+  auto [x, y] = S();
+
+  extern void h7(int = x); // expected-error {{default argument references local binding 'x'}}
+
+  auto [z, w] = E();
+  extern void h8a(int = sizeof(z)); // ok
+  extern void h8b(int = w);         // expected-error {{default argument references local binding 'w'}}
 
-  extern void h7(int = x); // FIXME: reject
+  extern auto get_array()->int(&)[2];
+  auto [a0, a1] = get_array();
+  extern void h9a(int = sizeof(a0));
+  extern void h9b(int = a1); // expected-error {{default argument references local binding 'a1'}}
 }
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -86,6 +86,20 @@
 /// argument expression.
 bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
   const NamedDecl *Decl = DRE->getDecl();
+
+  auto DiagnoseIfOdrUse = [&](const VarDecl *VD, unsigned DiagID,
+                              const auto &... DiagArgs) -> bool {
+    if (!DRE->isNonOdrUse()) {
+      auto DB = S.Diag(DRE->getBeginLoc(), DiagID);
+      int dummy[] = {0, (DB << DiagArgs, 0)...};
+      (void)dummy;
+      DB << DefaultArg->getSourceRange();
+      return true;
+    }
+
+    return false;
+  };
+
   if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) {
     // C++ [dcl.fct.default]p9:
     //   [...] parameters of a function shall not be used in default
@@ -111,10 +125,29 @@
     // C++20 [dcl.fct.default]p7 (DR as part of P0588R1, see also CWG 2346):
     //   Note: A local variable cannot be odr-used (6.3) in a default argument.
     //
-    if (VDecl->isLocalVarDecl() && !DRE->isNonOdrUse())
-      return S.Diag(DRE->getBeginLoc(),
-                    diag::err_param_default_argument_references_local)
-             << VDecl->getDeclName() << DefaultArg->getSourceRange();
+    if (VDecl->isLocalVarDecl() &&
+        DiagnoseIfOdrUse(VDecl,
+                         diag::err_param_default_argument_references_local,
+                         /*variable*/ 0, VDecl))
+      return true;
+
+  } else if (const auto *Binding = dyn_cast<BindingDecl>(Decl)) {
+    // C++20 [basic.pre]p7:
+    //   A local entity is [...] a structured binding whose corresponding
+    //   variable is such an entity [...]
+    //
+    // C++20 [basic.def.odr]p9:
+    //   A local entity (6.1) is odr-usable in a declarative region if [...]
+    //
+    // Note that this was not entirely clear in C++17 since [dcl.fct.default]p7
+    // only prohibited local variables (a structured binding declaration
+    // introduces identifiers as names).
+    //
+    const auto *VD = cast<VarDecl>(Binding->getDecomposedDecl());
+    if (VD->isLocalVarDecl() &&
+        DiagnoseIfOdrUse(VD, diag::err_param_default_argument_references_local,
+                         /*binding*/ 1, Binding))
+      return true;
   }
 
   return false;
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3994,7 +3994,8 @@
 def err_param_default_argument_references_param : Error<
   "default argument references parameter %0">;
 def err_param_default_argument_references_local : Error<
-  "default argument references local variable %0 of enclosing function">;
+  "default argument references local %select{variable|binding}0 %1 "
+  "of enclosing function">;
 def err_param_default_argument_references_this : Error<
   "default argument references 'this'">;
 def err_param_default_argument_nonfunc : Error<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to