riccibruno updated this revision to Diff 284364.
riccibruno marked 2 inline comments as done.
riccibruno edited the summary of this revision.
riccibruno added a comment.

Refer to the binding in the diagnostic.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D85613

Files:
  clang/include/clang/AST/DeclCXX.h
  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);
@@ -22,10 +37,21 @@
   };
 
   extern void h6(int = i5);
-  // expected-error-re@-1 {{default argument references local variable '(unnamed variable of type (anonymous union at {{.*}}:20:3))' of enclosing function}}
+  // expected-error-re@-1 {{default argument references local variable '(unnamed variable of type (anonymous union at {{.*}}:35:3))' of enclosing function}}
+
+  struct S {
+    int i, j;
+  };
+  auto [x, y] = S();
+
+  extern void h7(int = x); // expected-error {{default argument references local binding 'x'}}
 
-  struct S { int i; };
-  auto [x] = S();
+  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,22 @@
 /// argument expression.
 bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
   const NamedDecl *Decl = DRE->getDecl();
+
+  auto CheckAndDiagnoseLocalEntity = [&](const VarDecl *VD, unsigned DiagID,
+                                         const auto &... DiagArgs) -> bool {
+    if (VD->isLocalVarDecl() && !DRE->isNonOdrUse()) {
+      auto DB = S.Diag(DRE->getBeginLoc(), DiagID);
+      // FIXME: Replace with a fold once we can use C++17.
+      int dummy[] = {(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 +127,28 @@
     // 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 << DefaultArg->getSourceRange();
+    if (CheckAndDiagnoseLocalEntity(
+            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_or_null<VarDecl>(Binding->getDecomposedDecl());
+    if (VD && CheckAndDiagnoseLocalEntity(
+                  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
@@ -3988,7 +3988,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<
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -3840,6 +3840,8 @@
 /// DecompositionDecl of type 'int (&)[3]'.
 class BindingDecl : public ValueDecl {
   /// The declaration that this binding binds to part of.
+  // FIXME: Currently not set during deserialization of the BindingDecl;
+  // only set when the corresponding DecompositionDecl is visited.
   LazyDeclPtr Decomp;
   /// The binding represented by this declaration. References to this
   /// declaration are effectively equivalent to this expression (except
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to