diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 4 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 102 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 15 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 35 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 29 | ||||
-rw-r--r-- | test/SemaTemplate/current-instantiation.cpp | 71 | ||||
-rw-r--r-- | test/SemaTemplate/dependent-type-identity.cpp | 1 |
10 files changed, 235 insertions, 35 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index b81871ace2..f8e92bd407 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -408,7 +408,7 @@ public: /// the CXXRecordDecl X<T>::A. When a complete definition of /// X<int>::A is required, it will be instantiated from the /// declaration returned by getInstantiatedFromMemberClass(). - CXXRecordDecl *getInstantiatedFromMemberClass() { + CXXRecordDecl *getInstantiatedFromMemberClass() const { return TemplateOrInstantiation.dyn_cast<CXXRecordDecl*>(); } @@ -429,7 +429,7 @@ public: /// CXXRecordDecl that from a ClassTemplateDecl, while /// getDescribedClassTemplate() retrieves the ClassTemplateDecl from /// a CXXRecordDecl. - ClassTemplateDecl *getDescribedClassTemplate() { + ClassTemplateDecl *getDescribedClassTemplate() const { return TemplateOrInstantiation.dyn_cast<ClassTemplateDecl*>(); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 621145f1af..319d4d5756 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -507,9 +507,10 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { //===----------------------------------------------------------------------===// bool TagDecl::isDependentType() const { - if (isa<TemplateDecl>(this)) - return true; - + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) + if (Record->getDescribedClassTemplate()) + return true; + if (const TagDecl *TD = dyn_cast_or_null<TagDecl>(getDeclContext())) return TD->isDependentType(); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 20d1edb269..7a25fa9668 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1602,6 +1602,8 @@ public: DeclContext *computeDeclContext(const CXXScopeSpec &SS); bool isDependentScopeSpecifier(const CXXScopeSpec &SS); + CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); + bool isUnknownSpecialization(const CXXScopeSpec &SS); /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the /// global scope ('::'). diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 5395869a02..bbc1bc52cb 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -13,6 +13,7 @@ #include "Sema.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/Parse/DeclSpec.h" #include "llvm/ADT/STLExtras.h" @@ -26,8 +27,14 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS) { NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - if (NNS->isDependent()) - return 0; + if (NNS->isDependent()) { + // If this nested-name-specifier refers to the current + // instantiation, return its DeclContext. + if (CXXRecordDecl *Record = getCurrentInstantiationOf(NNS)) + return Record; + else + return 0; + } switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: @@ -61,6 +68,90 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) { return NNS->isDependent(); } +// \brief Determine whether this C++ scope specifier refers to an +// unknown specialization, i.e., a dependent type that is not the +// current instantiation. +bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) { + if (!isDependentScopeSpecifier(SS)) + return false; + + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + return getCurrentInstantiationOf(NNS) == 0; +} + +/// \brief If the given nested name specifier refers to the current +/// instantiation, return the declaration that corresponds to that +/// current instantiation (C++0x [temp.dep.type]p1). +/// +/// \param NNS a dependent nested name specifier. +CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { + assert(getLangOptions().CPlusPlus && "Only callable in C++"); + assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed"); + + QualType T = QualType(NNS->getAsType(), 0); + // If the nested name specifier does not refer to a type, then it + // does not refer to the current instantiation. + if (T.isNull()) + return 0; + + T = Context.getCanonicalType(T); + + for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) { + // If we've hit a namespace or the global scope, then the + // nested-name-specifier can't refer to the current instantiation. + if (Ctx->isFileContext()) + return 0; + + // Skip non-class contexts. + CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); + if (!Record) + continue; + + // If this record type is not dependent, + if (!Record->isDependentType()) + return 0; + + // C++ [temp.dep.type]p1: + // + // In the definition of a class template, a nested class of a + // class template, a member of a class template, or a member of a + // nested class of a class template, a name refers to the current + // instantiation if it is + // -- the injected-class-name (9) of the class template or + // nested class, + // -- in the definition of a primary class template, the name + // of the class template followed by the template argument + // list of the primary template (as described below) + // enclosed in <>, + // -- in the definition of a nested class of a class template, + // the name of the nested class referenced as a member of + // the current instantiation, or + // -- in the definition of a partial specialization, the name + // of the class template followed by the template argument + // list of the partial specialization enclosed in <>. If + // the nth template parameter is a parameter pack, the nth + // template argument is a pack expansion (14.6.3) whose + // pattern is the name of the parameter pack. (FIXME) + // + // All of these options come down to having the + // nested-name-specifier type that is equivalent to the + // injected-class-name of one of the types that is currently in + // our context. + if (Context.getTypeDeclType(Record) == T) + return Record; + + if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) { + QualType InjectedClassName + = Template->getInjectedClassNameType(Context); + if (T == Context.getCanonicalType(InjectedClassName)) + return Template->getTemplatedDecl(); + } + } + + return 0; +} + /// \brief Require that the context specified by SS be complete. /// /// If SS refers to a type, this routine checks whether the type is @@ -113,9 +204,10 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, NestedNameSpecifier *Prefix = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - // If the prefix is already dependent, there is no name lookup to - // perform. Just build the resulting nested-name-specifier. - if (Prefix && Prefix->isDependent()) + // If the prefix already refers to an unknown specialization, there + // is no name lookup to perform. Just build the resulting + // nested-name-specifier. + if (Prefix && isUnknownSpecialization(SS)) return NestedNameSpecifier::Create(Context, Prefix, &II); NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d9e883f7a8..c778ca6c29 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -64,16 +64,15 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // 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)) + // We therefore do not perform any name lookup if the result would + // refer to a member of an unknown specialization. + if (SS && isUnknownSpecialization(*SS)) return 0; + LookupResult Result + = LookupParsedName(S, SS, &II, LookupOrdinaryName, false, false); + NamedDecl *IIDecl = 0; - LookupResult Result = LookupParsedName(S, SS, &II, LookupOrdinaryName, - false, false); switch (Result.getKind()) { case LookupResult::NotFound: case LookupResult::FoundOverloaded: @@ -3402,7 +3401,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, } } else if (TK == TK_Reference && SS.isEmpty() && Name && (Kind != TagDecl::TK_enum || !getLangOptions().CPlusPlus)) { - // C.scope.pdecl]p5: + // C++ [basic.scope.pdecl]p5: // -- for an elaborated-type-specifier of the form // // class-key identifier diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 11a38869e1..7e91f5beac 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -941,7 +941,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, DeclPtrTy TagDecl, SourceLocation LBrac, SourceLocation RBrac) { - TemplateDecl *Template = AdjustDeclIfTemplate(TagDecl); + AdjustDeclIfTemplate(TagDecl); ActOnFields(S, RLoc, TagDecl, (DeclPtrTy*)FieldCollector->getCurFields(), FieldCollector->getCurNumFields(), LBrac, RBrac, 0); @@ -982,7 +982,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, } } - if (!Template) + if (!RD->isDependentType()) AddImplicitlyDeclaredMembersToClass(RD); } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index b1643bb50b..64acbe04c1 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -17,6 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/Parse/DeclSpec.h" #include "clang/Basic/LangOptions.h" @@ -1117,14 +1118,37 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS, DeclarationName Name, LookupNameKind NameKind, bool RedeclarationOnly, bool AllowBuiltinCreation, SourceLocation Loc) { - if (SS) { - if (SS->isInvalid() || RequireCompleteDeclContext(*SS)) + if (SS && (SS->isSet() || SS->isInvalid())) { + // If the scope specifier is invalid, don't even look for + // anything. + if (SS->isInvalid()) return LookupResult::CreateLookupResult(Context, 0); - if (SS->isSet()) { - return LookupQualifiedName(computeDeclContext(*SS), - Name, NameKind, RedeclarationOnly); + assert(!isUnknownSpecialization(*SS) && "Can't lookup dependent types"); + + if (isDependentScopeSpecifier(*SS)) { + // Determine whether we are looking into the current + // instantiation. + NestedNameSpecifier *NNS + = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); + CXXRecordDecl *Current = getCurrentInstantiationOf(NNS); + assert(Current && "Bad dependent scope specifier"); + + // We nested name specifier refers to the current instantiation, + // so now we will look for a member of the current instantiation + // (C++0x [temp.dep.type]). + unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind, true); + DeclContext::lookup_iterator I, E; + for (llvm::tie(I, E) = Current->lookup(Context, Name); I != E; ++I) + if (isAcceptableLookupResult(*I, NameKind, IDNS)) + return LookupResult::CreateLookupResult(Context, I, E); } + + if (RequireCompleteDeclContext(*SS)) + return LookupResult::CreateLookupResult(Context, 0); + + return LookupQualifiedName(computeDeclContext(*SS), + Name, NameKind, RedeclarationOnly); } return LookupName(S, Name, NameKind, RedeclarationOnly, @@ -1601,4 +1625,3 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, } } } - diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 0e1daea23c..3938978dfd 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2170,16 +2170,29 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, QualType Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, SourceRange Range) { - if (NNS->isDependent()) // FIXME: member of the current instantiation! - return Context.getTypenameType(NNS, &II); + CXXRecordDecl *CurrentInstantiation = 0; + if (NNS->isDependent()) { + CurrentInstantiation = getCurrentInstantiationOf(NNS); + + // If the nested-name-specifier does not refer to the current + // instantiation, then build a typename type. + if (!CurrentInstantiation) + return Context.getTypenameType(NNS, &II); + } - CXXScopeSpec SS; - SS.setScopeRep(NNS); - SS.setRange(Range); - if (RequireCompleteDeclContext(SS)) - return QualType(); + DeclContext *Ctx = 0; - DeclContext *Ctx = computeDeclContext(SS); + if (CurrentInstantiation) + Ctx = CurrentInstantiation; + else { + CXXScopeSpec SS; + SS.setScopeRep(NNS); + SS.setRange(Range); + if (RequireCompleteDeclContext(SS)) + return QualType(); + + Ctx = computeDeclContext(SS); + } assert(Ctx && "No declaration context?"); DeclarationName Name(&II); diff --git a/test/SemaTemplate/current-instantiation.cpp b/test/SemaTemplate/current-instantiation.cpp new file mode 100644 index 0000000000..603c14016f --- /dev/null +++ b/test/SemaTemplate/current-instantiation.cpp @@ -0,0 +1,71 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +// This test concerns the identity of dependent types within the +// canonical type system, specifically focusing on the difference +// between members of the current instantiation and membmers of an +// unknown specialization. This considers C++ [temp.type], which +// specifies type equivalence within a template, and C++0x +// [temp.dep.type], which defines what it means to be a member of the +// current instantiation. + +template<typename T, typename U> +struct X0 { + typedef T T_type; + typedef U U_type; + + void f0(T&); // expected-note{{previous}} + void f0(typename X0::U_type&); + void f0(typename X0::T_type&); // expected-error{{redecl}} + + void f1(T&); // expected-note{{previous}} + void f1(typename X0::U_type&); + void f1(typename X0<T, U>::T_type&); // expected-error{{redecl}} + + void f2(T&); // expected-note{{previous}} + void f2(typename X0::U_type&); + void f2(typename X0<T_type, U_type>::T_type&); // expected-error{{redecl}} + + void f3(T&); // expected-note{{previous}} + void f3(typename X0::U_type&); + void f3(typename ::X0<T_type, U_type>::T_type&); // expected-error{{redecl}} + + struct X1 { + typedef T my_T_type; + + void g0(T&); // expected-note{{previous}} + void g0(typename X0::U_type&); + void g0(typename X0::T_type&); // expected-error{{redecl}} + + void g1(T&); // expected-note{{previous}} + void g1(typename X0::U_type&); + void g1(typename X0<T, U>::T_type&); // expected-error{{redecl}} + + void g2(T&); // expected-note{{previous}} + void g2(typename X0::U_type&); + void g2(typename X0<T_type, U_type>::T_type&); // expected-error{{redecl}} + + void g3(T&); // expected-note{{previous}} + void g3(typename X0::U_type&); + void g3(typename ::X0<T_type, U_type>::T_type&); // expected-error{{redecl}} + + void g4(T&); // expected-note{{previous}} + void g4(typename X0::U_type&); + void g4(typename X1::my_T_type&); // expected-error{{redecl}} + + void g5(T&); // expected-note{{previous}} + void g5(typename X0::U_type&); + void g5(typename X0::X1::my_T_type&); // expected-error{{redecl}} + + void g6(T&); // expected-note{{previous}} + void g6(typename X0::U_type&); + void g6(typename X0<T, U>::X1::my_T_type&); // expected-error{{redecl}} + + void g7(T&); // expected-note{{previous}} + void g7(typename X0::U_type&); + void g7(typename ::X0<typename X1::my_T_type, U_type>::X1::my_T_type&); // expected-error{{redecl}} + + void g8(T&); // expected-note{{previous}} + void g8(typename X0<U, T_type>::T_type&); + void g8(typename ::X0<typename X0<T_type, U>::X1::my_T_type, U_type>::X1::my_T_type&); // expected-error{{redecl}} + }; +}; diff --git a/test/SemaTemplate/dependent-type-identity.cpp b/test/SemaTemplate/dependent-type-identity.cpp index 6843dbe892..739cb7f39f 100644 --- a/test/SemaTemplate/dependent-type-identity.cpp +++ b/test/SemaTemplate/dependent-type-identity.cpp @@ -5,7 +5,6 @@ // specifies type equivalence within a template. // // FIXME: template template parameters -// FIXME: members of the current instantiation namespace N { template<typename T> |