From: John McCall Date: Wed, 18 Nov 2009 02:36:19 +0000 (+0000) Subject: Incremental progress on using declarations. Split UnresolvedUsingDecl into X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7ba107a1863ddfa1664555854f0d7bdb3c491c92;p=clang Incremental progress on using declarations. Split UnresolvedUsingDecl into two classes, one for typenames and one for values; this seems to have some support from Doug if not necessarily from the extremely-vague-on-this-point standard. Track the location of the 'typename' keyword in a using-typename decl. Make a new lookup result for unresolved values and deal with it in most places. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89184 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 76834d77ec..f9d2f71b1f 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -56,7 +56,6 @@ namespace clang { class TranslationUnitDecl; class TypeDecl; class TypedefDecl; - class UnresolvedUsingDecl; class UsingDecl; namespace Builtin { class Context; } @@ -205,7 +204,7 @@ class ASTContext { /// /// This mapping will contain an entry that maps from the UsingDecl in /// B to the UnresolvedUsingDecl in B. - llvm::DenseMap + llvm::DenseMap InstantiatedFromUnresolvedUsingDecl; llvm::DenseMap InstantiatedFromUnnamedFieldDecl; @@ -285,12 +284,11 @@ public: /// \brief If this using decl is instantiated from an unresolved using decl, /// return it. - UnresolvedUsingDecl *getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD); + NamedDecl *getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD); /// \brief Note that the using decl \p Inst is an instantiation of /// the unresolved using decl \p Tmpl of a class template. - void setInstantiatedFromUnresolvedUsingDecl(UsingDecl *Inst, - UnresolvedUsingDecl *Tmpl); + void setInstantiatedFromUnresolvedUsingDecl(UsingDecl *Inst, NamedDecl *Tmpl); FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field); diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 4d8991a46f..e5bf78cd10 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1766,31 +1766,88 @@ public: static bool classof(const UsingDecl *D) { return true; } }; -/// UnresolvedUsingDecl - Represents a using declaration whose name can not -/// yet be resolved. -class UnresolvedUsingDecl : public NamedDecl { +/// UnresolvedUsingValueDecl - Represents a dependent using +/// declaration which was not marked with 'typename'. Unlike +/// non-dependent using declarations, these *only* bring through +/// non-types; otherwise they would break two-phase lookup. +/// +/// template class A : public Base { +/// using Base::foo; +/// }; +class UnresolvedUsingValueDecl : public ValueDecl { /// \brief The source range that covers the nested-name-specifier /// preceding the declaration name. SourceRange TargetNestedNameRange; - /// \brief The source location of the target declaration name. - SourceLocation TargetNameLocation; + /// \brief The source location of the 'using' keyword + SourceLocation UsingLocation; NestedNameSpecifier *TargetNestedNameSpecifier; - DeclarationName TargetName; + UnresolvedUsingValueDecl(DeclContext *DC, QualType Ty, + SourceLocation UsingLoc, SourceRange TargetNNR, + NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, + DeclarationName TargetName) + : ValueDecl(Decl::UnresolvedUsingValue, DC, TargetNameLoc, TargetName, Ty), + TargetNestedNameRange(TargetNNR), UsingLocation(UsingLoc), + TargetNestedNameSpecifier(TargetNNS) + { } - // \brief Has 'typename' keyword. - bool IsTypeName; +public: + /// \brief Returns the source range that covers the nested-name-specifier + /// preceding the namespace name. + SourceRange getTargetNestedNameRange() const { return TargetNestedNameRange; } + + /// \brief Get target nested name declaration. + NestedNameSpecifier* getTargetNestedNameSpecifier() { + return TargetNestedNameSpecifier; + } + + /// \brief Returns the source location of the 'using' keyword. + SourceLocation getUsingLoc() const { return UsingLocation; } + + static UnresolvedUsingValueDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, + SourceRange TargetNNR, NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, DeclarationName TargetName); + + static bool classof(const Decl *D) { + return D->getKind() == Decl::UnresolvedUsingValue; + } + static bool classof(const UnresolvedUsingValueDecl *D) { return true; } +}; - UnresolvedUsingDecl(DeclContext *DC, SourceLocation UsingLoc, - SourceRange TargetNNR, NestedNameSpecifier *TargetNNS, - SourceLocation TargetNameLoc, DeclarationName TargetName, - bool IsTypeNameArg) - : NamedDecl(Decl::UnresolvedUsing, DC, UsingLoc, TargetName), - TargetNestedNameRange(TargetNNR), TargetNameLocation(TargetNameLoc), - TargetNestedNameSpecifier(TargetNNS), TargetName(TargetName), - IsTypeName(IsTypeNameArg) { } +/// UnresolvedUsingTypenameDecl - Represents a dependent using +/// declaration which was marked with 'typename'. +/// +/// template class A : public Base { +/// using typename Base::foo; +/// }; +/// +/// The type associated with a unresolved using typename decl is +/// currently always a typename type. +class UnresolvedUsingTypenameDecl : public TypeDecl { + /// \brief The source range that covers the nested-name-specifier + /// preceding the declaration name. + SourceRange TargetNestedNameRange; + + /// \brief The source location of the 'using' keyword + SourceLocation UsingLocation; + + /// \brief The source location of the 'typename' keyword + SourceLocation TypenameLocation; + + NestedNameSpecifier *TargetNestedNameSpecifier; + + UnresolvedUsingTypenameDecl(DeclContext *DC, SourceLocation UsingLoc, + SourceLocation TypenameLoc, + SourceRange TargetNNR, NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, IdentifierInfo *TargetName) + : TypeDecl(Decl::UnresolvedUsingTypename, DC, TargetNameLoc, TargetName), + TargetNestedNameRange(TargetNNR), UsingLocation(UsingLoc), + TypenameLocation(TypenameLoc), TargetNestedNameSpecifier(TargetNNS) + { } public: /// \brief Returns the source range that covers the nested-name-specifier @@ -1802,26 +1859,22 @@ public: return TargetNestedNameSpecifier; } - /// \brief Returns the source location of the target declaration name. - SourceLocation getTargetNameLocation() const { return TargetNameLocation; } + /// \brief Returns the source location of the 'using' keyword. + SourceLocation getUsingLoc() const { return UsingLocation; } - /// \brief Returns the source location of the target declaration name. - DeclarationName getTargetName() const { return TargetName; } - - bool isTypeName() const { return IsTypeName; } + /// \brief Returns the source location of the 'typename' keyword. + SourceLocation getTypenameLoc() const { return TypenameLocation; } - static UnresolvedUsingDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation UsingLoc, - SourceRange TargetNNR, - NestedNameSpecifier *TargetNNS, - SourceLocation TargetNameLoc, - DeclarationName TargetName, - bool IsTypeNameArg); + static UnresolvedUsingTypenameDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, + SourceLocation TypenameLoc, + SourceRange TargetNNR, NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, DeclarationName TargetName); static bool classof(const Decl *D) { - return D->getKind() == Decl::UnresolvedUsing; + return D->getKind() == Decl::UnresolvedUsingTypename; } - static bool classof(const UnresolvedUsingDecl *D) { return true; } + static bool classof(const UnresolvedUsingTypenameDecl *D) { return true; } }; /// StaticAssertDecl - Represents a C++0x static_assert declaration. diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def index f0238375cc..ec1b3b055c 100644 --- a/include/clang/AST/DeclNodes.def +++ b/include/clang/AST/DeclNodes.def @@ -81,6 +81,7 @@ ABSTRACT_DECL(Named, Decl) DECL(NamespaceAlias, NamedDecl) ABSTRACT_DECL(Type, NamedDecl) DECL(Typedef, TypeDecl) + DECL(UnresolvedUsingTypename, TypeDecl) ABSTRACT_DECL(Tag, TypeDecl) DECL(Enum, TagDecl) DECL(Record, TagDecl) @@ -91,6 +92,7 @@ ABSTRACT_DECL(Named, Decl) DECL(TemplateTypeParm, TypeDecl) ABSTRACT_DECL(Value, NamedDecl) DECL(EnumConstant, ValueDecl) + DECL(UnresolvedUsingValue, ValueDecl) ABSTRACT_DECL(Declarator, ValueDecl) DECL(Function, DeclaratorDecl) DECL(CXXMethod, FunctionDecl) @@ -109,7 +111,6 @@ ABSTRACT_DECL(Named, Decl) DECL(ClassTemplate, TemplateDecl) DECL(TemplateTemplateParm, TemplateDecl) DECL(Using, NamedDecl) - DECL(UnresolvedUsing, NamedDecl) DECL(UsingShadow, NamedDecl) DECL(ObjCMethod, NamedDecl) DECL(ObjCContainer, NamedDecl) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fd544827b1..78a3ae5d47 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -103,6 +103,8 @@ def err_using_requires_qualname : Error< "using declaration requires a qualified name">; def err_using_typename_non_type : Error< "'typename' keyword used on a non-type">; +def err_using_dependent_value_is_type : Error< + "dependent using declaration resolved to type without 'typename'">; def err_using_decl_nested_name_specifier_is_not_a_base_class : Error< "using declaration refers into '%0', which is not a base class of %1">; def err_using_decl_can_not_refer_to_class_member : Error< @@ -115,6 +117,8 @@ def err_using_decl_destructor : Error< "using declaration can not refer to a destructor">; def err_using_decl_template_id : Error< "using declaration can not refer to a template specialization">; +def note_using_decl_target : Note< + "target of using declaration">; def err_invalid_thread : Error< "'__thread' is only allowed on variable declarations">; diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 87fa63e42c..d1f241ea70 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1203,6 +1203,8 @@ public: /// 'typename' keyword. FIXME: This will eventually be split into a /// separate action. /// + /// \param TypenameLoc the location of the 'typename' keyword, if present + /// /// \returns a representation of the using declaration. virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, @@ -1210,7 +1212,8 @@ public: const CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, - bool IsTypeName); + bool IsTypeName, + SourceLocation TypenameLoc); /// ActOnParamDefaultArgument - Parse default argument for function parameter virtual void ActOnParamDefaultArgument(DeclPtrTy param, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c3dc8bc4da..dc13e7f468 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -256,9 +256,9 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, = new (*this) MemberSpecializationInfo(Tmpl, TSK); } -UnresolvedUsingDecl * +NamedDecl * ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) { - llvm::DenseMap::const_iterator Pos + llvm::DenseMap::const_iterator Pos = InstantiatedFromUnresolvedUsingDecl.find(UUD); if (Pos == InstantiatedFromUnresolvedUsingDecl.end()) return 0; @@ -268,7 +268,10 @@ ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) { void ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD, - UnresolvedUsingDecl *UUD) { + NamedDecl *UUD) { + assert((isa(UUD) || + isa(UUD)) && + "original declaration is not an unresolved using decl"); assert(!InstantiatedFromUnresolvedUsingDecl[UD] && "Already noted what using decl what instantiated from"); InstantiatedFromUnresolvedUsingDecl[UD] = UUD; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index abcffed405..831f552489 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -212,8 +212,9 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case UsingShadow: return 0; // we'll actually overwrite this later - case UnresolvedUsing: - return IDNS_Tag | IDNS_Ordinary | IDNS_Using; + case UnresolvedUsingValue: + case UnresolvedUsingTypename: + return IDNS_Ordinary | IDNS_Using; case Using: return IDNS_Using; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 520206d248..a21c93ffcd 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -920,15 +920,30 @@ UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, return new (C) UsingDecl(DC, L, NNR, UL, TargetNNS, Name, IsTypeNameArg); } -UnresolvedUsingDecl *UnresolvedUsingDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation UsingLoc, - SourceRange TargetNNR, - NestedNameSpecifier *TargetNNS, - SourceLocation TargetNameLoc, - DeclarationName TargetName, - bool IsTypeNameArg) { - return new (C) UnresolvedUsingDecl(DC, UsingLoc, TargetNNR, TargetNNS, - TargetNameLoc, TargetName, IsTypeNameArg); +UnresolvedUsingValueDecl * +UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceRange TargetNNR, + NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, + DeclarationName TargetName) { + return new (C) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc, + TargetNNR, TargetNNS, + TargetNameLoc, TargetName); +} + +UnresolvedUsingTypenameDecl * +UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceLocation TypenameLoc, + SourceRange TargetNNR, + NestedNameSpecifier *TargetNNS, + SourceLocation TargetNameLoc, + DeclarationName TargetName) { + return new (C) UnresolvedUsingTypenameDecl(DC, UsingLoc, TypenameLoc, + TargetNNR, TargetNNS, + TargetNameLoc, + TargetName.getAsIdentifierInfo()); } StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 645133b4da..131de8b2e1 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -71,7 +71,8 @@ namespace { void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); - void VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D); + void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); }; @@ -829,10 +830,17 @@ void DeclPrinter::VisitUsingDecl(UsingDecl *D) { Out << D->getNameAsString(); } -void DeclPrinter::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { +void +DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + Out << "using typename "; + D->getTargetNestedNameSpecifier()->print(Out, Policy); + Out << D->getDeclName().getAsString(); +} + +void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { Out << "using "; D->getTargetNestedNameSpecifier()->print(Out, Policy); - Out << D->getTargetName().getAsString(); + Out << D->getDeclName().getAsString(); } void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) { diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp index a83966d91e..7681eac6ed 100644 --- a/lib/Parse/MinimalAction.cpp +++ b/lib/Parse/MinimalAction.cpp @@ -49,7 +49,8 @@ Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope, const CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, - bool IsTypeName) { + bool IsTypeName, + SourceLocation TypenameLoc) { // FIXME: Parser seems to assume that Action::ActOn* takes ownership over // passed AttributeList, however other actions don't free it, is it diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index baf9e4ba59..914bfc9db8 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -283,11 +283,13 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS) { CXXScopeSpec SS; + SourceLocation TypenameLoc; bool IsTypeName; // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { + TypenameLoc = Tok.getLocation(); ConsumeToken(); IsTypeName = true; } @@ -330,7 +332,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context, tok::semi); return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS, Name, - AttrList, IsTypeName); + AttrList, IsTypeName, TypenameLoc); } /// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b3db88a7ba..35a7d782f1 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1110,6 +1110,11 @@ public: /// functions into an OverloadedFunctionDecl. FoundOverloaded, + /// @brief Name lookup found an unresolvable value declaration + /// and cannot yet complete. This only happens in C++ dependent + /// contexts with dependent using declarations. + FoundUnresolvedValue, + /// @brief Name lookup results in an ambiguity; use /// getAmbiguityKind to figure out what kind of ambiguity /// we have. @@ -1417,6 +1422,7 @@ public: assert(ResultKind != NotFound || Decls.size() == 0); assert(ResultKind != Found || Decls.size() == 1); assert(ResultKind == NotFound || ResultKind == Found || + ResultKind == FoundUnresolvedValue || (ResultKind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects) || Decls.size() > 1); assert((Paths != NULL) == (ResultKind == Ambiguous && @@ -2017,7 +2023,9 @@ public: SourceLocation IdentLoc, DeclarationName Name, AttributeList *AttrList, - bool IsTypeName); + bool IsInstantiation, + bool IsTypeName, + SourceLocation TypenameLoc); virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, @@ -2025,7 +2033,8 @@ public: const CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, - bool IsTypeName); + bool IsTypeName, + SourceLocation TypenameLoc); /// AddCXXDirectInitializerToDecl - This action is called immediately after /// ActOnDeclarator, when a C++ direct initializer is present. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2228b41b33..3f204983a3 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -94,6 +94,7 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, switch (Result.getResultKind()) { case LookupResult::NotFound: case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: return 0; case LookupResult::Ambiguous: @@ -166,6 +167,10 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, } else if (ObjCInterfaceDecl *IDecl = dyn_cast(IIDecl)) { T = Context.getObjCInterfaceType(IDecl); + } else if (UnresolvedUsingTypenameDecl *UUDecl = + dyn_cast(IIDecl)) { + // FIXME: preserve source structure information. + T = Context.getTypenameType(UUDecl->getTargetNestedNameSpecifier(), &II); } else { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); @@ -2446,7 +2451,9 @@ void Sema::CheckVariableDeclaration(VarDecl *NewVD, NamedDecl *PrevDecl, } static bool isUsingDecl(Decl *D) { - return isa(D) || isa(D); + return isa(D) || + isa(D) || + isa(D); } /// \brief Data used with FindOverriddenMethod diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 4f04bd2604..cb18064638 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2809,7 +2809,8 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, const CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, - bool IsTypeName) { + bool IsTypeName, + SourceLocation TypenameLoc) { assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); switch (Name.getKind()) { @@ -2837,7 +2838,9 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, DeclarationName TargetName = GetNameFromUnqualifiedId(Name); NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, Name.getSourceRange().getBegin(), - TargetName, AttrList, IsTypeName); + TargetName, AttrList, + /* IsInstantiation */ false, + IsTypeName, TypenameLoc); if (UD) { PushOnScopeChains(UD, S); UD->setAccess(AS); @@ -2872,13 +2875,20 @@ static UsingShadowDecl *BuildUsingShadowDecl(Sema &SemaRef, Scope *S, return Shadow; } +/// Builds a using declaration. +/// +/// \param IsInstantiation - Whether this call arises from an +/// instantiation of an unresolved using declaration. We treat +/// the lookup differently for these declarations. NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, const CXXScopeSpec &SS, SourceLocation IdentLoc, DeclarationName Name, AttributeList *AttrList, - bool IsTypeName) { + bool IsInstantiation, + bool IsTypeName, + SourceLocation TypenameLoc) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); assert(IdentLoc.isValid() && "Invalid TargetName location."); @@ -2895,9 +2905,16 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, DeclContext *LookupContext = computeDeclContext(SS); if (!LookupContext) { - return UnresolvedUsingDecl::Create(Context, CurContext, UsingLoc, - SS.getRange(), NNS, - IdentLoc, Name, IsTypeName); + if (IsTypeName) { + return UnresolvedUsingTypenameDecl::Create(Context, CurContext, + UsingLoc, TypenameLoc, + SS.getRange(), NNS, + IdentLoc, Name); + } else { + return UnresolvedUsingValueDecl::Create(Context, CurContext, + UsingLoc, SS.getRange(), NNS, + IdentLoc, Name); + } } if (const CXXRecordDecl *RD = dyn_cast(CurContext)) { @@ -2929,7 +2946,12 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // hide tag declarations: tag names are visible through the using // declaration even if hidden by ordinary names. LookupResult R(*this, Name, IdentLoc, LookupOrdinaryName); - R.setHideTags(false); + + // We don't hide tags behind ordinary decls if we're in a + // non-dependent context, but in a dependent context, this is + // important for the stability of two-phase lookup. + if (!IsInstantiation) + R.setHideTags(false); LookupQualifiedName(R, LookupContext); @@ -2942,11 +2964,27 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, if (R.isAmbiguous()) return 0; - if (IsTypeName && - (R.getResultKind() != LookupResult::Found - || !isa(R.getFoundDecl()))) { - Diag(IdentLoc, diag::err_using_typename_non_type); - return 0; + if (IsTypeName) { + // If we asked for a typename and got a non-type decl, error out. + if (R.getResultKind() != LookupResult::Found + || !isa(R.getFoundDecl())) { + Diag(IdentLoc, diag::err_using_typename_non_type); + for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) + Diag((*I)->getUnderlyingDecl()->getLocation(), + diag::note_using_decl_target); + return 0; + } + } else { + // If we asked for a non-typename and we got a type, error out, + // but only if this is an instantiation of an unresolved using + // decl. Otherwise just silently find the type name. + if (IsInstantiation && + R.getResultKind() == LookupResult::Found && + isa(R.getFoundDecl())) { + Diag(IdentLoc, diag::err_using_dependent_value_is_type); + Diag(R.getFoundDecl()->getLocation(), diag::note_using_decl_target); + return 0; + } } // C++0x N2914 [namespace.udecl]p6: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 2e33200228..43f150fbef 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -977,7 +977,7 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D, else if (TemplateDecl *Template = dyn_cast(D)) return BuildDeclRefExpr(Template, Context.OverloadTy, Loc, false, false, SS); - else if (UnresolvedUsingDecl *UD = dyn_cast(D)) + else if (UnresolvedUsingValueDecl *UD = dyn_cast(D)) return BuildDeclRefExpr(UD, Context.DependentTy, Loc, /*TypeDependent=*/true, /*ValueDependent=*/true, SS); diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index d736d42f77..f37fb8be24 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -245,7 +245,12 @@ void Sema::LookupResult::resolveKind() { unsigned N = Decls.size(); // Fast case: no possible ambiguity. - if (N <= 1) return; + if (N == 0) return; + if (N == 1) { + if (isa(Decls[0])) + ResultKind = FoundUnresolvedValue; + return; + } // Don't do any extra resolution if we've already resolved as ambiguous. if (ResultKind == Ambiguous) return; @@ -254,6 +259,7 @@ void Sema::LookupResult::resolveKind() { bool Ambiguous = false; bool HasTag = false, HasFunction = false, HasNonFunction = false; + bool HasUnresolved = false; unsigned UniqueTagIndex = 0; @@ -266,12 +272,15 @@ void Sema::LookupResult::resolveKind() { // If it's not unique, pull something off the back (and // continue at this index). Decls[I] = Decls[--N]; - } else if (isa(D)) { - // FIXME: support unresolved using decls + } else if (isa(D)) { + // FIXME: support unresolved using value declarations Decls[I] = Decls[--N]; } else { // Otherwise, do some decl type analysis and then continue. - if (isa(D)) { + + if (isa(D)) { + HasUnresolved = true; + } else if (isa(D)) { if (HasTag) Ambiguous = true; UniqueTagIndex = I; @@ -296,7 +305,8 @@ void Sema::LookupResult::resolveKind() { // wherever the object, function, or enumerator name is visible. // But it's still an error if there are distinct tag types found, // even if they're not visible. (ref?) - if (HideTags && HasTag && !Ambiguous && (HasFunction || HasNonFunction)) + if (HideTags && HasTag && !Ambiguous && !HasUnresolved && + (HasFunction || HasNonFunction)) Decls[UniqueTagIndex] = Decls[--N]; Decls.set_size(N); @@ -306,6 +316,8 @@ void Sema::LookupResult::resolveKind() { if (Ambiguous) setAmbiguous(LookupResult::AmbiguousReference); + else if (HasUnresolved) + ResultKind = LookupResult::FoundUnresolvedValue; else if (N > 1) ResultKind = LookupResult::FoundOverloaded; else diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index a799ddb24b..28fa6bdaa6 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4501,6 +4501,10 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, Referenced = Result.getFoundDecl(); break; + case LookupResult::FoundUnresolvedValue: + llvm::llvm_unreachable("unresolved using decl in non-dependent context"); + return QualType(); + case LookupResult::FoundOverloaded: DiagID = diag::err_typename_nested_not_type; Referenced = *Result.begin(); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 00ef407566..8d5741df29 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -66,7 +66,8 @@ namespace { Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D); - Decl *VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D); + Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); + Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); // Base case. FIXME: Remove once we can instantiate everything. Decl *VisitDecl(Decl *D) { @@ -1025,8 +1026,33 @@ Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { return Inst; } -Decl * -TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { +Decl * TemplateDeclInstantiator + ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + NestedNameSpecifier *NNS = + SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(), + D->getTargetNestedNameRange(), + TemplateArgs); + if (!NNS) + return 0; + + CXXScopeSpec SS; + SS.setRange(D->getTargetNestedNameRange()); + SS.setScopeRep(NNS); + + NamedDecl *UD = + SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(), + D->getUsingLoc(), SS, D->getLocation(), + D->getDeclName(), 0, + /*instantiation*/ true, + /*typename*/ true, D->getTypenameLoc()); + if (UD) + SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast(UD), + D); + return UD; +} + +Decl * TemplateDeclInstantiator + ::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { NestedNameSpecifier *NNS = SemaRef.SubstNestedNameSpecifier(D->getTargetNestedNameSpecifier(), D->getTargetNestedNameRange(), @@ -1040,8 +1066,10 @@ TemplateDeclInstantiator::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) { NamedDecl *UD = SemaRef.BuildUsingDeclaration(/*Scope*/ 0, D->getAccess(), - D->getLocation(), SS, D->getTargetNameLocation(), - D->getDeclName(), 0, D->isTypeName()); + D->getUsingLoc(), SS, D->getLocation(), + D->getDeclName(), 0, + /*instantiation*/ true, + /*typename*/ false, SourceLocation()); if (UD) SemaRef.Context.setInstantiatedFromUnresolvedUsingDecl(cast(UD), D); @@ -1724,7 +1752,13 @@ static bool isInstantiationOf(EnumDecl *Pattern, return false; } -static bool isInstantiationOf(UnresolvedUsingDecl *Pattern, +static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern, + UsingDecl *Instance, + ASTContext &C) { + return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; +} + +static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern, UsingDecl *Instance, ASTContext &C) { return C.getInstantiatedFromUnresolvedUsingDecl(Instance) == Pattern; @@ -1747,7 +1781,15 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { if (D->getKind() != Other->getKind()) { - if (UnresolvedUsingDecl *UUD = dyn_cast(D)) { + if (UnresolvedUsingTypenameDecl *UUD + = dyn_cast(D)) { + if (UsingDecl *UD = dyn_cast(Other)) { + return isInstantiationOf(UUD, UD, Ctx); + } + } + + if (UnresolvedUsingValueDecl *UUD + = dyn_cast(D)) { if (UsingDecl *UD = dyn_cast(Other)) { return isInstantiationOf(UUD, UD, Ctx); } diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp index 692ae8f4c1..35e8c08a11 100644 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p1.cpp @@ -7,11 +7,11 @@ template class test {}; class foo {}; test<0> foo(foo); // expected-note {{candidate}} -namespace A { +namespace Test0 { class foo { int x; }; test<1> foo(class foo); - namespace B { + namespace A { test<2> foo(class ::foo); // expected-note {{candidate}} void test0() { @@ -22,7 +22,7 @@ namespace A { } void test1() { - using A::foo; + using Test0::foo; class foo a; test<1> _ = (foo)(a); @@ -37,8 +37,31 @@ namespace A { // But basic unqualified lookup is not. test<2> _1 = (foo)(a); - class A::foo b; + class Test0::foo b; test<2> _2 = (foo)(b); // expected-error {{incompatible type passing}} } } } + +namespace Test1 { + namespace A { + class a {}; + } + + namespace B { + typedef class {} b; + } + + namespace C { + int c(); // expected-note {{target of using declaration}} + } + + namespace D { + using typename A::a; + using typename B::b; + using typename C::c; // expected-error {{'typename' keyword used on a non-type}} + + a _1 = A::a(); + b _2 = B::b(); + } +} diff --git a/test/SemaCXX/using-decl-templates.cpp b/test/SemaCXX/using-decl-templates.cpp index 1a53704c1e..684009b78a 100644 --- a/test/SemaCXX/using-decl-templates.cpp +++ b/test/SemaCXX/using-decl-templates.cpp @@ -2,12 +2,12 @@ template struct A { void f() { } - struct N { }; + struct N { }; // expected-note{{target of using declaration}} }; template struct B : A { using A::f; - using A::N; + using A::N; // expected-error{{dependent using declaration resolved to type without 'typename'}} using A::foo; // expected-error{{no member named 'foo'}} using A::f; // expected-error{{using declaration refers into 'A::', which is not a base class of 'B'}}