[cfe-commits] r63646 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Parse/ lib/AST/ lib/Sema/ test/SemaCXX/
Douglas Gregor
dgregor at apple.com
Tue Feb 3 11:21:41 PST 2009
Author: dgregor
Date: Tue Feb 3 13:21:40 2009
New Revision: 63646
URL: http://llvm.org/viewvc/llvm-project?rev=63646&view=rev
Log:
Semantic analysis, ASTs, and unqualified name lookup support for C++
using directives, from Piotr Rak!
Added:
cfe/trunk/test/SemaCXX/using-directive.cpp
Modified:
cfe/trunk/include/clang/AST/ASTContext.h
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/AST/DeclNodes.def
cfe/trunk/include/clang/AST/DeclarationName.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
cfe/trunk/include/clang/Basic/IdentifierTable.h
cfe/trunk/include/clang/Parse/Scope.h
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/AST/DeclBase.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/AST/DeclSerialization.cpp
cfe/trunk/lib/AST/DeclarationName.cpp
cfe/trunk/lib/AST/StmtDumper.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/test/SemaCXX/member-name-lookup.cpp
Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Tue Feb 3 13:21:40 2009
@@ -452,7 +452,18 @@
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
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Tue Feb 3 13:21:40 2009
@@ -25,6 +25,7 @@
class DeclContext;
class TranslationUnitDecl;
class NamespaceDecl;
+class UsingDirectiveDecl;
class NamedDecl;
class FunctionDecl;
class CXXRecordDecl;
@@ -768,6 +769,22 @@
/// 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:
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Feb 3 13:21:40 2009
@@ -948,6 +948,82 @@
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
Modified: cfe/trunk/include/clang/AST/DeclNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclNodes.def?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclNodes.def (original)
+++ cfe/trunk/include/clang/AST/DeclNodes.def Tue Feb 3 13:21:40 2009
@@ -76,6 +76,7 @@
DECL(ObjCIvar, FieldDecl)
DECL(ObjCAtDefsField, FieldDecl)
DECL(Namespace, NamedDecl)
+ DECL(UsingDirective, NamedDecl)
ABSTRACT_DECL(Type, NamedDecl)
DECL(Typedef, TypeDecl)
ABSTRACT_DECL(Tag, TypeDecl)
Modified: cfe/trunk/include/clang/AST/DeclarationName.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclarationName.h?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclarationName.h (original)
+++ cfe/trunk/include/clang/AST/DeclarationName.h Tue Feb 3 13:21:40 2009
@@ -27,6 +27,7 @@
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 @@
CXXConstructorName,
CXXDestructorName,
CXXConversionFunctionName,
- CXXOperatorName
+ CXXOperatorName,
+ CXXUsingDirective
};
private:
@@ -153,7 +155,12 @@
/// 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.
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.def Tue Feb 3 13:21:40 2009
@@ -1041,6 +1041,10 @@
"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,
Modified: cfe/trunk/include/clang/Basic/IdentifierTable.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/IdentifierTable.h?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/IdentifierTable.h (original)
+++ cfe/trunk/include/clang/Basic/IdentifierTable.h Tue Feb 3 13:21:40 2009
@@ -449,6 +449,7 @@
#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
CXXOperator##Name,
#include "clang/Basic/OperatorKinds.def"
+ CXXUsingDirective,
NUM_EXTRA_KINDS
};
@@ -456,8 +457,9 @@
/// 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;
Modified: cfe/trunk/include/clang/Parse/Scope.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Scope.h?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Scope.h (original)
+++ cfe/trunk/include/clang/Parse/Scope.h Tue Feb 3 13:21:40 2009
@@ -122,6 +122,9 @@
/// 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 @@
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 @@
if (Flags & BlockScope) BlockParent = this;
if (Flags & TemplateParamScope) TemplateParamParent = this;
DeclsInScope.clear();
+ UsingDirectives.clear();
Entity = 0;
}
};
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Tue Feb 3 13:21:40 2009
@@ -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 @@
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;
Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Tue Feb 3 13:21:40 2009
@@ -499,8 +499,9 @@
// [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 @@
}
// 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 @@
(*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));
+}
+
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Tue Feb 3 13:21:40 2009
@@ -363,3 +363,14 @@
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);
+}
+
Modified: cfe/trunk/lib/AST/DeclSerialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclSerialization.cpp?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclSerialization.cpp (original)
+++ cfe/trunk/lib/AST/DeclSerialization.cpp Tue Feb 3 13:21:40 2009
@@ -203,6 +203,10 @@
case DeclarationName::CXXOperatorName:
S.EmitInt(Name.getCXXOverloadedOperator());
break;
+
+ case DeclarationName::CXXUsingDirective:
+ // No extra data to emit
+ break;
}
}
@@ -242,6 +246,10 @@
Name = C.DeclarationNames.getCXXOperatorName(Op);
break;
}
+
+ case DeclarationName::CXXUsingDirective:
+ Name = DeclarationName::getUsingDirectiveName();
+ break;
}
}
Modified: cfe/trunk/lib/AST/DeclarationName.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclarationName.cpp?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclarationName.cpp (original)
+++ cfe/trunk/lib/AST/DeclarationName.cpp Tue Feb 3 13:21:40 2009
@@ -95,10 +95,13 @@
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 @@
Result += Type.getAsString();
return Result;
}
+ case CXXUsingDirective:
+ return "<using-directive>";
}
assert(false && "Unexpected declaration name kind");
@@ -246,6 +251,17 @@
}
}
+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>;
Modified: cfe/trunk/lib/AST/StmtDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtDumper.cpp?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtDumper.cpp (original)
+++ cfe/trunk/lib/AST/StmtDumper.cpp Tue Feb 3 13:21:40 2009
@@ -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 @@
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");
}
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Feb 3 13:21:40 2009
@@ -539,10 +539,6 @@
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 @@
/// 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 @@
/// 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 @@
/// 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 @@
/// 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 @@
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 @@
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 @@
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);"
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Feb 3 13:21:40 2009
@@ -42,6 +42,8 @@
// 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 @@
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 @@
} 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
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Feb 3 13:21:40 2009
@@ -1433,21 +1433,59 @@
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
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Tue Feb 3 13:21:40 2009
@@ -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.
+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<DeclContext*>(S->getEntity())) {
+
+ if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(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<UsingDirectiveDecl*>(*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 @@
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<NamedDecl*, 3> 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<NamedDecl>(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<OverloadedFunctionDecl>(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<Decl*, >
+ 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<NamedDecl>(*OI));
+#endif
+ } else {
+ // First time we found OverloadedFunctionDecl, we want to conserve
+ // it, and possibly add other found Decls later.
+ FoundOverloaded = cast<OverloadedFunctionDecl>(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<FunctionDecl>(*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<FunctionDecl>(*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<TagDecl>(*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<TagDecl>(*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<OverloadedFunctionDecl>(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<std::string> Names;
+ std::string QualName;
+ DeclContext *Ctx = D->getDeclContext();
+
+ if (Ctx->isFunctionOrMethod())
+ return cast<NamedDecl>(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<NamedDecl>(Ctx)) {
+ Names.push_back(ND->getNameAsString());
+ } else {
+ break;
+ }
+ Ctx = Ctx->getParent();
+ }
+ for (std::vector<std::string>::reverse_iterator I= Names.rbegin(), End =Names.rend(); I!=End; ++I)
+ QualName += *I + "::";
+ QualName += cast<NamedDecl>(D)->getNameAsString();
+ return QualName;
+}
+
+Sema::LookupResult
+Sema::LookupResult::CreateLookupResult(ASTContext &Context, Decl *D) {
+ LookupResult Result;
+ Result.StoredKind = (D && isa<OverloadedFunctionDecl>(D))?
+ OverloadedDeclSingleDecl : SingleDecl;
+ Result.First = reinterpret_cast<uintptr_t>(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 @@
case SingleDecl:
return (reinterpret_cast<Decl *>(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 @@
reinterpret_cast<DeclContext::lookup_iterator>(First),
reinterpret_cast<DeclContext::lookup_iterator>(Last));
- case AmbiguousLookup:
+ case OverloadedDeclSingleDecl:
+ return reinterpret_cast<OverloadedFunctionDecl*>(First);
+
+ case AmbiguousLookupStoresDecls:
+ case AmbiguousLookupStoresBasePaths:
assert(false &&
"Name lookup returned an ambiguity that could not be handled");
break;
@@ -174,11 +488,11 @@
}
/// @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<BasePaths *>(First);
+ if (StoredKind == AmbiguousLookupStoresBasePaths)
+ return reinterpret_cast<BasePaths *>(First);
+ return 0;
}
Sema::LookupResult::iterator::reference
@@ -187,13 +501,17 @@
case SingleDecl:
return reinterpret_cast<Decl*>(Current);
+ case OverloadedDeclSingleDecl:
+ return *reinterpret_cast<Decl**>(Current);
+
case OverloadedDeclFromIdResolver:
return *IdentifierResolver::iterator::getFromOpaqueValue(Current);
case OverloadedDeclFromDeclContext:
return *reinterpret_cast<DeclContext::lookup_iterator>(Current);
-
- case AmbiguousLookup:
+
+ case AmbiguousLookupStoresDecls:
+ case AmbiguousLookupStoresBasePaths:
assert(false && "Cannot look into ambiguous lookup results");
break;
}
@@ -207,6 +525,12 @@
Current = reinterpret_cast<uintptr_t>((Decl*)0);
break;
+ case OverloadedDeclSingleDecl: {
+ Decl ** I = reinterpret_cast<Decl**>(Current);
+ ++I;
+ Current = reinterpret_cast<uintptr_t>(I);
+ }
+
case OverloadedDeclFromIdResolver: {
IdentifierResolver::iterator I
= IdentifierResolver::iterator::getFromOpaqueValue(Current);
@@ -223,7 +547,8 @@
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::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<OverloadedFunctionDecl*>(First);
+ return iterator(this, reinterpret_cast<uintptr_t>(&(*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<OverloadedFunctionDecl*>(First);
+ return iterator(this, reinterpret_cast<uintptr_t>(&(*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<DeclContext*>(S->getEntity()))
+ return Ctx->isFunctionOrMethod();
+ return true;
+}
- case Sema::LookupTagName:
- IDNS = Decl::IDNS_Tag;
- break;
+std::pair<bool, Sema::LookupResult>
+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<DeclContext *>(S->getEntity());
+
+ if (Ctx && isa<TranslationUnitDecl>(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 @@
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<DeclContext *>(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<bool, LookupResult> 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 @@
return LookupName(S, Name, NameKind, RedeclarationOnly);
}
+
/// @brief Produce a diagnostic describing the ambiguity that resulted
/// from name lookup.
///
@@ -633,37 +1089,57 @@
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;
-
- DeclContext::lookup_iterator Found = Paths->front().Decls.first;
- while (isa<CXXMethodDecl>(*Found) && cast<CXXMethodDecl>(*Found)->isStatic())
- ++Found;
-
- Diag((*Found)->getLocation(), diag::note_ambiguous_member_found);
+ 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<CXXMethodDecl>(*Found) && cast<CXXMethodDecl>(*Found)->isStatic())
+ ++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<Decl *> 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<Decl **>(Result.First),
+ **DEnd = reinterpret_cast<Decl **>(Result.Last);
- std::set<Decl *> 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<Decl **>(Result.First);
+
+ return true;
}
- delete Paths;
+ assert(false && "Unhandled form of name lookup ambiguity");
+ // We can't reach here.
return true;
}
Modified: cfe/trunk/test/SemaCXX/member-name-lookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-name-lookup.cpp?rev=63646&r1=63645&r2=63646&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/member-name-lookup.cpp (original)
+++ cfe/trunk/test/SemaCXX/member-name-lookup.cpp Tue Feb 3 13:21:40 2009
@@ -130,3 +130,17 @@
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 { };
+};
Added: cfe/trunk/test/SemaCXX/using-directive.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/using-directive.cpp?rev=63646&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/using-directive.cpp (added)
+++ cfe/trunk/test/SemaCXX/using-directive.cpp Tue Feb 3 13:21:40 2009
@@ -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 { };
+}
More information about the cfe-commits
mailing list