PR48002: Fix injection of elaborated-type-specifiers within local
authorRichard Smith <richard@metafoo.co.uk>
Wed, 28 Oct 2020 21:27:38 +0000 (14:27 -0700)
committerRichard Smith <richard@metafoo.co.uk>
Wed, 28 Oct 2020 21:29:45 +0000 (14:29 -0700)
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
clang/test/CXX/basic/basic.scope/basic.scope.pdecl/p7.cpp [new file with mode: 0644]

index 2bffd2a..10c9db0 100644 (file)
@@ -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 (file)
index 0000000..fe4f42a
--- /dev/null
@@ -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}}