[PATCH] D85613: [clang] Look through bindings when checking whether a default argument references a local entity.

Bruno Ricci via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Sun Aug 9 09:25:41 PDT 2020


riccibruno created this revision.
riccibruno added reviewers: rsmith, erichkeane, rjmccall.
riccibruno added a project: clang.
Herald added a subscriber: cfe-commits.
riccibruno requested review of this revision.

Currently clang accepts a default argument containing a structured binding which is a local entity:

  struct S { int i, j; };
  auto [x, y] = S();
  extern void h(int = x); // Should be rejected.

It was not entirely clear in C++17 that this was forbidden since `C++17 [dcl.fct.default]p7` only used the term "local variable". However this is clearly forbidden in C++20 with the new wording in terms of odr-usable local entities.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D85613

Files:
  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 at -1 {{default argument references local variable '(unnamed variable of type (anonymous union at {{.*}}:20:3))' of enclosing function}}
+  // expected-error-re at -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 variable '[x, y]'}}
 
-  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 variable '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 variable '[a0, a1]'}}
 }
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -86,6 +86,34 @@
 /// argument expression.
 bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) {
   const NamedDecl *Decl = DRE->getDecl();
+
+  // 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).
+  if (const auto *Binding = dyn_cast<BindingDecl>(Decl)) {
+    if (const VarDecl *HoldingVar = Binding->getHoldingVar()) {
+      // C++20 [dcl.struct.bind]p4:
+      //   Each vi is the name [...] that refers to the object bound to ri [...]
+      Decl = HoldingVar;
+    } else {
+      // C++20 [dcl.struct.bind]p3:
+      //   Each vi is the name of an lvalue that refers to the element i of
+      //   the array [...]
+      //
+      // C++20 [dcl.struct.bind]p5:
+      //   [...] each vi is the name of an lvalue that refers to the member mi
+      //   of e [...]
+      Decl = Binding->getDecomposedDecl();
+    }
+  }
+
   if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) {
     // C++ [dcl.fct.default]p9:
     //   [...] parameters of a function shall not be used in default


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D85613.284215.patch
Type: text/x-patch
Size: 3430 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200809/7d393dfa/attachment.bin>


More information about the cfe-commits mailing list