From: Douglas Gregor Date: Wed, 27 May 2009 17:07:49 +0000 (+0000) Subject: Improve name lookup for and template instantiation of declaration X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2bba76b0ec4c2f2134eebb1a2bbfe102f36c2f6e;p=clang Improve name lookup for and template instantiation of declaration references. There are several smallish fixes here: - Make sure we look through template parameter scope when determining whether we're parsing a nested class (or nested class *template*). This makes sure that we delay parsing the bodies of inline member functions until after we're out of the outermost class (template) scope. - Since the bodies of member functions are always parsed "out-of-line", even when they were declared in-line, teach unqualified name lookup to look into the (semantic) parents. - Use the new InstantiateDeclRef to handle the instantiation of a reference to a declaration (in DeclRefExpr), which drastically simplifies template instantiation for DeclRefExprs. - When we're instantiating a ParmVarDecl, it must be in the current instantiation scope, so only look there. Also, remove the #if 0's and FIXME's from the dynarray example, which now compiles and executes thanks to Anders and Eli. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72481 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index c53b0f071c..ee14213876 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1067,7 +1067,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // // FIXME: Only function bodies and constructor ctor-initializers are // parsed correctly, fix the rest. - if (!CurScope->getParent()->isClassScope()) { + if (!CurScope->getParent()->isClassScope() && + !(CurScope->getParent()->isTemplateParamScope() && + CurScope->getParent()->getParent()->isClassScope())) { // We are not inside a nested class. This class and its nested classes // are complete and we can parse the delayed portions of method // declarations and the lexed inline method definitions. diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 8fe287cb41..6212449744 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -687,7 +687,8 @@ Sema::CppLookupName(Scope *S, DeclarationName Name, if (R || RedeclarationOnly) return std::make_pair(true, R); } - if (Ctx->getParent() != Ctx->getLexicalParent()) { + if (Ctx->getParent() != Ctx->getLexicalParent() + || isa(Ctx)) { // It is out of line defined C++ method or struct, we continue // doing name lookup in parent context. Once we will find namespace // or translation-unit we save it for possible checking diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index e69a1ce644..a5eb7793b8 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -697,9 +697,13 @@ static NamedDecl *findInstantiationOf(ASTContext &Ctx, NamedDecl * Sema::InstantiateDeclRef(NamedDecl *D, const TemplateArgumentList &TemplateArgs) { DeclContext *ParentDC = D->getDeclContext(); + if (isa(D) || ParentDC->isFunctionOrMethod()) { + // D is a local of some kind. Look into the map of local + // declarations to their instantiations. + return cast(CurrentInstantiationScope->getInstantiationOf(D)); + } - if (!ParentDC->isFileContext()) { - NamedDecl *ParentDecl = cast(ParentDC); + if (NamedDecl *ParentDecl = dyn_cast(ParentDC)) { ParentDecl = InstantiateDeclRef(ParentDecl, TemplateArgs); if (!ParentDecl) return 0; @@ -707,12 +711,6 @@ Sema::InstantiateDeclRef(NamedDecl *D, const TemplateArgumentList &TemplateArgs) ParentDC = cast(ParentDecl); } - if (ParentDC->isFunctionOrMethod()) { - // D is a local of some kind. Look into the map of local - // variables to their instantiations. - return cast(CurrentInstantiationScope->getInstantiationOf(D)); - } - if (ParentDC != D->getDeclContext()) { // We performed some kind of instantiation in the parent context, // so now we need to look into the instantiated parent context to diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp index a0fc25de92..726ac2b425 100644 --- a/lib/Sema/SemaTemplateInstantiateExpr.cpp +++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp @@ -109,8 +109,7 @@ TemplateExprInstantiator::VisitUnresolvedFunctionNameExpr( Sema::OwningExprResult TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { // FIXME: Recast this in terms of Sema::InstantiateDeclRef. - Decl *D = E->getDecl(); - ValueDecl *NewD = 0; + NamedDecl *D = E->getDecl(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast(D)) { assert(NTTP->getDepth() == 0 && "No nested templates yet"); const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()]; @@ -131,29 +130,22 @@ TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) { *Arg.getAsIntegral(), T, E->getSourceRange().getBegin())); - } else if (ParmVarDecl *Parm = dyn_cast(D)) { - NewD = SemaRef.CurrentInstantiationScope->getInstantiationOf(Parm); - } else if (VarDecl *Var = dyn_cast(D)) { - if (Var->hasLocalStorage()) - NewD = SemaRef.CurrentInstantiationScope->getInstantiationOf(Var); - else - assert(false && - "FIXME: instantiation of non-local variable declarations"); - } else if (isa(D)) { - // FIXME: Instantiate decl! - NewD = cast(D); - } else if (isa(D)) { - // FIXME: instantiate decls? - return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(cast(D), + } + + if (OverloadedFunctionDecl *Ovl = dyn_cast(D)) { + // FIXME: instantiate each decl in the overload set + return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Ovl, SemaRef.Context.OverloadTy, E->getLocation(), false, false)); - } else - assert(false && "FIXME: unhandled declaration reference kind"); + } + ValueDecl *NewD + = dyn_cast_or_null(SemaRef.InstantiateDeclRef(D, TemplateArgs)); if (!NewD) return SemaRef.ExprError(); + // FIXME: Build QualifiedDeclRefExpr? QualType T = NewD->getType(); return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(NewD, T.getNonReferenceType(), diff --git a/test/SemaTemplate/example-dynarray.cpp b/test/SemaTemplate/example-dynarray.cpp index 1fe85d920c..0fcaba3d9b 100644 --- a/test/SemaTemplate/example-dynarray.cpp +++ b/test/SemaTemplate/example-dynarray.cpp @@ -120,8 +120,6 @@ int main() { assert(di.size() == 4); di.push_back(4); -#if 0 - // FIXME: Copy construction via copy initialization dynarray di2 = di; assert(di2.size() == 5); assert(di.begin() != di2.begin()); @@ -129,7 +127,6 @@ int main() { I != IEnd; ++I) assert(*I == I - di2.begin()); - // FIXME: Copy construction via direct initialization dynarray di3(di); assert(di3.size() == 5); assert(di.begin() != di3.begin()); @@ -137,7 +134,6 @@ int main() { I != IEnd; ++I) assert(*I == I - di3.begin()); - // FIXME: assignment operator dynarray di4; assert(di4.size() == 0); di4 = di; @@ -146,7 +142,6 @@ int main() { for (dynarray::iterator I = di4.begin(), IEnd = di4.end(); I != IEnd; ++I) assert(*I == I - di4.begin()); -#endif return 0; } diff --git a/test/SemaTemplate/instantiate-declref.cpp b/test/SemaTemplate/instantiate-declref.cpp new file mode 100644 index 0000000000..2512df15b1 --- /dev/null +++ b/test/SemaTemplate/instantiate-declref.cpp @@ -0,0 +1,27 @@ +// RUN: clang-cc -fsyntax-only %s + +namespace N { + struct Outer { + struct Inner { + template + struct InnerTemplate { + struct VeryInner { + typedef T type; + + static enum K1 { K1Val = sizeof(T) } Kind1; + // FIXME: Remove the name K2, below + static enum K2 { K2Val = sizeof(T)*2 } Kind2; + + void foo() { + K1 k1 = K1Val; + Kind1 = K1Val; + Outer::Inner::InnerTemplate::VeryInner::Kind2 = K2Val; + } + }; + }; + }; + }; +} + +typedef int INT; +template struct N::Outer::Inner::InnerTemplate::VeryInner;