diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-03-19 17:26:29 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-03-19 17:26:29 +0000 |
commit | 5953d8b37f92f0cf548941f617c9b0a7703df33b (patch) | |
tree | e9b4379486d998455e7f649c99f5d5f79d51ee80 /lib/Sema | |
parent | 5e1e1f95c98b1add70c238093bbd5dc8d4f9c4e9 (diff) |
Introduce a new expression type, UnresolvedDeclRefExpr, that describes
dependent qualified-ids such as
Fibonacci<N - 1>::value
where N is a template parameter. These references are "unresolved"
because the name is dependent and, therefore, cannot be resolved to a
declaration node (as we would do for a DeclRefExpr or
QualifiedDeclRefExpr). UnresolvedDeclRefExprs instantiate to
DeclRefExprs, QualifiedDeclRefExprs, etc.
Also, be a bit more careful about keeping only a single set of
specializations for a class template, and instantiating from the
definition of that template rather than a previous declaration. In
general, we need a better solution for this for all TagDecls, because
it's too easy to accidentally look at a declaration that isn't the
definition.
We can now process a simple Fibonacci computation described as a
template metaprogram.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67308 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.h | 7 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 57 |
6 files changed, 107 insertions, 3 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3755744126..df1e7c38a5 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1455,6 +1455,7 @@ public: bool RequireCompleteDeclContext(const CXXScopeSpec &SS); DeclContext *computeDeclContext(const CXXScopeSpec &SS); + bool isDependentScopeSpecifier(const CXXScopeSpec &SS); /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). @@ -1880,6 +1881,12 @@ public: ClassTemplateSpecializationDecl *ClassTemplateSpec, bool ExplicitInstantiation); + CXXScopeSpec InstantiateScopeSpecifier(const NestedNameSpecifier *Components, + unsigned NumComponents, + SourceRange Range, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + // Simple function for cloning expressions. template<typename T> OwningExprResult Clone(T *E) { diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 156f3a12fb..9e1196143b 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -29,6 +29,21 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) { return NNS.computeDeclContext(Context); } +bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) { + if (!SS.isSet() || SS.isInvalid()) + return false; + + NestedNameSpecifier NNS + = NestedNameSpecifier::getFromOpaquePtr(SS.getCurrentScopeRep()); + + if (Type *T = NNS.getAsType()) + return T->isDependentType(); + + // FIXME: What about the injected-class-name of a class template? It + // is dependent, but we represent it as a declaration. + return false; +} + /// \brief Require that the context specified by SS be complete. /// /// If SS refers to a type, this routine checks whether the type is diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 483b79a098..18d55d92f4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -52,6 +52,20 @@ std::string Sema::getDeclName(DeclTy *d) { /// and then return NULL. Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS) { + // C++ [temp.res]p3: + // A qualified-id that refers to a type and in which the + // nested-name-specifier depends on a template-parameter (14.6.2) + // shall be prefixed by the keyword typename to indicate that the + // qualified-id denotes a type, forming an + // elaborated-type-specifier (7.1.5.3). + // + // We therefore do not perform any name lookup up SS is a dependent + // scope name. FIXME: we will need to perform a special kind of + // lookup if the scope specifier names a member of the current + // instantiation. + if (SS && isDependentScopeSpecifier(*SS)) + return 0; + NamedDecl *IIDecl = 0; LookupResult Result = LookupParsedName(S, SS, &II, LookupOrdinaryName, false, false); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index b15f6ab984..e43d4b8027 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -613,6 +613,21 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, // Could be enum-constant, value decl, instance variable, etc. if (SS && SS->isInvalid()) return ExprError(); + + // C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it contains: + // -- a nested-name-specifier that contains a class-name that + // names a dependent type. + if (SS && isDependentScopeSpecifier(*SS)) { + llvm::SmallVector<NestedNameSpecifier, 16> Specs; + for (CXXScopeSpec::iterator Spec = SS->begin(), SpecEnd = SS->end(); + Spec != SpecEnd; ++Spec) + Specs.push_back(NestedNameSpecifier::getFromOpaquePtr(*Spec)); + return Owned(UnresolvedDeclRefExpr::Create(Context, Name, Loc, + SS->getRange(), &Specs[0], + Specs.size())); + } + LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName, false, true, Loc); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index b4e505e7c2..fd39a9150f 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -477,7 +477,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, - NewClass); + NewClass, PrevClassTemplate); // Set the lexical context of these templates NewClass->setLexicalDeclContext(CurContext); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 7df9941aa5..10f9926b3e 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -625,6 +625,7 @@ namespace { OwningExprResult VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); OwningExprResult VisitConditionalOperator(ConditionalOperator *E); OwningExprResult VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + OwningExprResult VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *E); OwningExprResult VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E); OwningExprResult VisitImplicitCastExpr(ImplicitCastExpr *E); @@ -897,6 +898,26 @@ TemplateExprInstantiator::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { } Sema::OwningExprResult +TemplateExprInstantiator::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *E) { + CXXScopeSpec SS = SemaRef.InstantiateScopeSpecifier(E->begin(), E->size(), + E->getQualifierRange(), + TemplateArgs, + NumTemplateArgs); + if (SS.isInvalid() || SS.isEmpty()) + return SemaRef.ExprError(); + + // FIXME: We're passing in a NULL scope, because + // ActOnDeclarationNameExpr doesn't actually use the scope when we + // give it a non-empty scope specifier. Investigate whether it would + // be better to refactor ActOnDeclarationNameExpr. + return SemaRef.ActOnDeclarationNameExpr(/*Scope=*/0, E->getLocation(), + E->getDeclName(), + /*HasTrailingLParen=*/false, + &SS, + /*FIXME:isAddressOfOperand=*/false); +} + +Sema::OwningExprResult TemplateExprInstantiator::VisitCXXTemporaryObjectExpr( CXXTemporaryObjectExpr *E) { QualType T = E->getType(); @@ -1047,7 +1068,9 @@ Sema::InstantiateClassTemplateSpecialization( // the best template. ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate(); - if (!Template->getTemplatedDecl()->getDefinition(Context)) { + RecordDecl *Pattern = cast_or_null<RecordDecl>( + Template->getTemplatedDecl()->getDefinition(Context)); + if (!Pattern) { Diag(ClassTemplateSpec->getLocation(), diag::err_template_implicit_instantiate_undefined) << Context.getTypeDeclType(ClassTemplateSpec); @@ -1084,7 +1107,6 @@ Sema::InstantiateClassTemplateSpecialization( // FIXME: Create the injected-class-name for the // instantiation. Should this be a typedef or something like it? - RecordDecl *Pattern = Template->getTemplatedDecl(); llvm::SmallVector<DeclTy *, 32> Fields; for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), MemberEnd = Pattern->decls_end(); @@ -1118,3 +1140,34 @@ Sema::InstantiateClassTemplateSpecialization( return Invalid; } + +/// \brief Instantiate a sequence of nested-name-specifiers into a +/// scope specifier. +CXXScopeSpec +Sema::InstantiateScopeSpecifier(const NestedNameSpecifier *Components, + unsigned NumComponents, + SourceRange Range, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + CXXScopeSpec SS; + for (unsigned Comp = 0; Comp < NumComponents; ++Comp) { + if (Type *T = Components[Comp].getAsType()) { + QualType NewT = InstantiateType(QualType(T, 0), TemplateArgs, + NumTemplateArgs, Range.getBegin(), + DeclarationName()); + if (NewT.isNull()) + return SS; + NestedNameSpecifier NNS(NewT.getTypePtr()); + SS.addScopeRep(NNS.getAsOpaquePtr()); + } else { + DeclContext *DC = Components[Comp].getAsDeclContext(); + // FIXME: injected-class-name might be dependent, and therefore + // would need instantiation. + NestedNameSpecifier NNS(DC); + SS.addScopeRep(NNS.getAsOpaquePtr()); + } + } + + SS.setRange(Range); + return SS; +} |