Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -71,7 +71,7 @@ Modified Compiler Flags ----------------------- -- ... +- -Wshadow now also checks for shadowed structured bindings Removed Compiler Flags ------------------------- Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -2598,6 +2598,8 @@ NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D, const LookupResult &R); NamedDecl *getShadowedDeclaration(const VarDecl *D, const LookupResult &R); + NamedDecl *getShadowedDeclaration(const BindingDecl *D, + const LookupResult &R); void CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, const LookupResult &R); void CheckShadow(Scope *S, VarDecl *D); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -7560,6 +7560,19 @@ return isa(ShadowedDecl) ? ShadowedDecl : nullptr; } +/// Return the declaration shadowed by the given variable \p D, or null +/// if it doesn't shadow any declaration or shadowing warnings are disabled. +NamedDecl *Sema::getShadowedDeclaration(const BindingDecl *D, + const LookupResult &R) { + if (!shouldWarnIfShadowedDecl(Diags, R)) + return nullptr; + + NamedDecl *ShadowedDecl = R.getFoundDecl(); + return isa(ShadowedDecl) || isa(ShadowedDecl) + ? ShadowedDecl + : nullptr; +} + /// Diagnose variable or built-in function shadowing. Implements /// -Wshadow. /// Index: clang/lib/Sema/SemaDeclCXX.cpp =================================================================== --- clang/lib/Sema/SemaDeclCXX.cpp +++ clang/lib/Sema/SemaDeclCXX.cpp @@ -857,17 +857,28 @@ Previous.clear(); } + auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name); + + // Find the shadowed declaration before filtering for scope. + NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty() + ? getShadowedDeclaration(BD, Previous) + : nullptr; + bool ConsiderLinkage = DC->isFunctionOrMethod() && DS.getStorageClassSpec() == DeclSpec::SCS_extern; FilterLookupForScope(Previous, DC, S, ConsiderLinkage, /*AllowInlineNamespace*/false); + + // Diagnose shadowed variables if this isn't a redeclaration. + if (ShadowedDecl && !D.isRedeclaration()) + CheckShadow(BD, ShadowedDecl, Previous); + if (!Previous.empty()) { auto *Old = Previous.getRepresentativeDecl(); Diag(B.NameLoc, diag::err_redefinition) << B.Name; Diag(Old->getLocation(), diag::note_previous_definition); } - auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name); PushOnScopeChains(BD, S, true); Bindings.push_back(BD); ParsingInitForAutoVars.insert(BD); Index: clang/test/SemaCXX/warn-shadow.cpp =================================================================== --- clang/test/SemaCXX/warn-shadow.cpp +++ clang/test/SemaCXX/warn-shadow.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -verify -fsyntax-only -std=c++11 -Wshadow-all %s +// RUN: %clang_cc1 -verify -fsyntax-only -std=c++17 -Wshadow-all %s namespace { int i; // expected-note {{previous declaration is here}} @@ -265,3 +265,86 @@ PR24718_1 // Does not shadow a type. }; }; + +// MyTuple and std code is copied from live-bindings-test.cpp + +//#define USE_STD + +#ifndef USE_STD +// Machinery required for custom structured bindings decomposition. +typedef unsigned long size_t; + +namespace std { +template class tuple_size; +template +constexpr size_t tuple_size_v = tuple_size::value; +template class tuple_element; + +template +struct integral_constant { + static constexpr T value = v; + typedef T value_type; + typedef integral_constant type; + constexpr operator value_type() const noexcept { return value; } +}; +} // namespace std + +struct MyTuple { + int a; + int b; + + template + int get() const { + if constexpr (N == 0) + return a; + else if constexpr (N == 1) + return b; + } +}; + +namespace std { +template <> +struct tuple_size + : std::integral_constant {}; + +template +struct tuple_element { + using type = int; +}; +} // namespace std + +MyTuple getMyTuple(); +#else + +#include +std::tuple getMyTuple(); +#endif + + +namespace structured_binding_tests { +int x; // expected-note {{previous declaration is here}} +int y; // expected-note {{previous declaration is here}} + +void test1() { + const auto [x, y] = getMyTuple(); // expected-warning 2 {{declaration shadows a variable in namespace 'structured_binding_tests'}} +} + +void test2() { + int a; // expected-note {{previous declaration is here}} + bool b; // expected-note {{previous declaration is here}} + { + auto [a, b] = getMyTuple(); // expected-warning 2 {{declaration shadows a local variable}} + } +} + +class A +{ + int m_a; // expected-note {{previous declaration is here}} + int m_b; // expected-note {{previous declaration is here}} + + void test3() { + auto [m_a, m_b] = getMyTuple(); // expected-warning 2 {{declaration shadows a field of 'structured_binding_tests::A'}} + } +}; + +}; // namespace structured_binding_tests \ No newline at end of file