[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