[cfe-commits] r98544 - in /cfe/trunk: lib/Sema/SemaLookup.cpp test/CXX/temp/temp.res/temp.local/p7.cpp test/CXX/temp/temp.res/temp.local/p8.cpp test/CXX/temp/temp.res/temp.local/p9.cpp
Douglas Gregor
dgregor at apple.com
Mon Mar 15 07:33:29 PDT 2010
Author: dgregor
Date: Mon Mar 15 09:33:29 2010
New Revision: 98544
URL: http://llvm.org/viewvc/llvm-project?rev=98544&view=rev
Log:
Implement C++ [temp.local]p8, which specifies that a template
parameter hides a namespace-scope declararion with the same name in an
out-of-line definition of a template. The lookup requires a strange
interleaving of lexical and semantic scopes (go C++), which I have not
yet handled in the typo correction/code completion path.
Fixes PR6594.
Added:
cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp (with props)
cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp (with props)
cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp (with props)
Modified:
cfe/trunk/lib/Sema/SemaLookup.cpp
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=98544&r1=98543&r2=98544&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Mon Mar 15 09:33:29 2010
@@ -590,13 +590,74 @@
return false;
}
-// Find the next outer declaration context corresponding to this scope.
-static DeclContext *findOuterContext(Scope *S) {
- for (S = S->getParent(); S; S = S->getParent())
- if (S->getEntity())
- return static_cast<DeclContext *>(S->getEntity())->getPrimaryContext();
+// Find the next outer declaration context from this scope. This
+// routine actually returns the semantic outer context, which may
+// differ from the lexical context (encoded directly in the Scope
+// stack) when we are parsing a member of a class template. In this
+// case, the second element of the pair will be true, to indicate that
+// name lookup should continue searching in this semantic context when
+// it leaves the current template parameter scope.
+static std::pair<DeclContext *, bool> findOuterContext(Scope *S) {
+ DeclContext *DC = static_cast<DeclContext *>(S->getEntity());
+ DeclContext *Lexical = 0;
+ for (Scope *OuterS = S->getParent(); OuterS;
+ OuterS = OuterS->getParent()) {
+ if (OuterS->getEntity()) {
+ Lexical
+ = static_cast<DeclContext *>(OuterS->getEntity())->getPrimaryContext();
+ break;
+ }
+ }
+
+ // C++ [temp.local]p8:
+ // In the definition of a member of a class template that appears
+ // outside of the namespace containing the class template
+ // definition, the name of a template-parameter hides the name of
+ // a member of this namespace.
+ //
+ // Example:
+ //
+ // namespace N {
+ // class C { };
+ //
+ // template<class T> class B {
+ // void f(T);
+ // };
+ // }
+ //
+ // template<class C> void N::B<C>::f(C) {
+ // C b; // C is the template parameter, not N::C
+ // }
+ //
+ // In this example, the lexical context we return is the
+ // TranslationUnit, while the semantic context is the namespace N.
+ if (!Lexical || !DC || !S->getParent() ||
+ !S->getParent()->isTemplateParamScope())
+ return std::make_pair(Lexical, false);
+
+ // Find the outermost template parameter scope.
+ // For the example, this is the scope for the template parameters of
+ // template<class C>.
+ Scope *OutermostTemplateScope = S->getParent();
+ while (OutermostTemplateScope->getParent() &&
+ OutermostTemplateScope->getParent()->isTemplateParamScope())
+ OutermostTemplateScope = OutermostTemplateScope->getParent();
- return 0;
+ // Find the namespace context in which the original scope occurs. In
+ // the example, this is namespace N.
+ DeclContext *Semantic = DC;
+ while (!Semantic->isFileContext())
+ Semantic = Semantic->getParent();
+
+ // Find the declaration context just outside of the template
+ // parameter scope. This is the context in which the template is
+ // being lexically declaration (a namespace context). In the
+ // example, this is the global scope.
+ if (Lexical->isFileContext() && !Lexical->Equals(Semantic) &&
+ Lexical->Encloses(Semantic))
+ return std::make_pair(Semantic, true);
+
+ return std::make_pair(Lexical, false);
}
bool Sema::CppLookupName(LookupResult &R, Scope *S) {
@@ -627,6 +688,7 @@
// }
// }
//
+ DeclContext *OutsideOfTemplateParamDC = 0;
for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
// Check whether the IdResolver has anything in this scope.
bool Found = false;
@@ -641,8 +703,25 @@
return true;
}
- if (DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity())) {
- DeclContext *OuterCtx = findOuterContext(S);
+ DeclContext *Ctx = static_cast<DeclContext*>(S->getEntity());
+ if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC &&
+ S->getParent() && !S->getParent()->isTemplateParamScope()) {
+ // We've just searched the last template parameter scope and
+ // found nothing, so look into the the contexts between the
+ // lexical and semantic declaration contexts returned by
+ // findOuterContext(). This implements the name lookup behavior
+ // of C++ [temp.local]p8.
+ Ctx = OutsideOfTemplateParamDC;
+ OutsideOfTemplateParamDC = 0;
+ }
+
+ if (Ctx) {
+ DeclContext *OuterCtx;
+ bool SearchAfterTemplateScope;
+ llvm::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S);
+ if (SearchAfterTemplateScope)
+ OutsideOfTemplateParamDC = OuterCtx;
+
for (; Ctx && Ctx->getPrimaryContext() != OuterCtx;
Ctx = Ctx->getLookupParent()) {
// We do not directly look into transparent contexts, since
@@ -725,7 +804,10 @@
}
}
- if (Ctx) {
+ // If we have a context, and it's not a context stashed in the
+ // template parameter scope for an out-of-line definition, also
+ // look into that context.
+ if (Ctx && !(Found && S && S->isTemplateParamScope())) {
assert(Ctx->isFileContext() &&
"We should have been looking only at file context here already.");
@@ -2216,13 +2298,14 @@
}
}
+ // FIXME: C++ [temp.local]p8
DeclContext *Entity = 0;
if (S->getEntity()) {
// Look into this scope's declaration context, along with any of its
// parent lookup contexts (e.g., enclosing classes), up to the point
// where we hit the context stored in the next outer scope.
Entity = (DeclContext *)S->getEntity();
- DeclContext *OuterCtx = findOuterContext(S);
+ DeclContext *OuterCtx = findOuterContext(S).first; // FIXME
for (DeclContext *Ctx = Entity; Ctx && Ctx->getPrimaryContext() != OuterCtx;
Ctx = Ctx->getLookupParent()) {
Added: cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp?rev=98544&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp Mon Mar 15 09:33:29 2010
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<class T> struct A {
+ int B;
+ int f();
+};
+
+template<class B> int A<B>::f() {
+ return B;
+}
Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p7.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp?rev=98544&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp Mon Mar 15 09:33:29 2010
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace N {
+ enum { C };
+ template<class T> class B {
+ void f(T);
+ };
+}
+
+template<class C> void N::B<C>::f(C) {
+ C b;
+}
+
+namespace N {
+ enum { D };
+ namespace M {
+ enum { C , D };
+ template<typename C> class X {
+ template<typename U> void f(C, U);
+
+ template<typename D> void g(C, D) {
+ C c;
+ D d;
+ }
+ };
+ }
+}
+
+template<typename C>
+template<typename D>
+void N::M::X<C>::f(C, D) {
+ C c;
+ D d;
+}
Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p8.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp?rev=98544&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp Mon Mar 15 09:33:29 2010
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+struct A {
+ struct B { void f(); };
+ int a;
+ int Y;
+};
+
+template<class B, class a> struct X : A {
+ B b; // A's B
+ a c; // expected-error{{unknown type name 'a'}}
+
+ void g() {
+ b.g(); // expected-error{{no member named 'g' in 'A::B'}}
+ }
+};
Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CXX/temp/temp.res/temp.local/p9.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the cfe-commits
mailing list