From 3876cc88ac22b74ff0ae0a1f17eb08ba655eb93f Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 30 Oct 2013 01:02:04 +0000 Subject: [PATCH] PR17731: When determining whether a tag and a non-tag were declared in the same scope, be careful about function-scope declarations (which are not declared in their semantic context). llvm-svn: 193671 --- clang/lib/Sema/SemaLookup.cpp | 19 +++++++- .../basic.scope/basic.scope.hiding/p2.cpp | 45 +++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index cca0f22f14a1..dba0759b1838 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -337,6 +337,21 @@ void LookupResult::deletePaths(CXXBasePaths *Paths) { delete Paths; } +/// Get a representative context for a declaration such that two declarations +/// will have the same context if they were found within the same scope. +DeclContext *getContextForScopeMatching(Decl *D) { + // For function-local declarations, use that function as the context. This + // doesn't account for scopes within the function; the caller must deal with + // those. + DeclContext *DC = D->getLexicalDeclContext(); + if (DC->isFunctionOrMethod()) + return DC; + + // Otherwise, look at the semantic context of the declaration. The + // declaration must have been found there. + return D->getDeclContext()->getRedeclContext(); +} + /// Resolves the result kind of this lookup. void LookupResult::resolveKind() { unsigned N = Decls.size(); @@ -437,8 +452,8 @@ void LookupResult::resolveKind() { // even if they're not visible. (ref?) if (HideTags && HasTag && !Ambiguous && (HasFunction || HasNonFunction || HasUnresolved)) { - if (Decls[UniqueTagIndex]->getDeclContext()->getRedeclContext()->Equals( - Decls[UniqueTagIndex? 0 : N-1]->getDeclContext()->getRedeclContext())) + if (getContextForScopeMatching(Decls[UniqueTagIndex])->Equals( + getContextForScopeMatching(Decls[UniqueTagIndex ? 0 : N - 1]))) Decls[UniqueTagIndex] = Decls[--N]; else Ambiguous = true; diff --git a/clang/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp b/clang/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp index 911df989530f..1d2b525da4c2 100644 --- a/clang/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp +++ b/clang/test/CXX/basic/basic.scope/basic.scope.hiding/p2.cpp @@ -22,3 +22,48 @@ void f() { Y(1); // okay } +namespace PR17731 { + void f() { + struct S { S() {} }; + int S(void); + int a = S(); + struct S b; + { + int S(void); + int a = S(); + struct S c = b; + } + { + struct S { S() {} }; // expected-note {{candidate}} + int a = S(); // expected-error {{no viable conversion from 'S'}} + struct S c = b; // expected-error {{no viable conversion from 'struct S'}} + } + } + void g() { + int S(void); + struct S { S() {} }; + int a = S(); + struct S b; + { + int S(void); + int a = S(); + struct S c = b; + } + { + struct S { S() {} }; // expected-note {{candidate}} + int a = S(); // expected-error {{no viable conversion from 'S'}} + struct S c = b; // expected-error {{no viable conversion from 'struct S'}} + } + } + + struct A { + struct B; + void f(); + int B; + }; + struct A::B {}; + void A::f() { + B = 123; + struct B b; + } +}