diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-02-03 19:21:40 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-02-03 19:21:40 +0000 |
commit | 2a3009a432bdcec59e6383d7b2b17494d6f91649 (patch) | |
tree | 6f72140cec82a050b33451ebcda7f762e90234e2 | |
parent | 89c9d8e7f0700d27b1d93dc3832eb1af9b92c221 (diff) |
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
-rw-r--r-- | include/clang/AST/ASTContext.h | 13 | ||||
-rw-r--r-- | include/clang/AST/DeclBase.h | 17 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 76 | ||||
-rw-r--r-- | include/clang/AST/DeclNodes.def | 1 | ||||
-rw-r--r-- | include/clang/AST/DeclarationName.h | 9 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 4 | ||||
-rw-r--r-- | include/clang/Basic/IdentifierTable.h | 6 | ||||
-rw-r--r-- | include/clang/Parse/Scope.h | 27 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 8 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 18 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 11 | ||||
-rw-r--r-- | lib/AST/DeclSerialization.cpp | 8 | ||||
-rw-r--r-- | lib/AST/DeclarationName.cpp | 18 | ||||
-rw-r--r-- | lib/AST/StmtDumper.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 76 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 23 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 50 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 716 | ||||
-rw-r--r-- | test/SemaCXX/member-name-lookup.cpp | 14 | ||||
-rw-r--r-- | test/SemaCXX/using-directive.cpp | 74 |
20 files changed, 1023 insertions, 155 deletions
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<TagDecl>(cast<TagType>(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, udir_iterator> 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<UsingDirectiveDecl*>(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<Action::DeclTy*, 2> 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<UsingDirectiveDecl>(this)->getNominatedNamespace() == + cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace(); + } + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(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<udir_iterator>(Result.first), + reinterpret_cast<udir_iterator>(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 "<using-directive>"; } 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<uintptr_t>(&UDirExtra); + Ptr |= StoredDeclarationNameExtra; + + return DeclarationName(Ptr); +} + DeclarationNameTable::DeclarationNameTable() { CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>; 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 <cstdio> @@ -247,6 +248,14 @@ void StmtDumper::DumpDeclarator(Decl *D) { tagname = "<anonymous>"; fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname); // FIXME: print tag bodies. + } else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(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 = "<anonymous>"; + 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<uintptr_t>(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<uintptr_t>(Paths); Result.Last = DifferentSubobjectTypes? 1 : 0; Result.Context = &Context; return Result; } + template <typename Iterator> + 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<uintptr_t>(Array); + Result.Last = reinterpret_cast<uintptr_t>(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<LookupResult, 3> LookupResultsVecTy; + + std::pair<bool, LookupResult> 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<TagDecl>( - 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<NamedDecl>(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<NamedDecl>(static_cast<Decl*>(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<NamespaceDecl>(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<DeclContext>(NS); + while (CommonAncestor && !CommonAncestor->Encloses(CurContext)) + CommonAncestor = CommonAncestor->getParent(); + + UDir = UsingDirectiveDecl::Create(Context, CurContext, UsingLoc, + NamespcLoc, IdentLoc, + cast<NamespaceDecl>(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<DeclContext*>(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 <set> +#include <vector> +#include <iterator> +#include <utility> +#include <algorithm> using namespace clang; +typedef llvm::SmallVector<UsingDirectiveDecl*, 4> UsingDirectivesTy; +typedef llvm::DenseSet<NamespaceDecl*> NamespaceSet; +typedef llvm::SmallVector<Sema::LookupResult, 3> LookupResultsTy; + +/// UsingDirAncestorCompare - Implements strict weak ordering of +/// UsingDirectives. It orders them by address of its common ancestor. +str |