From: Douglas Gregor Date: Tue, 3 Feb 2009 19:21:40 +0000 (+0000) Subject: Semantic analysis, ASTs, and unqualified name lookup support for C++ X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2a3009a432bdcec59e6383d7b2b17494d6f91649;p=clang Semantic analysis, ASTs, and unqualified name lookup support for C++ using directives, from Piotr Rak! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63646 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index bf585b6d9e..bf6fa99f2c 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -452,7 +452,18 @@ public: const Type *getCanonicalType(const Type *T) { return T->getCanonicalTypeInternal().getTypePtr(); } - + + /// \brief Retrieves the "canonical" declaration of the given tag + /// declaration. + /// + /// The canonical declaration for the given tag declaration is + /// either the definition of the tag (if it is a complete type) or + /// the first declaration of that tag. + TagDecl *getCanonicalDecl(TagDecl *Tag) { + QualType T = getTagDeclType(Tag); + return cast(cast(T)->getDecl()); + } + /// Type Query functions. If the type is an instance of the specified class, /// return the Type pointer for the underlying maximally pretty type. This /// is a member of ASTContext because this may need to do some amount of diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 23bcd58a2a..3aaadedb15 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -25,6 +25,7 @@ namespace clang { class DeclContext; class TranslationUnitDecl; class NamespaceDecl; +class UsingDirectiveDecl; class NamedDecl; class FunctionDecl; class CXXRecordDecl; @@ -768,6 +769,22 @@ public: /// replaced with D. void makeDeclVisibleInContext(NamedDecl *D); + /// udir_iterator - Iterates through the using-directives stored + /// within this context. + typedef UsingDirectiveDecl * const * udir_iterator; + + typedef std::pair udir_iterator_range; + + udir_iterator_range getUsingDirectives() const; + + udir_iterator using_directives_begin() const { + return getUsingDirectives().first; + } + + udir_iterator using_directives_end() const { + return getUsingDirectives().second; + } + static bool classof(const Decl *D) { switch (D->getKind()) { #define DECL_CONTEXT(Name) case Decl::Name: diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 5d4385b994..7c248fd9e3 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -948,6 +948,82 @@ protected: void ReadInRec(llvm::Deserializer& D, ASTContext& C); }; +/// UsingDirectiveDecl - Represents C++ using-directive. For example: +/// +/// using namespace std; +/// +// NB: UsingDirectiveDecl should be Decl not NamedDecl, but we provide +// artificial name, for all using-directives in order to store +// them in DeclContext effectively. +class UsingDirectiveDecl : public NamedDecl { + + /// SourceLocation - Location of 'namespace' token. + SourceLocation NamespaceLoc; + + /// IdentLoc - Location of nominated namespace-name identifier. + // FIXME: We don't store location of scope specifier. + SourceLocation IdentLoc; + + /// NominatedNamespace - Namespace nominated by using-directive. + NamespaceDecl *NominatedNamespace; + + /// Enclosing context containing both using-directive and nomintated + /// namespace. + DeclContext *CommonAncestor; + + /// getUsingDirectiveName - Returns special DeclarationName used by + /// using-directives. This is only used by DeclContext for storing + /// UsingDirectiveDecls in its lookup structure. + static DeclarationName getName() { + return DeclarationName::getUsingDirectiveName(); + } + + UsingDirectiveDecl(DeclContext *DC, SourceLocation L, + SourceLocation NamespcLoc, + SourceLocation IdentLoc, + NamespaceDecl *Nominated, + DeclContext *CommonAncestor) + : NamedDecl(Decl::UsingDirective, DC, L, getName()), + NamespaceLoc(NamespcLoc), IdentLoc(IdentLoc), + NominatedNamespace(Nominated? Nominated->getOriginalNamespace() : 0), + CommonAncestor(CommonAncestor) { + } + +public: + /// getNominatedNamespace - Returns namespace nominated by using-directive. + NamespaceDecl *getNominatedNamespace() { return NominatedNamespace; } + + const NamespaceDecl *getNominatedNamespace() const { + return const_cast(this)->getNominatedNamespace(); + } + + /// getCommonAncestor - returns common ancestor context of using-directive, + /// and nominated by it namespace. + DeclContext *getCommonAncestor() { return CommonAncestor; } + const DeclContext *getCommonAncestor() const { return CommonAncestor; } + + /// getNamespaceKeyLocation - Returns location of namespace keyword. + SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; } + + /// getIdentLocation - Returns location of identifier. + SourceLocation getIdentLocation() const { return IdentLoc; } + + static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + SourceLocation NamespaceLoc, + SourceLocation IdentLoc, + NamespaceDecl *Nominated, + DeclContext *CommonAncestor); + + static bool classof(const Decl *D) { + return D->getKind() == Decl::UsingDirective; + } + static bool classof(const UsingDirectiveDecl *D) { return true; } + + // Friend for getUsingDirectiveName. + friend class DeclContext; +}; + /// TemplateParameterList - Stores a list of template parameters. class TemplateParameterList { /// NumParams - The number of template parameters in this template diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def index 94c40f8e73..17a8bc3835 100644 --- a/include/clang/AST/DeclNodes.def +++ b/include/clang/AST/DeclNodes.def @@ -76,6 +76,7 @@ ABSTRACT_DECL(Named, Decl) DECL(ObjCIvar, FieldDecl) DECL(ObjCAtDefsField, FieldDecl) DECL(Namespace, NamedDecl) + DECL(UsingDirective, NamedDecl) ABSTRACT_DECL(Type, NamedDecl) DECL(Typedef, TypeDecl) ABSTRACT_DECL(Tag, TypeDecl) diff --git a/include/clang/AST/DeclarationName.h b/include/clang/AST/DeclarationName.h index 8aac8ac00d..bc9f674f3c 100644 --- a/include/clang/AST/DeclarationName.h +++ b/include/clang/AST/DeclarationName.h @@ -27,6 +27,7 @@ namespace clang { class DeclarationNameExtra; class IdentifierInfo; class MultiKeywordSelector; + class UsingDirectiveDecl; /// DeclarationName - The name of a declaration. In the common case, /// this just stores an IdentifierInfo pointer to a normal @@ -45,7 +46,8 @@ public: CXXConstructorName, CXXDestructorName, CXXConversionFunctionName, - CXXOperatorName + CXXOperatorName, + CXXUsingDirective }; private: @@ -153,7 +155,12 @@ private: /// Construct a declaration name from a raw pointer. DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { } + /// getUsingDirectiveName - Return name for all using-directives. + static DeclarationName getUsingDirectiveName(); + friend class DeclarationNameTable; + friend class UsingDirectiveDecl; + friend class NamedDecl; /// getFETokenInfoAsVoid - Retrieves the front end-specified pointer /// for this name as a void pointer. diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 7f1ca49b66..54f5086a53 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -1041,6 +1041,10 @@ DIAG(err_ambiguous_member_multiple_subobject_types, ERROR, "member %0 found in multiple base classes of different types") DIAG(note_ambiguous_member_found, NOTE, "member found by ambiguous name lookup") +DIAG(err_ambiguous_reference, ERROR, + "reference to %0 is ambiguous") +DIAG(note_ambiguous_candidate, NOTE, + "candidate found by name lookup is '%0'") // C++ operator overloading DIAG(err_operator_overload_needs_class_or_enum, ERROR, diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 91a0bf2e8a..f408a038ab 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -449,6 +449,7 @@ public: #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ CXXOperator##Name, #include "clang/Basic/OperatorKinds.def" + CXXUsingDirective, NUM_EXTRA_KINDS }; @@ -456,8 +457,9 @@ public: /// operator-id (if the value is one of the CXX* enumerators of /// ExtraKind), in which case the DeclarationNameExtra is also a /// CXXSpecialName (for CXXConstructor, CXXDestructor, or - /// CXXConversionFunction) or CXXOperatorIdName, otherwise it is - /// NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of + /// CXXConversionFunction) or CXXOperatorIdName, it may be also + /// name common to C++ using-directives (CXXUsingDirective), otherwise + /// it is NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of /// arguments in the Objective-C selector, in which case the /// DeclarationNameExtra is also a MultiKeywordSelector. unsigned ExtraKindOrNumArgs; diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h index 5243ecceda..edbc52730d 100644 --- a/include/clang/Parse/Scope.h +++ b/include/clang/Parse/Scope.h @@ -122,6 +122,9 @@ private: /// maintained by the Action implementation. void *Entity; + typedef llvm::SmallVector UsingDirectivesTy; + UsingDirectivesTy UsingDirectives; + public: Scope(Scope *Parent, unsigned ScopeFlags) { Init(Parent, ScopeFlags); @@ -234,6 +237,29 @@ public: void setWithinElse(bool WE) { WithinElse = WE; } + typedef UsingDirectivesTy::iterator udir_iterator; + typedef UsingDirectivesTy::const_iterator const_udir_iterator; + + void PushUsingDirective(Action::DeclTy *UDir) { + UsingDirectives.push_back(UDir); + } + + udir_iterator using_directives_begin() { + return UsingDirectives.begin(); + } + + udir_iterator using_directives_end() { + return UsingDirectives.end(); + } + + const_udir_iterator using_directives_begin() const { + return UsingDirectives.begin(); + } + + const_udir_iterator using_directives_end() const { + return UsingDirectives.end(); + } + /// Init - This is used by the parser to implement scope caching. /// void Init(Scope *Parent, unsigned ScopeFlags) { @@ -265,6 +291,7 @@ public: if (Flags & BlockScope) BlockParent = this; if (Flags & TemplateParamScope) TemplateParamParent = this; DeclsInScope.clear(); + UsingDirectives.clear(); Entity = 0; } }; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 0a3801a78f..6bc02e0a97 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Stmt.h" #include "clang/AST/Expr.h" @@ -146,6 +147,13 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch"); + // UsingDirectiveDecl's are not really NamedDecl's, and all have same name. + // We want to keep it, unless it nominates same namespace. + if (getKind() == Decl::UsingDirective) { + return cast(this)->getNominatedNamespace() == + cast(OldD)->getNominatedNamespace(); + } + if (const FunctionDecl *FD = dyn_cast(this)) // For function declarations, we keep track of redeclarations. return FD->getPreviousDeclaration() == OldD; diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 6d0cda1fce..21e1e0ce10 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -499,8 +499,9 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { // [FirstMatch, LastMatch) contains the set of declarations that // have the same name as this declaration. Determine where the - // declaration D will be inserted into this range. - if (D->getIdentifierNamespace() == Decl::IDNS_Tag) + // declaration D will be inserted into this range. + if (D->getKind() == Decl::UsingDirective || + D->getIdentifierNamespace() == Decl::IDNS_Tag) InsertPos = LastMatch; else if (Array[LastMatch-1]->getIdentifierNamespace() == Decl::IDNS_Tag) InsertPos = LastMatch - 1; @@ -549,7 +550,9 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { } // Put this declaration into the appropriate slot. - if (D->getIdentifierNamespace() == Decl::IDNS_Tag || Pos->second.empty()) + if (D->getKind() == Decl::UsingDirective || + D->getIdentifierNamespace() == Decl::IDNS_Tag + || Pos->second.empty()) Pos->second.push_back(D); else if (Pos->second.back()->getIdentifierNamespace() == Decl::IDNS_Tag) { NamedDecl *TagD = Pos->second.back(); @@ -561,3 +564,12 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { (*Map)[D->getDeclName()].push_back(D); } } + +/// Returns iterator range [First, Last) of UsingDirectiveDecls stored within +/// this context. +DeclContext::udir_iterator_range DeclContext::getUsingDirectives() const { + lookup_const_result Result = lookup(UsingDirectiveDecl::getName()); + return udir_iterator_range(reinterpret_cast(Result.first), + reinterpret_cast(Result.second)); +} + diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 39ca878791..5e1875ab65 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -363,3 +363,14 @@ LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, LanguageIDs Lang, bool Braces) { return new (C) LinkageSpecDecl(DC, L, Lang, Braces); } + +UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + SourceLocation NamespaceLoc, + SourceLocation IdentLoc, + NamespaceDecl *Used, + DeclContext *CommonAncestor) { + return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, IdentLoc, + Used, CommonAncestor); +} + diff --git a/lib/AST/DeclSerialization.cpp b/lib/AST/DeclSerialization.cpp index 5b881f2186..a10b229fcd 100644 --- a/lib/AST/DeclSerialization.cpp +++ b/lib/AST/DeclSerialization.cpp @@ -203,6 +203,10 @@ void NamedDecl::EmitInRec(Serializer& S) const { case DeclarationName::CXXOperatorName: S.EmitInt(Name.getCXXOverloadedOperator()); break; + + case DeclarationName::CXXUsingDirective: + // No extra data to emit + break; } } @@ -242,6 +246,10 @@ void NamedDecl::ReadInRec(Deserializer& D, ASTContext& C) { Name = C.DeclarationNames.getCXXOperatorName(Op); break; } + + case DeclarationName::CXXUsingDirective: + Name = DeclarationName::getUsingDirectiveName(); + break; } } diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp index ae579c26fa..0a6adef15b 100644 --- a/lib/AST/DeclarationName.cpp +++ b/lib/AST/DeclarationName.cpp @@ -95,10 +95,13 @@ DeclarationName::NameKind DeclarationName::getNameKind() const { case DeclarationNameExtra::CXXConversionFunction: return CXXConversionFunctionName; + case DeclarationNameExtra::CXXUsingDirective: + return CXXUsingDirective; + default: // Check if we have one of the CXXOperator* enumeration values. if (getExtra()->ExtraKindOrNumArgs < - DeclarationNameExtra::NUM_EXTRA_KINDS) + DeclarationNameExtra::CXXUsingDirective) return CXXOperatorName; return ObjCMultiArgSelector; @@ -165,6 +168,8 @@ std::string DeclarationName::getAsString() const { Result += Type.getAsString(); return Result; } + case CXXUsingDirective: + return ""; } assert(false && "Unexpected declaration name kind"); @@ -246,6 +251,17 @@ void DeclarationName::setFETokenInfo(void *T) { } } +DeclarationName DeclarationName::getUsingDirectiveName() { + // Single instance of DeclarationNameExtra for using-directive + static DeclarationNameExtra UDirExtra = + { DeclarationNameExtra::CXXUsingDirective }; + + uintptr_t Ptr = reinterpret_cast(&UDirExtra); + Ptr |= StoredDeclarationNameExtra; + + return DeclarationName(Ptr); +} + DeclarationNameTable::DeclarationNameTable() { CXXSpecialNamesImpl = new llvm::FoldingSet; diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 83313ed9be..87a9f8e36b 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -14,6 +14,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Compiler.h" #include @@ -247,6 +248,14 @@ void StmtDumper::DumpDeclarator(Decl *D) { tagname = ""; fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname); // FIXME: print tag bodies. + } else if (UsingDirectiveDecl *UD = dyn_cast(D)) { + // print using-directive decl (e.g. "using namespace x;") + const char *ns; + if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier()) + ns = II->getName(); + else + ns = ""; + fprintf(F, "\"%s %s;\"",UD->getDeclKindName(), ns); } else { assert(0 && "Unexpected decl"); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index b0a0a5e9ee..0969cd0387 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -539,10 +539,6 @@ public: void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); - // FIXME: NamespaceNameOnly parameter is added temporarily - // we will need a better way to specify lookup criteria for things - // like template specializations, explicit template instantiations, etc. - Scope *getNonFieldDeclScope(Scope *S); /// \name Name lookup @@ -614,6 +610,9 @@ public: /// First is a single declaration (a Decl*), which may be NULL. SingleDecl, + /// First is a single declaration (an OverloadedFunctionDecl*). + OverloadedDeclSingleDecl, + /// [First, Last) is an iterator range represented as opaque /// pointers used to reconstruct IdentifierResolver::iterators. OverloadedDeclFromIdResolver, @@ -626,7 +625,13 @@ public: /// by the LookupResult. Last is non-zero to indicate that the /// ambiguity is caused by two names found in base class /// subobjects of different types. - AmbiguousLookup + AmbiguousLookupStoresBasePaths, + + /// [First, Last) is an iterator range represented as opaque + /// pointers used to reconstruct new'ed Decl*[] array containing + /// found ambiguous decls. LookupResult is owner of this array. + AmbiguousLookupStoresDecls + } StoredKind; /// The first lookup result, whose contents depend on the kind of @@ -635,14 +640,14 @@ public: /// IdentifierResolver::iterator (if StoredKind == /// OverloadedDeclFromIdResolver), a DeclContext::lookup_iterator /// (if StoredKind == OverloadedDeclFromDeclContext), or a - /// BasePaths pointer (if StoredKind == AmbiguousLookup). + /// BasePaths pointer (if StoredKind == AmbiguousLookupStoresBasePaths). mutable uintptr_t First; /// The last lookup result, whose contents depend on the kind of /// lookup result. This may be unused (if StoredKind == /// SingleDecl), it may have the same type as First (for /// overloaded function declarations), or is may be used as a - /// Boolean value (if StoredKind == AmbiguousLookup). + /// Boolean value (if StoredKind == AmbiguousLookupStoresBasePaths). mutable uintptr_t Last; /// Context - The context in which we will build any @@ -690,17 +695,25 @@ public: /// return d.x; // error: 'x' is found in two A subobjects (of B and C) /// } /// @endcode - AmbiguousBaseSubobjects + AmbiguousBaseSubobjects, + + /// Name lookup results in an ambiguity because multiple definitions + /// of entity that meet the lookup criteria were found in different + /// declaration contexts. + /// @code + /// namespace A { + /// int i; + /// namespace B { int i; } + /// int test() { + /// using namespace B; + /// return i; // error 'i' is found in namespace A and A::B + /// } + /// } + /// @endcode + AmbiguousReference }; - static LookupResult CreateLookupResult(ASTContext &Context, Decl *D) { - LookupResult Result; - Result.StoredKind = SingleDecl; - Result.First = reinterpret_cast(D); - Result.Last = 0; - Result.Context = &Context; - return Result; - } + static LookupResult CreateLookupResult(ASTContext &Context, Decl *D); static LookupResult CreateLookupResult(ASTContext &Context, IdentifierResolver::iterator F, @@ -713,20 +726,37 @@ public: static LookupResult CreateLookupResult(ASTContext &Context, BasePaths *Paths, bool DifferentSubobjectTypes) { LookupResult Result; - Result.StoredKind = AmbiguousLookup; + Result.StoredKind = AmbiguousLookupStoresBasePaths; Result.First = reinterpret_cast(Paths); Result.Last = DifferentSubobjectTypes? 1 : 0; Result.Context = &Context; return Result; } + template + static LookupResult CreateLookupResult(ASTContext &Context, + Iterator B, std::size_t Len) { + Decl ** Array = new Decl*[Len]; + for (std::size_t Idx = 0; Idx < Len; ++Idx, ++B) + Array[Idx] = *B; + LookupResult Result; + Result.StoredKind = AmbiguousLookupStoresDecls; + Result.First = reinterpret_cast(Array); + Result.Last = reinterpret_cast(Array + Len); + Result.Context = &Context; + return Result; + } + LookupKind getKind() const; /// @brief Determine whether name look found something. operator bool() const { return getKind() != NotFound; } /// @brief Determines whether the lookup resulted in an ambiguity. - bool isAmbiguous() const { return StoredKind == AmbiguousLookup; } + bool isAmbiguous() const { + return StoredKind == AmbiguousLookupStoresBasePaths || + StoredKind == AmbiguousLookupStoresDecls; + } /// @brief Allows conversion of a lookup result into a /// declaration, with the same behavior as getAsDecl. @@ -786,6 +816,14 @@ public: iterator end(); }; +private: + typedef llvm::SmallVector LookupResultsVecTy; + + std::pair CppLookupName(Scope *S, DeclarationName Name, + LookupNameKind NameKind, + bool RedeclarationOnly); + +public: /// Determines whether D is a suitable lookup result according to the /// lookup criteria. bool isAcceptableLookupResult(Decl *D, LookupNameKind NameKind, @@ -1171,6 +1209,8 @@ public: IdentifierInfo *NamespcName, AttributeList *AttrList); + void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); + /// AddCXXDirectInitializerToDecl - This action is called immediately after /// ActOnDeclarator, when a C++ direct initializer is present. /// e.g: "int x(1);" diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d7c5fa6860..39747b63ee 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -42,6 +42,8 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, Scope *S, // FIXME: In the event of an ambiguous lookup, we could visit all of // the entities found to determine whether they are all types. This // might provide better diagnostics. + case LookupResult::AmbiguousReference: + // FIXME: We need source location of identifier to diagnose more correctly. return 0; case LookupResult::Found: IIDecl = Result.getAsDecl(); @@ -2813,7 +2815,7 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, SearchDC = DC; // Look-up name inside 'foo::'. PrevDecl = dyn_cast_or_null( - LookupQualifiedName(DC, Name, LookupTagName).getAsDecl()); + LookupQualifiedName(DC, Name, LookupTagName, true).getAsDecl()); // A tag 'foo::bar' must already exist. if (PrevDecl == 0) { @@ -2824,8 +2826,23 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagKind TK, } else if (Name) { // If this is a named struct, check to see if there was a previous forward // declaration or definition. - Decl *D = LookupName(S, Name, LookupTagName); - PrevDecl = dyn_cast_or_null(D); + // FIXME: We're looking into outer scopes here, even when we + // shouldn't be. Doing so can result in ambiguities that we + // shouldn't be diagnosing. + LookupResult R = LookupName(S, Name, LookupTagName); + if (R.isAmbiguous()) { + DiagnoseAmbiguousLookup(R, Name, NameLoc); + // FIXME: This is not best way to recover from case like: + // + // struct S s; + // + // causes needless err_ovl_no_viable_function_in_init latter. + Name = 0; + PrevDecl = 0; + Invalid = true; + } + else + PrevDecl = dyn_cast_or_null(static_cast(R)); if (!getLangOptions().CPlusPlus && TK != TK_Reference) { // FIXME: This makes sure that we ignore the contexts associated diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 296adc1a94..201d8b3ca8 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1433,21 +1433,59 @@ Sema::DeclTy *Sema::ActOnUsingDirective(Scope *S, assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); assert(NamespcName && "Invalid NamespcName."); assert(IdentLoc.isValid() && "Invalid NamespceName location."); + assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); - // FIXME: This still requires lot more checks, and AST support. + UsingDirectiveDecl *UDir = 0; // Lookup namespace name. - Decl *NS = LookupParsedName(S, &SS, NamespcName, LookupNamespaceName, false); - - if (NS) { + LookupResult R = LookupParsedName(S, &SS, NamespcName, + LookupNamespaceName, false); + if (R.isAmbiguous()) { + DiagnoseAmbiguousLookup(R, NamespcName, IdentLoc); + return 0; + } + if (Decl *NS = R) { assert(isa(NS) && "expected namespace decl"); + // C++ [namespace.udir]p1: + // A using-directive specifies that the names in the nominated + // namespace can be used in the scope in which the + // using-directive appears after the using-directive. During + // unqualified name lookup (3.4.1), the names appear as if they + // were declared in the nearest enclosing namespace which + // contains both the using-directive and the nominated + // namespace. [Note: in this context, “contains” means “contains + // directly or indirectly”. ] + + // Find enclosing context containing both using-directive and + // nominated namespace. + DeclContext *CommonAncestor = cast(NS); + while (CommonAncestor && !CommonAncestor->Encloses(CurContext)) + CommonAncestor = CommonAncestor->getParent(); + + UDir = UsingDirectiveDecl::Create(Context, CurContext, UsingLoc, + NamespcLoc, IdentLoc, + cast(NS), + CommonAncestor); + PushUsingDirective(S, UDir); } else { Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange(); } - // FIXME: We ignore AttrList for now, and delete it to avoid leak. + // FIXME: We ignore attributes for now. delete AttrList; - return 0; + return UDir; +} + +void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { + // If scope has associated entity, then using directive is at namespace + // or translation unit scope. We add UsingDirectiveDecls, into + // it's lookup structure. + if (DeclContext *Ctx = static_cast(S->getEntity())) + Ctx->addDecl(UDir); + else + // Otherwise it is block-sope. using-directives will affect lookup + // only to the end of scope. + S->PushUsingDirective(UDir); } /// AddCXXDirectInitializerToDecl - This action is called immediately after diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index da2deec02a..39b782c016 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -21,14 +21,90 @@ #include "clang/Basic/LangOptions.h" #include "llvm/ADT/STLExtras.h" #include +#include +#include +#include +#include using namespace clang; +typedef llvm::SmallVector UsingDirectivesTy; +typedef llvm::DenseSet NamespaceSet; +typedef llvm::SmallVector LookupResultsTy; + +/// UsingDirAncestorCompare - Implements strict weak ordering of +/// UsingDirectives. It orders them by address of its common ancestor. +struct UsingDirAncestorCompare { + + /// @brief Compares UsingDirectiveDecl common ancestor with DeclContext. + bool operator () (UsingDirectiveDecl *U, const DeclContext *Ctx) const { + return U->getCommonAncestor() < Ctx; + } + + /// @brief Compares UsingDirectiveDecl common ancestor with DeclContext. + bool operator () (const DeclContext *Ctx, UsingDirectiveDecl *U) const { + return Ctx < U->getCommonAncestor(); + } + + /// @brief Compares UsingDirectiveDecl common ancestors. + bool operator () (UsingDirectiveDecl *U1, UsingDirectiveDecl *U2) const { + return U1->getCommonAncestor() < U2->getCommonAncestor(); + } +}; + +/// AddNamespaceUsingDirectives - Adds all UsingDirectiveDecl's to heap UDirs +/// (ordered by common ancestors), found in namespace NS, +/// including all found (recursively) in their nominated namespaces. +void AddNamespaceUsingDirectives(DeclContext *NS, + UsingDirectivesTy &UDirs, + NamespaceSet &Visited) { + DeclContext::udir_iterator I, End; + + for (llvm::tie(I, End) = NS->getUsingDirectives(); I !=End; ++I) { + UDirs.push_back(*I); + std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare()); + NamespaceDecl *Nominated = (*I)->getNominatedNamespace(); + if (Visited.insert(Nominated).second) + AddNamespaceUsingDirectives(Nominated, UDirs, /*ref*/ Visited); + } +} + +/// AddScopeUsingDirectives - Adds all UsingDirectiveDecl's found in Scope S, +/// including all found in the namespaces they nominate. +static void AddScopeUsingDirectives(Scope *S, UsingDirectivesTy &UDirs) { + NamespaceSet VisitedNS; + + if (DeclContext *Ctx = static_cast(S->getEntity())) { + + if (NamespaceDecl *NS = dyn_cast(Ctx)) + VisitedNS.insert(NS); + + AddNamespaceUsingDirectives(Ctx, UDirs, /*ref*/ VisitedNS); + + } else { + Scope::udir_iterator + I = S->using_directives_begin(), + End = S->using_directives_end(); + + for (; I != End; ++I) { + UsingDirectiveDecl * UD = static_cast(*I); + UDirs.push_back(UD); + std::push_heap(UDirs.begin(), UDirs.end(), UsingDirAncestorCompare()); + + NamespaceDecl *Nominated = UD->getNominatedNamespace(); + if (!VisitedNS.count(Nominated)) { + VisitedNS.insert(Nominated); + AddNamespaceUsingDirectives(Nominated, UDirs, /*ref*/ VisitedNS); + } + } + } +} + /// MaybeConstructOverloadSet - Name lookup has determined that the /// elements in [I, IEnd) have the name that we are looking for, and /// *I is a match for the namespace. This routine returns an /// appropriate Decl for name lookup, which may either be *I or an -/// OverloadeFunctionDecl that represents the overloaded functions in +/// OverloadedFunctionDecl that represents the overloaded functions in /// [I, IEnd). /// /// The existance of this routine is temporary; users of LookupResult @@ -69,6 +145,236 @@ MaybeConstructOverloadSet(ASTContext &Context, return *I; } +/// Merges together multiple LookupResults dealing with duplicated Decl's. +static Sema::LookupResult +MergeLookupResults(ASTContext &Context, LookupResultsTy &Results) { + typedef Sema::LookupResult LResult; + typedef llvm::SmallVector DeclsVecTy; + + DeclsVecTy FoundDecls; + OverloadedFunctionDecl *FoundOverloaded = 0; + + LookupResultsTy::iterator I = Results.begin(), End = Results.end(); + for (; I != End; ++I) { + + switch (I->getKind()) { + case LResult::NotFound: + assert(false && + "Should be always successful name lookup result here."); + break; + + case LResult::AmbiguousReference: + assert(false && + "Shouldn't get ambiguous reference here."); + break; + + case LResult::Found: + FoundDecls.push_back(cast(I->getAsDecl())); + break; + + case LResult::AmbiguousBaseSubobjectTypes: + case LResult::AmbiguousBaseSubobjects: { + LResult Ambig = *I; + // Free rest of OverloadedFunctionDecl, and other BasePaths + // stored in LookupResults. +#if 0 + // FIXME: + // It should not happen, when we look start in each DeclContext only once. + // See FIXME in CppLookupName. + assert(Results.size() == 1 && "Multiple LookupResults should be not case " + "here, since using-directives can't occur at class scope."); +#else + if (FoundOverloaded) + FoundOverloaded->Destroy(Context); + + for (++I; I != End; ++I) { + if (I->getKind() == LResult::FoundOverloaded) + cast(I->getAsDecl())->Destroy(Context); + else if (BasePaths *Paths = I->getBasePaths()) + delete Paths; + assert(I->getKind() != LResult::AmbiguousReference && + "Shouldn't get ambiguous reference here."); + } +#endif + return Ambig; + } + + case LResult::FoundOverloaded: + if (FoundOverloaded) { + // We have one spare OverloadedFunctionDecl already, so we store + // its function decls. +#if 0 + FIXME: As soon as, stop call MaybeConstructOverloadSet here, + which requires iterator::reference of type NamedDecl*, FoundDecls + can be SmallVector + or when Lookup*Name() starts return NamedDecl's* instead of Decl's + + this will work: + std::copy(I->begin(), I->end(), std::back_inserter(FoundDecls)); +#else + Sema::LookupResult::iterator OI = I->begin(), OEnd = I->end(); + for (; OI != OEnd; ++OI) + FoundDecls.push_back(cast(*OI)); +#endif + } else { + // First time we found OverloadedFunctionDecl, we want to conserve + // it, and possibly add other found Decls later. + FoundOverloaded = cast(I->getAsDecl()); + } + break; + } + } + + // Remove duplicated Decl pointing at same Decl, this might be case + // for code like: + // + // namespace A { int i; } + // namespace B { using namespace A; } + // namespace C { using namespace A; } + // + // void foo() { + // using namespace B; + // using namespace C; + // ++i; // finds A::i, from both namespace B and C at global scope + // } + // + // C++ [namespace.qual].p3: + // The same declaration found more than once is not an ambiguity + // (because it is still a unique declaration). + // + // FIXME: At this point happens too, because we are doing redundant lookups. + // + DeclsVecTy::iterator DI = FoundDecls.begin(), DEnd = FoundDecls.end(); + // FIXME: Using SmallPtrSet instead would be better, once OverloadedFunctionDecl + // dies. + std::sort(DI, DEnd); + DEnd = std::unique(DI, DEnd); + + if (FoundOverloaded) { + // We found overloaded functions result. We want to add any other + // found decls, that are not already in FoundOverloaded, and are functions + // or methods. + OverloadedFunctionDecl::function_iterator + FBegin = FoundOverloaded->function_begin(), + FEnd = FoundOverloaded->function_end(); + // FIXME: This is O(n^2)! + for (DI ; DI < DEnd; ++DI) { + FunctionDecl *Fun = dyn_cast(*DI); + if (Fun && (std::find(FBegin, FEnd, Fun) != FEnd)) { /* Skip.*/ } + else DEnd = std::remove(DI, DEnd, *DI); + } + + for (DI = FoundDecls.begin(); DI != DEnd; ++DI) + FoundOverloaded->addOverload(cast(*DI)); + + return LResult::CreateLookupResult(Context, FoundOverloaded); + } else if (std::size_t FoundLen = std::distance(FoundDecls.begin(), DEnd)) { + // We might found multiple TagDecls pointing at same definition. + if (TagDecl *R = dyn_cast(*FoundDecls.begin())) { + TagDecl *Canonical = Context.getCanonicalDecl(R); + DeclsVecTy::iterator RI = FoundDecls.begin(), REnd = DEnd; + for (;;) { + ++RI; + if (RI == REnd) { + FoundLen = 1; + break; + } + R = dyn_cast(*RI); + if (R && Canonical == Context.getCanonicalDecl(R)) { /* Skip */} + else break; + } + } + + // We might find FunctionDecls in two (or more) distinct DeclContexts. + // 3.4.1.p1 ... Name lookup may associate more than one declaration with + // a name if it finds the name to be a function name; the declarations + // are said to form a set of overloaded functions (13.1). + // Overload resolution (13.3) takes place after name lookup has succeeded. + + Decl *D = MaybeConstructOverloadSet(Context, DI, DEnd); + if ((FoundLen == 1) || isa(D)) + return LResult::CreateLookupResult(Context, D); + + // Found multiple Decls, it is ambiguous reference. + return LResult::CreateLookupResult(Context, FoundDecls.begin(), FoundLen); + } + + LResult Result = LResult::CreateLookupResult(Context, 0); + return Result; +} + +// Retrieve the set of identifier namespaces that correspond to a +// specific kind of name lookup. +inline unsigned +getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, + bool CPlusPlus) { + unsigned IDNS = 0; + switch (NameKind) { + case Sema::LookupOrdinaryName: + IDNS = Decl::IDNS_Ordinary; + if (CPlusPlus) + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member; + break; + + case Sema::LookupTagName: + IDNS = Decl::IDNS_Tag; + break; + + case Sema::LookupMemberName: + IDNS = Decl::IDNS_Member; + if (CPlusPlus) + IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary; + break; + + case Sema::LookupNestedNameSpecifierName: + case Sema::LookupNamespaceName: + IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member; + break; + } + return IDNS; +} + +// Return qualified name for Decl D, like A::B::i, for i being member of +// namespace A::B. +std::string +getQualifiedName(Decl *D) { + std::vector Names; + std::string QualName; + DeclContext *Ctx = D->getDeclContext(); + + if (Ctx->isFunctionOrMethod()) + return cast(D)->getNameAsString(); + + while (Ctx) { + if (Ctx->isFunctionOrMethod()) { + // FIXME: That probably is happend, because D was member of local + // scope class/struct/union. How do we handle this case? + break; + } + if (NamedDecl *ND = dyn_cast(Ctx)) { + Names.push_back(ND->getNameAsString()); + } else { + break; + } + Ctx = Ctx->getParent(); + } + for (std::vector::reverse_iterator I= Names.rbegin(), End =Names.rend(); I!=End; ++I) + QualName += *I + "::"; + QualName += cast(D)->getNameAsString(); + return QualName; +} + +Sema::LookupResult +Sema::LookupResult::CreateLookupResult(ASTContext &Context, Decl *D) { + LookupResult Result; + Result.StoredKind = (D && isa(D))? + OverloadedDeclSingleDecl : SingleDecl; + Result.First = reinterpret_cast(D); + Result.Last = 0; + Result.Context = &Context; + return Result; +} + /// @brief Moves the name-lookup results from Other to this LookupResult. Sema::LookupResult Sema::LookupResult::CreateLookupResult(ASTContext &Context, @@ -124,12 +430,16 @@ Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const { case SingleDecl: return (reinterpret_cast(First) != 0)? Found : NotFound; + case OverloadedDeclSingleDecl: case OverloadedDeclFromIdResolver: case OverloadedDeclFromDeclContext: return FoundOverloaded; - case AmbiguousLookup: + case AmbiguousLookupStoresBasePaths: return Last? AmbiguousBaseSubobjectTypes : AmbiguousBaseSubobjects; + + case AmbiguousLookupStoresDecls: + return AmbiguousReference; } // We can't ever get here. @@ -164,7 +474,11 @@ Decl *Sema::LookupResult::getAsDecl() const { reinterpret_cast(First), reinterpret_cast(Last)); - case AmbiguousLookup: + case OverloadedDeclSingleDecl: + return reinterpret_cast(First); + + case AmbiguousLookupStoresDecls: + case AmbiguousLookupStoresBasePaths: assert(false && "Name lookup returned an ambiguity that could not be handled"); break; @@ -174,11 +488,11 @@ Decl *Sema::LookupResult::getAsDecl() const { } /// @brief Retrieves the BasePaths structure describing an ambiguous -/// name lookup. +/// name lookup, or null. BasePaths *Sema::LookupResult::getBasePaths() const { - assert((StoredKind == AmbiguousLookup) && - "getBasePaths can only be used on an ambiguous lookup"); - return reinterpret_cast(First); + if (StoredKind == AmbiguousLookupStoresBasePaths) + return reinterpret_cast(First); + return 0; } Sema::LookupResult::iterator::reference @@ -187,13 +501,17 @@ Sema::LookupResult::iterator::operator*() const { case SingleDecl: return reinterpret_cast(Current); + case OverloadedDeclSingleDecl: + return *reinterpret_cast(Current); + case OverloadedDeclFromIdResolver: return *IdentifierResolver::iterator::getFromOpaqueValue(Current); case OverloadedDeclFromDeclContext: return *reinterpret_cast(Current); - - case AmbiguousLookup: + + case AmbiguousLookupStoresDecls: + case AmbiguousLookupStoresBasePaths: assert(false && "Cannot look into ambiguous lookup results"); break; } @@ -207,6 +525,12 @@ Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() { Current = reinterpret_cast((Decl*)0); break; + case OverloadedDeclSingleDecl: { + Decl ** I = reinterpret_cast(Current); + ++I; + Current = reinterpret_cast(I); + } + case OverloadedDeclFromIdResolver: { IdentifierResolver::iterator I = IdentifierResolver::iterator::getFromOpaqueValue(Current); @@ -223,7 +547,8 @@ Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() { break; } - case AmbiguousLookup: + case AmbiguousLookupStoresDecls: + case AmbiguousLookupStoresBasePaths: assert(false && "Cannot look into ambiguous lookup results"); break; } @@ -232,44 +557,228 @@ Sema::LookupResult::iterator& Sema::LookupResult::iterator::operator++() { } Sema::LookupResult::iterator Sema::LookupResult::begin() { - assert(StoredKind != AmbiguousLookup && "Lookup into an ambiguous result"); - return iterator(this, First); + assert(!isAmbiguous() && "Lookup into an ambiguous result"); + if (StoredKind != OverloadedDeclSingleDecl) + return iterator(this, First); + OverloadedFunctionDecl * Ovl = + reinterpret_cast(First); + return iterator(this, reinterpret_cast(&(*Ovl->function_begin()))); } Sema::LookupResult::iterator Sema::LookupResult::end() { - assert(StoredKind != AmbiguousLookup && "Lookup into an ambiguous result"); - return iterator(this, Last); + assert(!isAmbiguous() && "Lookup into an ambiguous result"); + if (StoredKind != OverloadedDeclSingleDecl) + return iterator(this, Last); + OverloadedFunctionDecl * Ovl = + reinterpret_cast(First); + return iterator(this, reinterpret_cast(&(*Ovl->function_end()))); } -// Retrieve the set of identifier namespaces that correspond to a -// specific kind of name lookup. -inline unsigned -getIdentifierNamespacesFromLookupNameKind(Sema::LookupNameKind NameKind, - bool CPlusPlus) { - unsigned IDNS = 0; - switch (NameKind) { - case Sema::LookupOrdinaryName: - IDNS = Decl::IDNS_Ordinary; - if (CPlusPlus) - IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member; - break; +static bool isFunctionLocalScope(Scope *S) { + if (DeclContext *Ctx = static_cast(S->getEntity())) + return Ctx->isFunctionOrMethod(); + return true; +} - case Sema::LookupTagName: - IDNS = Decl::IDNS_Tag; - break; +std::pair +Sema::CppLookupName(Scope *S, DeclarationName Name, + LookupNameKind NameKind, bool RedeclarationOnly) { + assert(getLangOptions().CPlusPlus && + "Can perform only C++ lookup"); +unsigned IDNS + = getIdentifierNamespacesFromLookupNameKind(NameKind, /*CPlusPlus*/ true); + Scope *Initial = S; + IdentifierResolver::iterator + I = IdResolver.begin(Name), + IEnd = IdResolver.end(); + + // First we lookup local scope. + // We don't consider using-dirctives, as per 7.3.4.p1 [namespace.udir] + // ...During unqualified name lookup (3.4.1), the names appear as if + // they were declared in the nearest enclosing namespace which contains + // both the using-directive and the nominated namespace. + // [Note: in this context, “contains” means “contains directly or + // indirectly”. + // + // For example: + // namespace A { int i; } + // void foo() { + // int i; + // { + // using namespace A; + // ++i; // finds local 'i', A::i appears at global scope + // } + // } + // + for (; S && isFunctionLocalScope(S); S = S->getParent()) { + // Check whether the IdResolver has anything in this scope. + for (; I != IEnd && S->isDeclScope(*I); ++I) { + if (isAcceptableLookupResult(*I, NameKind, IDNS)) { + // We found something. Look for anything else in our scope + // with this same name and in an acceptable identifier + // namespace, so that we can construct an overload set if we + // need to. + IdentifierResolver::iterator LastI = I; + for (++LastI; LastI != IEnd; ++LastI) { + if (!S->isDeclScope(*LastI)) + break; + } + LookupResult Result = + LookupResult::CreateLookupResult(Context, I, LastI); + return std::make_pair(true, Result); + } + } + // NB: Icky, we need to look in function scope, but we need to check its + // parent DeclContext (instead S->getParent()) for member name lookup, + // in case it is out of line method definition. Like in: + // + // class C { + // int i; + // void foo(); + // }; + // + // C::foo() { + // (void) i; + // } + // + // FIXME: Maybe we should do member name lookup here instead? + if (S->getEntity() && isFunctionLocalScope(S)) + break; + } - case Sema::LookupMemberName: - IDNS = Decl::IDNS_Member; - if (CPlusPlus) - IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary; - break; + // Collect UsingDirectiveDecls in all scopes, and recursivly all + // nominated namespaces by those using-directives. + // UsingDirectives are pushed to heap, in common ancestor pointer + // value order. + // FIXME: Cache this sorted list in Scope structure, and maybe + // DeclContext, so we don't build it for each lookup! + UsingDirectivesTy UDirs; + for (Scope *SC = Initial; SC; SC = SC->getParent()) + AddScopeUsingDirectives(SC, UDirs); + + // Sort heapified UsingDirectiveDecls. + std::sort_heap(UDirs.begin(), UDirs.end()); + + // Lookup namespace scope, global scope, or possibly (CXX)Record DeclContext + // for member name lookup. + // Unqualified name lookup in C++ requires looking into scopes + // that aren't strictly lexical, and therefore we walk through the + // context as well as walking through the scopes. + for (; S; S = S->getParent()) { + LookupResultsTy LookupResults; + bool LookedInCtx = false; + + // Check whether the IdResolver has anything in this scope. + for (; I != IEnd && S->isDeclScope(*I); ++I) { + if (isAcceptableLookupResult(*I, NameKind, IDNS)) { + // We found something. Look for anything else in our scope + // with this same name and in an acceptable identifier + // namespace, so that we can construct an overload set if we + // need to. + IdentifierResolver::iterator LastI = I; + for (++LastI; LastI != IEnd; ++LastI) { + if (!S->isDeclScope(*LastI)) + break; + } + + // We store name lookup result, and continue trying to look into + // associated context, and maybe namespaces nominated by + // using-directives. + LookupResults.push_back( + LookupResult::CreateLookupResult(Context, I, LastI)); + break; + } + } - case Sema::LookupNestedNameSpecifierName: - case Sema::LookupNamespaceName: - IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member; - break; + // If there is an entity associated with this scope, it's a + // DeclContext. We might need to perform qualified lookup into + // it, or namespaces nominated by using-directives. + DeclContext *Ctx = static_cast(S->getEntity()); + + if (Ctx && isa(Ctx)) { + UsingDirectivesTy::const_iterator UI, UEnd; + // For each UsingDirectiveDecl, which common ancestor is equal + // to Ctx, we preform qualified name lookup into namespace nominated + // by it. + llvm::tie(UI, UEnd) = + std::equal_range(UDirs.begin(), UDirs.end(), Ctx, + UsingDirAncestorCompare()); + for (; UI != UEnd; ++UI) { + // FIXME: We will have to ensure, that we won't consider + // again using-directives during qualified name lookup! + // (Once using-directives support for qualified name lookup gets + // implemented). + if (LookupResult R = LookupQualifiedName((*UI)->getNominatedNamespace(), + Name, NameKind, RedeclarationOnly)) + LookupResults.push_back(R); + } + LookupResult Result; + if ((Result = MergeLookupResults(Context, LookupResults)) || + RedeclarationOnly) { + return std::make_pair(true, Result); + } + } + + // FIXME: We're performing redundant lookups here, where the + // scope stack mirrors the semantic nested of classes and + // namespaces. We can save some work by checking the lexical + // scope against the semantic scope and avoiding any lookups + // when they are the same. + // FIXME: In some cases, we know that every name that could be + // found by this qualified name lookup will also be on the + // identifier chain. For example, inside a class without any + // base classes, we never need to perform qualified lookup + // because all of the members are on top of the identifier + // chain. However, we cannot perform this optimization when the + // lexical and semantic scopes don't line up, e.g., in an + // out-of-line member definition. + while (Ctx && Ctx->isFunctionOrMethod()) + Ctx = Ctx->getParent(); + while (Ctx && (Ctx->isNamespace() || Ctx->isRecord())) { + LookedInCtx = true; + // Look for declarations of this name in this scope. + if (LookupResult R = LookupQualifiedName(Ctx, Name, NameKind, + RedeclarationOnly)) + // We store that, to investigate futher, wheather reference + // to this Decl is no ambiguous. + LookupResults.push_back(R); + + if (Ctx->isNamespace()) { + // For each UsingDirectiveDecl, which common ancestor is equal + // to Ctx, we preform qualified name lookup into namespace nominated + // by it. + UsingDirectivesTy::const_iterator UI, UEnd; + llvm::tie(UI, UEnd) = + std::equal_range(UDirs.begin(), UDirs.end(), Ctx, + UsingDirAncestorCompare()); + for (; UI != UEnd; ++UI) { + // FIXME: We will have to ensure, that we won't consider + // again using-directives during qualified name lookup! + // (Once using-directives support for qualified name lookup gets + // implemented). + LookupResult R = LookupQualifiedName((*UI)->getNominatedNamespace(), + Name, NameKind, + RedeclarationOnly); + if (R) + LookupResults.push_back(R); + } + } + LookupResult Result; + if ((Result = MergeLookupResults(Context, LookupResults)) || + (RedeclarationOnly && !Ctx->isTransparentContext())) { + return std::make_pair(true, Result); + } + Ctx = Ctx->getParent(); + } + + if (!(LookedInCtx || LookupResults.empty())) { + // We didn't Performed lookup in Scope entity, so we return + // result form IdentifierResolver. + assert((LookupResults.size() == 1) && "Wrong size!"); + return std::make_pair(true, LookupResults.front()); + } } - return IDNS; + return std::make_pair(false, LookupResult()); } /// @brief Perform unqualified name lookup starting from a given @@ -346,65 +855,11 @@ Sema::LookupName(Scope *S, DeclarationName Name, LookupNameKind NameKind, if ((*I)->isInIdentifierNamespace(IDNS)) return LookupResult::CreateLookupResult(Context, *I); } else { - unsigned IDNS - = getIdentifierNamespacesFromLookupNameKind(NameKind, - getLangOptions().CPlusPlus); - - // Unqualified name lookup in C++ requires looking into scopes - // that aren't strictly lexical, and therefore we walk through the - // context as well as walking through the scopes. - - // FIXME: does "true" for LookInParentCtx actually make sense? - IdentifierResolver::iterator I = IdResolver.begin(Name), - IEnd = IdResolver.end(); - for (; S; S = S->getParent()) { - // Check whether the IdResolver has anything in this scope. - for (; I != IEnd && S->isDeclScope(*I); ++I) { - if (isAcceptableLookupResult(*I, NameKind, IDNS)) { - // We found something. Look for anything else in our scope - // with this same name and in an acceptable identifier - // namespace, so that we can construct an overload set if we - // need to. - IdentifierResolver::iterator LastI = I; - for (++LastI; LastI != IEnd; ++LastI) { - if (!S->isDeclScope(*LastI)) - break; - } - return LookupResult::CreateLookupResult(Context, I, LastI); - } - } - - // If there is an entity associated with this scope, it's a - // DeclContext. We might need to perform qualified lookup into - // it. - // FIXME: We're performing redundant lookups here, where the - // scope stack mirrors the semantic nested of classes and - // namespaces. We can save some work by checking the lexical - // scope against the semantic scope and avoiding any lookups - // when they are the same. - // FIXME: In some cases, we know that every name that could be - // found by this qualified name lookup will also be on the - // identifier chain. For example, inside a class without any - // base classes, we never need to perform qualified lookup - // because all of the members are on top of the identifier - // chain. However, we cannot perform this optimization when the - // lexical and semantic scopes don't line up, e.g., in an - // out-of-line member definition. - DeclContext *Ctx = static_cast(S->getEntity()); - while (Ctx && Ctx->isFunctionOrMethod()) - Ctx = Ctx->getParent(); - while (Ctx && (Ctx->isNamespace() || Ctx->isRecord())) { - // Look for declarations of this name in this scope. - if (LookupResult Result = LookupQualifiedName(Ctx, Name, NameKind, - RedeclarationOnly)) - return Result; - - if (RedeclarationOnly && !Ctx->isTransparentContext()) - return LookupResult::CreateLookupResult(Context, 0); - - Ctx = Ctx->getParent(); - } - } + // Perform C++ unqualified name lookup. + std::pair MaybeResult = + CppLookupName(S, Name, NameKind, RedeclarationOnly); + if (MaybeResult.first) + return MaybeResult.second; } // If we didn't find a use of this identifier, and if the identifier @@ -612,6 +1067,7 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS, return LookupName(S, Name, NameKind, RedeclarationOnly); } + /// @brief Produce a diagnostic describing the ambiguity that resulted /// from name lookup. /// @@ -633,37 +1089,57 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name, SourceRange LookupRange) { assert(Result.isAmbiguous() && "Lookup result must be ambiguous"); - BasePaths *Paths = Result.getBasePaths(); - if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) { - QualType SubobjectType = Paths->front().back().Base->getType(); - Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects) - << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths) - << LookupRange; + if (BasePaths *Paths = Result.getBasePaths()) + { + if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) { + QualType SubobjectType = Paths->front().back().Base->getType(); + Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects) + << Name << SubobjectType << getAmbiguousPathsDisplayString(*Paths) + << LookupRange; - DeclContext::lookup_iterator Found = Paths->front().Decls.first; - while (isa(*Found) && cast(*Found)->isStatic()) - ++Found; + DeclContext::lookup_iterator Found = Paths->front().Decls.first; + while (isa(*Found) && cast(*Found)->isStatic()) + ++Found; - Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); + Diag((*Found)->getLocation(), diag::note_ambiguous_member_found); + return true; + } + + assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes && + "Unhandled form of name lookup ambiguity"); + + Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types) + << Name << LookupRange; + + std::set DeclsPrinted; + for (BasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end(); + Path != PathEnd; ++Path) { + Decl *D = *Path->Decls.first; + if (DeclsPrinted.insert(D).second) + Diag(D->getLocation(), diag::note_ambiguous_member_found); + } + + delete Paths; return true; - } + } else if (Result.getKind() == LookupResult::AmbiguousReference) { - assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes && - "Unhandled form of name lookup ambiguity"); + Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange; - Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types) - << Name << LookupRange; + Decl **DI = reinterpret_cast(Result.First), + **DEnd = reinterpret_cast(Result.Last); - std::set DeclsPrinted; - for (BasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end(); - Path != PathEnd; ++Path) { - Decl *D = *Path->Decls.first; - if (DeclsPrinted.insert(D).second) - Diag(D->getLocation(), diag::note_ambiguous_member_found); + for (DI; DI != DEnd; ++DI) + Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) + << getQualifiedName(*DI); + + delete[] reinterpret_cast(Result.First); + + return true; } - delete Paths; + assert(false && "Unhandled form of name lookup ambiguity"); + // We can't reach here. return true; } diff --git a/test/SemaCXX/member-name-lookup.cpp b/test/SemaCXX/member-name-lookup.cpp index 4752f57aca..a19161203e 100644 --- a/test/SemaCXX/member-name-lookup.cpp +++ b/test/SemaCXX/member-name-lookup.cpp @@ -130,3 +130,17 @@ void G::test_virtual_lookup() { a; // expected-error{{non-static member 'a' found in multiple base-class subobjects of type 'struct A'}} static_f(0); // okay } + + +struct HasMemberType1 { + struct type { }; +}; + +struct HasMemberType2 { + struct type { }; +}; + +struct HasAnotherMemberType : HasMemberType1, HasMemberType2 { + // FIXME: this is well-formed, but we diagnose an ambiguity here + // struct type { }; +}; diff --git a/test/SemaCXX/using-directive.cpp b/test/SemaCXX/using-directive.cpp new file mode 100644 index 0000000000..f00209863d --- /dev/null +++ b/test/SemaCXX/using-directive.cpp @@ -0,0 +1,74 @@ +// RUN: clang -fsyntax-only -verify %s + +namespace A { + short i; // expected-note{{candidate found by name lookup is 'A::i'}} + namespace B { + long i; // expected-note{{candidate found by name lookup is 'A::B::i'}} + void f() {} // expected-note{{candidate function}} + int k; + namespace E {} // \ + expected-note{{candidate found by name lookup is 'A::B::E'}} + } + + namespace E {} // expected-note{{candidate found by name lookup is 'A::E'}} + + namespace C { + using namespace B; + namespace E {} // \ + expected-note{{candidate found by name lookup is 'A::C::E'}} + } + + void f() {} // expected-note{{candidate function}} + + class K1 { + void foo(); + }; + + void local_i() { + char i; + using namespace A; + using namespace B; + int a[sizeof(i) == sizeof(char)? 1 : -1]; // okay + } + namespace B { + int j; + } + + void ambig_i() { + using namespace A; + using namespace A::B; + (void) i; // expected-error{{reference to 'i' is ambiguous}} + f(); // expected-error{{call to 'f' is ambiguous}} + (void) j; // okay + using namespace C; + (void) k; // okay + using namespace E; // expected-error{{reference to 'E' is ambiguous}} + } + + struct K2 {}; // expected-note{{candidate found by name lookup is 'A::K2'}} +} + +struct K2 {}; // expected-note{{candidate found by name lookup is 'K2'}} + +using namespace A; + +void K1::foo() {} // okay + +// FIXME: Do we want err_ovl_no_viable_function_in_init here? +struct K2 k2; // expected-error{{reference to 'K2' is ambiguous}} \ + expected-error{{no matching constructor}} + +// FIXME: This case is incorrectly diagnosed! +//K2 k3; + + +class X { + // FIXME: produce a suitable error message for this + using namespace A; // expected-error{{expected unqualified-id}} +}; + +namespace N { + // FIXME: both of these should work, but they currently cause an ambiguity. + // struct K2; + // struct K2 { }; +}