diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-03-27 23:10:48 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-03-27 23:10:48 +0000 |
commit | d57959af02b4af695276f4204443afe6e5d86bd8 (patch) | |
tree | 1c3cfaf8db2cb260e9365d44d7f5b178a836b750 /lib/Sema | |
parent | ced21016cec1f189a695857bed103ecc9e3f3696 (diff) |
Initial implementation of parsing, semantic analysis, and template
instantiation for C++ typename-specifiers such as
typename T::type
The parsing of typename-specifiers is relatively easy thanks to
annotation tokens. When we see the "typename", we parse the
typename-specifier and produce a typename annotation token. There are
only a few places where we need to handle this. We currently parse the
typename-specifier form that terminates in an identifier, but not the
simple-template-id form, e.g.,
typename T::template apply<U, V>
Parsing of nested-name-specifiers has a similar problem, since at this
point we don't have any representation of a class template
specialization whose template-name is unknown.
Semantic analysis is only partially complete, with some support for
template instantiation that works for simple examples.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67875 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.h | 14 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 81 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 41 |
4 files changed, 135 insertions, 14 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index ac260c2e20..8dee4f19a2 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1790,6 +1790,20 @@ public: bool CheckTemplateDeclScope(Scope *S, MultiTemplateParamsArg &TemplateParameterLists); + /// \brief Called when the parser has parsed a C++ typename + /// specifier, e.g., "typename T::type". + /// + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param II the identifier we're retrieving (e.g., 'type' in the example). + /// \param IdLoc the location of the identifier. + virtual TypeResult + ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, + const IdentifierInfo &II, SourceLocation IdLoc); + QualType CheckTypenameType(NestedNameSpecifier *NNS, + const IdentifierInfo &II, + SourceRange Range); + //===--------------------------------------------------------------------===// // C++ Template Instantiation // diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 8fb2811ce5..a879989b33 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -127,17 +127,20 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) { // Determine whether we have a class (or, in C++0x, an enum) or // a typedef thereof. If so, build the nested-name-specifier. - QualType T; - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { + QualType T = Context.getTypeDeclType(Type); + bool AcceptableType = false; + if (T->isDependentType()) + AcceptableType = true; + else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { if (TD->getUnderlyingType()->isRecordType() || (getLangOptions().CPlusPlus0x && TD->getUnderlyingType()->isEnumeralType())) - T = Context.getTypeDeclType(TD); + AcceptableType = true; } else if (isa<RecordDecl>(Type) || (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type))) - T = Context.getTypeDeclType(Type); + AcceptableType = true; - if (!T.isNull()) + if (AcceptableType) return NestedNameSpecifier::Create(Context, Prefix, false, T.getTypePtr()); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 697582c82c..69946975cd 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1964,3 +1964,84 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, CurContext->addDecl(Specialization); return Specialization; } + +Sema::TypeResult +Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, + const IdentifierInfo &II, SourceLocation IdLoc) { + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + if (!NNS) + return true; + + QualType T = CheckTypenameType(NNS, II, SourceRange(TypenameLoc, IdLoc)); + if (T.isNull()) + return 0; + + return T.getAsOpaquePtr(); +} + +/// \brief Build the type that describes a C++ typename specifier, +/// e.g., "typename T::type". +QualType +Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, + SourceRange Range) { + if (NNS->isDependent()) // FIXME: member of the current instantiation! + return Context.getTypenameType(NNS, &II); + + CXXScopeSpec SS; + SS.setScopeRep(NNS); + SS.setRange(Range); + if (RequireCompleteDeclContext(SS)) + return QualType(); + + DeclContext *Ctx = computeDeclContext(SS); + assert(Ctx && "No declaration context?"); + + DeclarationName Name(&II); + LookupResult Result = LookupQualifiedName(Ctx, Name, LookupOrdinaryName, + false); + unsigned DiagID = 0; + Decl *Referenced = 0; + switch (Result.getKind()) { + case LookupResult::NotFound: + if (Ctx->isTranslationUnit()) + DiagID = diag::err_typename_nested_not_found_global; + else + DiagID = diag::err_typename_nested_not_found; + break; + + case LookupResult::Found: + if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getAsDecl())) { + // We found a type. Build a QualifiedNameType, since the + // typename-specifier was just sugar. FIXME: Tell + // QualifiedNameType that it has a "typename" prefix. + return Context.getQualifiedNameType(NNS, Context.getTypeDeclType(Type)); + } + + DiagID = diag::err_typename_nested_not_type; + Referenced = Result.getAsDecl(); + break; + + case LookupResult::FoundOverloaded: + DiagID = diag::err_typename_nested_not_type; + Referenced = *Result.begin(); + break; + + case LookupResult::AmbiguousBaseSubobjectTypes: + case LookupResult::AmbiguousBaseSubobjects: + case LookupResult::AmbiguousReference: + DiagnoseAmbiguousLookup(Result, Name, Range.getEnd(), Range); + return QualType(); + } + + // If we get here, it's because name lookup did not find a + // type. Emit an appropriate diagnostic and return an error. + if (NamedDecl *NamedCtx = dyn_cast<NamedDecl>(Ctx)) + Diag(Range.getEnd(), DiagID) << Range << Name << NamedCtx; + else + Diag(Range.getEnd(), DiagID) << Range << Name; + if (Referenced) + Diag(Referenced->getLocation(), diag::note_typename_refers_here) + << Name; + return QualType(); +} diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 52f87b93f7..b274f87025 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -485,8 +485,23 @@ QualType TemplateTypeInstantiator:: InstantiateQualifiedNameType(const QualifiedNameType *T, unsigned Quals) const { - assert(false && "Cannot have dependent qualified name types (yet)"); - return QualType(); + // When we instantiated a qualified name type, there's no point in + // keeping the qualification around in the instantiated result. So, + // just instantiate the named type. + return (*this)(T->getNamedType()); +} + +QualType +TemplateTypeInstantiator:: +InstantiateTypenameType(const TypenameType *T, unsigned Quals) const { + NestedNameSpecifier *NNS + = SemaRef.InstantiateNestedNameSpecifier(T->getQualifier(), + SourceRange(Loc), + TemplateArgs, NumTemplateArgs); + if (!NNS) + return QualType(); + + return SemaRef.CheckTypenameType(NNS, *T->getName(), SourceRange(Loc)); } QualType @@ -799,21 +814,29 @@ Sema::InstantiateNestedNameSpecifier(NestedNameSpecifier *NNS, if (!T->isDependentType()) return NNS; + // FIXME: We won't be able to perform the instantiation here when + // the template-name is dependent, e.g., we have something like + // "T::template apply<U>::type". T = InstantiateType(T, TemplateArgs, NumTemplateArgs, Range.getBegin(), DeclarationName()); if (T.isNull()) return 0; - // Note that T.getTypePtr(), below, strips cv-qualifiers. This is - // perfectly reasonable, since cv-qualified types in - // nested-name-specifiers don't matter. - // FIXME: we need to perform more checking on this type. - return NestedNameSpecifier::Create(Context, Prefix, + if (T->isRecordType() || + (getLangOptions().CPlusPlus0x && T->isEnumeralType())) { + // Note that T.getTypePtr(), below, strips cv-qualifiers. This is + // perfectly reasonable, since cv-qualified types in + // nested-name-specifiers don't matter. + return NestedNameSpecifier::Create(Context, Prefix, NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, - T.getTypePtr()); + T.getTypePtr()); + } + + Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T; + return 0; } } - // Required to silence GCC warning. + // Required to silence a GCC warning return 0; } |