[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