From 09abecef7bbfda18d34f046954eaa4d491062839 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 28 Oct 2020 14:27:38 -0700 Subject: [PATCH] PR48002: Fix injection of elaborated-type-specifiers within local classes into the enclosing block scope. We weren't properly detecting whether the name would be injected into a block scope in the case where it was lexically declared in a local class. --- clang/lib/Sema/SemaDecl.cpp | 7 +-- .../basic.scope/basic.scope.pdecl/p7.cpp | 56 +++++++++++++++++++ 2 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 clang/test/CXX/basic/basic.scope/basic.scope.pdecl/p7.cpp diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 2bffd2a87d08..10c9db073a25 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1478,10 +1478,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { // Out-of-line definitions shouldn't be pushed into scope in C++, unless they // are function-local declarations. - if (getLangOpts().CPlusPlus && D->isOutOfLine() && - !D->getDeclContext()->getRedeclContext()->Equals( - D->getLexicalDeclContext()->getRedeclContext()) && - !D->getLexicalDeclContext()->isFunctionOrMethod()) + if (getLangOpts().CPlusPlus && D->isOutOfLine() && !S->getFnParent()) return; // Template instantiations should also not be pushed into scope. @@ -15728,6 +15725,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // type declared by an elaborated-type-specifier. In C that is not correct // and we should instead merge compatible types found by lookup. if (getLangOpts().CPlusPlus) { + // FIXME: This can perform qualified lookups into function contexts, + // which are meaningless. Previous.setRedeclarationKind(forRedeclarationInCurContext()); LookupQualifiedName(Previous, SearchDC); } else { diff --git a/clang/test/CXX/basic/basic.scope/basic.scope.pdecl/p7.cpp b/clang/test/CXX/basic/basic.scope/basic.scope.pdecl/p7.cpp new file mode 100644 index 000000000000..fe4f42a8bdb1 --- /dev/null +++ b/clang/test/CXX/basic/basic.scope/basic.scope.pdecl/p7.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -verify %s + +// Some of the diagnostics produce 'did you mean?' suggestions. We don't care +// which ones for the purpose of this test. +// expected-note@* 0+{{here}} + +struct A *f(); +using Test_A = A; + +void f(struct B*); +using Test_B = B; + +struct C; +using Test_C = C; + +struct X { + struct D *f(); + void f(struct E*); + struct F; + friend struct G; +}; +using Test_D = D; +using Test_XD = X::D; // expected-error {{no type named 'D' in 'X'}} +using Test_E = E; +using Test_XE = X::E; // expected-error {{no type named 'E' in 'X'}} +using Test_F = F; // expected-error {{unknown type name 'F'}} +using Test_XF = X::F; +using Test_G = G; // expected-error {{unknown type name 'G'}} +using Test_XG = X::G; // expected-error {{no type named 'G' in 'X'}} + +void g() { + { + struct X { + struct H *f(); + void f(struct I*); + struct J; + friend struct K; + }; + using Test_H = H; + using Test_XH = X::H; // expected-error {{no type named}} + using Test_I = I; + using Test_XI = X::I; // expected-error {{no type named}} + using Test_J = J; // expected-error {{unknown type name}} + using Test_XJ = X::J; + using Test_K = K; // expected-error {{unknown type name}} + using Test_XK = X::K; // expected-error {{no type named}} + } + using Test_H = H; // expected-error {{unknown type name}} + using Test_I = I; // expected-error {{unknown type name}} + using Test_J = J; // expected-error {{unknown type name}} + using Test_K = K; // expected-error {{unknown type name}} +} +using Test_H = H; // expected-error {{unknown type name}} +using Test_I = I; // expected-error {{unknown type name}} +using Test_J = J; // expected-error {{unknown type name}} +using Test_K = K; // expected-error {{unknown type name}}