[cfe-commits] r83700 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaLookup.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaType.cpp test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp

John McCall rjmccall at apple.com
Fri Oct 9 22:48:20 PDT 2009


Author: rjmccall
Date: Sat Oct 10 00:48:19 2009
New Revision: 83700

URL: http://llvm.org/viewvc/llvm-project?rev=83700&view=rev
Log:
Qualified lookup through using declarations.  Diagnose a new type of ambiguity.
Split the various ambiguous result enumerators into their own enum.  Tests
for most of C++ [namespace.qual].


Added:
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp
    cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaType.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=83700&r1=83699&r2=83700&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Oct 10 00:48:19 2009
@@ -1996,6 +1996,10 @@
 def note_ambiguous_member_found : Note<"member found by ambiguous name lookup">;
 def err_ambiguous_reference : Error<"reference to %0 is ambiguous">;
 def note_ambiguous_candidate : Note<"candidate found by name lookup is %q0">;
+def err_ambiguous_tag_hiding : Error<"a type named %0 is hidden by a "
+  "declaration in a different namespace">;
+def note_hidden_tag : Note<"type declaration hidden">;
+def note_hiding_object : Note<"declaration hides type">;
 
 // C++ operator overloading
 def err_operator_overload_needs_class_or_enum : Error<

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=83700&r1=83699&r2=83700&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sat Oct 10 00:48:19 2009
@@ -1074,6 +1074,13 @@
       /// functions into an OverloadedFunctionDecl.
       FoundOverloaded,
 
+      /// @brief Name lookup results in an ambiguity; use
+      /// getAmbiguityKind to figure out what kind of ambiguity
+      /// we have.
+      Ambiguous
+    };
+
+    enum AmbiguityKind {
       /// Name lookup results in an ambiguity because multiple
       /// entities that meet the lookup criteria were found in
       /// subobjects of different types. For example:
@@ -1117,7 +1124,22 @@
       /// @endcode
       AmbiguousReference,
 
-      FirstAmbiguous = AmbiguousBaseSubobjectTypes
+      /// Name lookup results in an ambiguity because an entity with a
+      /// tag name was hidden by an entity with an ordinary name from
+      /// a different context.
+      /// @code
+      /// namespace A { struct Foo {}; }
+      /// namespace B { void Foo(); }
+      /// namespace C {
+      ///   using namespace A;
+      ///   using namespace B;
+      /// }
+      /// void test() {
+      ///   C::Foo(); // error: tag 'A::Foo' is hidden by an object in a
+      ///             // different namespace
+      /// }
+      /// @endcode
+      AmbiguousTagHiding
     };
 
     typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy;
@@ -1132,7 +1154,7 @@
     }
 
     bool isAmbiguous() const {
-      return getKind() >= FirstAmbiguous;
+      return getKind() == Ambiguous;
     }
 
     LookupKind getKind() const {
@@ -1140,6 +1162,11 @@
       return Kind;
     }
 
+    AmbiguityKind getAmbiguityKind() const {
+      assert(isAmbiguous());
+      return Ambiguity;
+    }
+
     iterator begin() const { return Decls.begin(); }
     iterator end() const { return Decls.end(); }
 
@@ -1158,6 +1185,25 @@
       Kind = Found;
     }
 
+    /// \brief Add all the declarations from another set of lookup
+    /// results.
+    void addAllDecls(const LookupResult &Other) {
+      Decls.append(Other.begin(), Other.end());
+      Kind = Found;
+    }
+
+    /// \brief Hides a set of declarations.
+    template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) {
+      unsigned I = 0, N = Decls.size();
+      while (I < N) {
+        if (Set.count(Decls[I]))
+          Decls[I] = Decls[--N];
+        else
+          I++;
+      }
+      Decls.set_size(N);
+    }
+
     /// \brief Resolves the kind of the lookup, possibly hiding decls.
     ///
     /// This should be called in any environment where lookup might
@@ -1181,6 +1227,11 @@
       return *Decls.begin();
     }
 
+    /// \brief Asks if the result is a single tag decl.
+    bool isSingleTagDecl() const {
+      return getKind() == Found && isa<TagDecl>(getFoundDecl());
+    }
+
     /// \brief Make these results show that the name was found in
     /// base classes of different types.
     ///
@@ -1193,6 +1244,13 @@
     /// The given paths object is copied and invalidated.
     void setAmbiguousBaseSubobjects(CXXBasePaths &P);
 
+    /// \brief Make these results show that the name was found in
+    /// different contexts and a tag decl was hidden by an ordinary
+    /// decl in a different context.
+    void setAmbiguousQualifiedTagHiding() {
+      setAmbiguous(AmbiguousTagHiding);
+    }
+
     /// \brief Clears out any current state.
     void clear() {
       Kind = NotFound;
@@ -1204,6 +1262,11 @@
     void print(llvm::raw_ostream &);
 
   private:
+    void setAmbiguous(AmbiguityKind AK) {
+      Kind = Ambiguous;
+      Ambiguity = AK;
+    }
+
     void addDeclsFromBasePaths(const CXXBasePaths &P);
 
     // Sanity checks.
@@ -1211,14 +1274,17 @@
       assert(Kind != NotFound || Decls.size() == 0);
       assert(Kind != Found || Decls.size() == 1);
       assert(Kind == NotFound || Kind == Found ||
-             Kind == AmbiguousBaseSubobjects || Decls.size() > 1);
-      assert((Paths != NULL) == (Kind == AmbiguousBaseSubobjectTypes ||
-                                 Kind == AmbiguousBaseSubobjects));
+             (Kind == Ambiguous && Ambiguity == AmbiguousBaseSubobjects)
+             || Decls.size() > 1);
+      assert((Paths != NULL) == (Kind == Ambiguous &&
+                                 (Ambiguity == AmbiguousBaseSubobjectTypes ||
+                                  Ambiguity == AmbiguousBaseSubobjects)));
     }
 
     static void deletePaths(CXXBasePaths *);
 
     LookupKind Kind;
+    AmbiguityKind Ambiguity; // ill-defined unless ambiguous
     DeclsTy Decls;
     CXXBasePaths *Paths;
   };

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=83700&r1=83699&r2=83700&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Oct 10 00:48:19 2009
@@ -94,9 +94,15 @@
   case LookupResult::FoundOverloaded:
     return 0;
 
-  case LookupResult::AmbiguousBaseSubobjectTypes:
-  case LookupResult::AmbiguousBaseSubobjects:
-  case LookupResult::AmbiguousReference: {
+  case LookupResult::Ambiguous: {
+    // Recover from type-hiding ambiguities by hiding the type.  We'll
+    // do the lookup again when looking for an object, and we can
+    // diagnose the error then.  If we don't do this, then the error
+    // about hiding the type will be immediately followed by an error
+    // that only makes sense if the identifier was treated like a type.
+    if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding)
+      return 0;
+
     // Look to see if we have a type anywhere in the list of results.
     for (LookupResult::iterator Res = Result.begin(), ResEnd = Result.end();
          Res != ResEnd; ++Res) {
@@ -4129,6 +4135,8 @@
   bool isStdBadAlloc = false;
   bool Invalid = false;
 
+  bool RedeclarationOnly = (TUK != TUK_Reference);
+
   if (Name && SS.isNotEmpty()) {
     // We have a nested-name tag ('struct foo::bar').
 
@@ -4155,11 +4163,18 @@
     SearchDC = DC;
     // Look-up name inside 'foo::'.
     LookupResult R;
-    LookupQualifiedName(R, DC, Name, LookupTagName, true);
-    PrevDecl = dyn_cast_or_null<TagDecl>(R.getAsSingleDecl(Context));
+    LookupQualifiedName(R, DC, Name, LookupTagName, RedeclarationOnly);
+
+    if (R.isAmbiguous()) {
+      DiagnoseAmbiguousLookup(R, Name, NameLoc, SS.getRange());
+      return DeclPtrTy();
+    }
+
+    if (R.getKind() == LookupResult::Found)
+      PrevDecl = dyn_cast<TagDecl>(R.getFoundDecl());
 
     // A tag 'foo::bar' must already exist.
-    if (PrevDecl == 0) {
+    if (!PrevDecl) {
       Diag(NameLoc, diag::err_not_tag_in_scope) << Name << SS.getRange();
       Name = 0;
       Invalid = true;
@@ -4172,8 +4187,7 @@
     // shouldn't be. Doing so can result in ambiguities that we
     // shouldn't be diagnosing.
     LookupResult R;
-    LookupName(R, S, Name, LookupTagName,
-                                /*RedeclarationOnly=*/(TUK != TUK_Reference));
+    LookupName(R, S, Name, LookupTagName, RedeclarationOnly);
     if (R.isAmbiguous()) {
       DiagnoseAmbiguousLookup(R, Name, NameLoc);
       // FIXME: This is not best way to recover from case like:

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=83700&r1=83699&r2=83700&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Sat Oct 10 00:48:19 2009
@@ -25,6 +25,7 @@
 #include "clang/Basic/LangOptions.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/ErrorHandling.h"
 #include <set>
 #include <vector>
 #include <iterator>
@@ -162,6 +163,9 @@
   // Fast case: no possible ambiguity.
   if (N <= 1) return;
 
+  // Don't do any extra resolution if we've already resolved as ambiguous.
+  if (Kind == Ambiguous) return;
+
   llvm::SmallPtrSet<NamedDecl*, 16> Unique;
 
   bool Ambiguous = false;
@@ -218,11 +222,11 @@
     Ambiguous = true;
 
   if (Ambiguous)
-    Kind = AmbiguousReference;
+    setAmbiguous(LookupResult::AmbiguousReference);
   else if (N > 1)
-    Kind = FoundOverloaded;
+    Kind = LookupResult::FoundOverloaded;
   else
-    Kind = Found;
+    Kind = LookupResult::Found;
 }
 
 /// @brief Converts the result of name lookup into a single (possible
@@ -278,7 +282,7 @@
   Paths->swap(P);
   addDeclsFromBasePaths(*Paths);
   resolveKind();
-  Kind = AmbiguousBaseSubobjects;
+  setAmbiguous(AmbiguousBaseSubobjects);
 }
 
 void Sema::LookupResult::setAmbiguousBaseSubobjectTypes(CXXBasePaths &P) {
@@ -286,7 +290,7 @@
   Paths->swap(P);
   addDeclsFromBasePaths(*Paths);
   resolveKind();
-  Kind = AmbiguousBaseSubobjectTypes;
+  setAmbiguous(AmbiguousBaseSubobjectTypes);
 }
 
 void Sema::LookupResult::print(llvm::raw_ostream &Out) {
@@ -644,6 +648,120 @@
   return false;
 }
 
+/// @brief Perform qualified name lookup in the namespaces nominated by
+/// using directives by the given context.
+///
+/// C++98 [namespace.qual]p2:
+///   Given X::m (where X is a user-declared namespace), or given ::m
+///   (where X is the global namespace), let S be the set of all
+///   declarations of m in X and in the transitive closure of all
+///   namespaces nominated by using-directives in X and its used
+///   namespaces, except that using-directives are ignored in any
+///   namespace, including X, directly containing one or more
+///   declarations of m. No namespace is searched more than once in
+///   the lookup of a name. If S is the empty set, the program is
+///   ill-formed. Otherwise, if S has exactly one member, or if the
+///   context of the reference is a using-declaration
+///   (namespace.udecl), S is the required set of declarations of
+///   m. Otherwise if the use of m is not one that allows a unique
+///   declaration to be chosen from S, the program is ill-formed.
+/// C++98 [namespace.qual]p5:
+///   During the lookup of a qualified namespace member name, if the
+///   lookup finds more than one declaration of the member, and if one
+///   declaration introduces a class name or enumeration name and the
+///   other declarations either introduce the same object, the same
+///   enumerator or a set of functions, the non-type name hides the
+///   class or enumeration name if and only if the declarations are
+///   from the same namespace; otherwise (the declarations are from
+///   different namespaces), the program is ill-formed.
+static bool LookupQualifiedNameInUsingDirectives(Sema::LookupResult &R,
+                                                 DeclContext *StartDC,
+                                                 DeclarationName Name,
+                                                 Sema::LookupNameKind NameKind,
+                                                 unsigned IDNS) {
+  assert(StartDC->isFileContext() && "start context is not a file context");
+
+  DeclContext::udir_iterator I = StartDC->using_directives_begin();
+  DeclContext::udir_iterator E = StartDC->using_directives_end();
+
+  if (I == E) return false;
+
+  // We have at least added all these contexts to the queue.
+  llvm::DenseSet<DeclContext*> Visited;
+  Visited.insert(StartDC);
+
+  // We have not yet looked into these namespaces, much less added
+  // their "using-children" to the queue.
+  llvm::SmallVector<NamespaceDecl*, 8> Queue;
+
+  // We have already looked into the initial namespace; seed the queue
+  // with its using-children.
+  for (; I != E; ++I) {
+    NamespaceDecl *ND = (*I)->getNominatedNamespace();
+    if (Visited.insert(ND).second)
+      Queue.push_back(ND);
+  }
+
+  // The easiest way to implement the restriction in [namespace.qual]p5
+  // is to check whether any of the individual results found a tag
+  // and, if so, to declare an ambiguity if the final result is not
+  // a tag.
+  bool FoundTag = false;
+  bool FoundNonTag = false;
+
+  Sema::LookupResult LocalR;
+
+  bool Found = false;
+  while (!Queue.empty()) {
+    NamespaceDecl *ND = Queue.back();
+    Queue.pop_back();
+
+    // We go through some convolutions here to avoid copying results
+    // between LookupResults.
+    bool UseLocal = !R.empty();
+    Sema::LookupResult &DirectR = UseLocal ? LocalR : R;
+    bool FoundDirect = LookupDirect(DirectR, ND, Name, NameKind, IDNS);
+
+    if (FoundDirect) {
+      // First do any local hiding.
+      DirectR.resolveKind();
+
+      // If the local result is a tag, remember that.
+      if (DirectR.isSingleTagDecl())
+        FoundTag = true;
+      else
+        FoundNonTag = true;
+
+      // Append the local results to the total results if necessary.
+      if (UseLocal) {
+        R.addAllDecls(LocalR);
+        LocalR.clear();
+      }
+    }
+
+    // If we find names in this namespace, ignore its using directives.
+    if (FoundDirect) {
+      Found = true;
+      continue;
+    }
+
+    for (llvm::tie(I,E) = ND->getUsingDirectives(); I != E; ++I) {
+      NamespaceDecl *Nom = (*I)->getNominatedNamespace();
+      if (Visited.insert(Nom).second)
+        Queue.push_back(Nom);
+    }
+  }
+
+  if (Found) {
+    if (FoundTag && FoundNonTag)
+      R.setAmbiguousQualifiedTagHiding();
+    else
+      R.resolveKind();
+  }
+
+  return Found;
+}
+
 /// @brief Perform qualified name lookup into a given context.
 ///
 /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find
@@ -704,9 +822,26 @@
     return true;
   }
 
+  // Don't descend into implied contexts for redeclarations.
+  // C++98 [namespace.qual]p6:
+  //   In a declaration for a namespace member in which the
+  //   declarator-id is a qualified-id, given that the qualified-id
+  //   for the namespace member has the form
+  //     nested-name-specifier unqualified-id
+  //   the unqualified-id shall name a member of the namespace
+  //   designated by the nested-name-specifier.
+  // See also [class.mfct]p5 and [class.static.data]p2.
+  if (RedeclarationOnly)
+    return false;
+
+  // If this is a namespace, look it up in 
+  if (LookupCtx->isFileContext())
+    return LookupQualifiedNameInUsingDirectives(R, LookupCtx, Name, NameKind,
+                                                IDNS);
+
   // If this isn't a C++ class, we aren't allowed to look into base
   // classes, we're done.
-  if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx))
+  if (!isa<CXXRecordDecl>(LookupCtx))
     return false;
 
   // Perform lookup into our base classes.
@@ -895,31 +1030,32 @@
                                    SourceRange LookupRange) {
   assert(Result.isAmbiguous() && "Lookup result must be ambiguous");
 
-  if (CXXBasePaths *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");
+  switch (Result.getAmbiguityKind()) {
+  case LookupResult::AmbiguousBaseSubobjects: {
+    CXXBasePaths *Paths = Result.getBasePaths();
+    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;
+  }
 
+  case LookupResult::AmbiguousBaseSubobjectTypes: {
     Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types)
       << Name << LookupRange;
-
+    
+    CXXBasePaths *Paths = Result.getBasePaths();
     std::set<Decl *> DeclsPrinted;
-    for (CXXBasePaths::paths_iterator Path = Paths->begin(), PathEnd = Paths->end();
+    for (CXXBasePaths::paths_iterator Path = Paths->begin(),
+                                      PathEnd = Paths->end();
          Path != PathEnd; ++Path) {
       Decl *D = *Path->Decls.first;
       if (DeclsPrinted.insert(D).second)
@@ -929,15 +1065,40 @@
     return true;
   }
 
-  assert(Result.getKind() == LookupResult::AmbiguousReference &&
-         "unhandled form of name lookup ambiguity");
-  Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange;
+  case LookupResult::AmbiguousTagHiding: {
+    Diag(NameLoc, diag::err_ambiguous_tag_hiding) << Name << LookupRange;
 
+    llvm::SmallPtrSet<NamedDecl*,8> TagDecls;
+
+    LookupResult::iterator DI, DE = Result.end();
+    for (DI = Result.begin(); DI != DE; ++DI)
+      if (TagDecl *TD = dyn_cast<TagDecl>(*DI)) {
+        TagDecls.insert(TD);
+        Diag(TD->getLocation(), diag::note_hidden_tag);
+      }
+
+    for (DI = Result.begin(); DI != DE; ++DI)
+      if (!isa<TagDecl>(*DI))
+        Diag((*DI)->getLocation(), diag::note_hiding_object);
+
+    // For recovery purposes, go ahead and implement the hiding.
+    Result.hideDecls(TagDecls);
+
+    return true;
+  }
+
+  case LookupResult::AmbiguousReference: {
+    Diag(NameLoc, diag::err_ambiguous_reference) << Name << LookupRange;
   
-  LookupResult::iterator DI = Result.begin(), DE = Result.end();
-  for (; DI != DE; ++DI)
-    Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI;
+    LookupResult::iterator DI = Result.begin(), DE = Result.end();
+    for (; DI != DE; ++DI)
+      Diag((*DI)->getLocation(), diag::note_ambiguous_candidate) << *DI;
+
+    return true;
+  }
+  }
 
+  llvm::llvm_unreachable("unknown ambiguity kind");
   return true;
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=83700&r1=83699&r2=83700&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sat Oct 10 00:48:19 2009
@@ -3858,9 +3858,7 @@
     Referenced = *Result.begin();
     break;
 
-  case LookupResult::AmbiguousBaseSubobjectTypes:
-  case LookupResult::AmbiguousBaseSubobjects:
-  case LookupResult::AmbiguousReference:
+  case LookupResult::Ambiguous:
     DiagnoseAmbiguousLookup(Result, Name, Range.getEnd(), Range);
     return QualType();
   }

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=83700&r1=83699&r2=83700&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sat Oct 10 00:48:19 2009
@@ -194,7 +194,13 @@
   case DeclSpec::TST_union:
   case DeclSpec::TST_struct: {
     Decl *D = static_cast<Decl *>(DS.getTypeRep());
-    assert(D && "Didn't get a decl for a class/enum/union/struct?");
+    if (!D) {
+      // This can happen in C++ with ambiguous lookups.
+      Result = Context.IntTy;
+      isInvalid = true;
+      break;
+    }
+
     assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 &&
            DS.getTypeSpecSign() == 0 &&
            "Can't handle qualifiers on typedef names yet!");

Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp?rev=83700&view=auto

==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p2.cpp Sat Oct 10 00:48:19 2009
@@ -0,0 +1,65 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace Ints {
+  int zero = 0; // expected-note {{candidate found by name lookup is 'Ints::zero'}}
+  void f(int); // expected-note 3 {{candidate function}}
+  void g(int);
+}
+
+namespace Floats {
+  float zero = 0.0f; // expected-note {{candidate found by name lookup is 'Floats::zero'}}
+  void f(float); // expected-note 3 {{candidate function}}
+  void g(float);
+}
+
+namespace Numbers {
+  using namespace Ints;
+  using namespace Floats;
+}
+
+void test() {
+  int i = Ints::zero;
+  Ints::f(i);
+  
+  float f = Floats::zero;
+  Floats::f(f);
+  
+  double n = Numbers::zero; // expected-error {{reference to 'zero' is ambiguous}}
+  Numbers::f(n); // expected-error{{call to 'f' is ambiguous}}
+  Numbers::f(i);
+  Numbers::f(f);
+}
+
+namespace Numbers {
+  struct Number {
+    explicit Number(double d) : d(d) {}
+    double d;
+  };
+  Number zero(0.0f);
+  void g(Number);
+}
+
+void test2() {
+  Numbers::Number n = Numbers::zero;
+  Numbers::f(n); // expected-error {{no matching function for call to 'f'}}
+  Numbers::g(n);
+}
+
+namespace Numbers2 {
+  using Numbers::f;
+  using Numbers::g;
+}
+
+void test3() {
+  Numbers::Number n = Numbers::zero;
+  Numbers2::f(n); // expected-error {{no matching function for call to 'f'}}
+  Numbers2::g(n);
+
+  int i = Ints::zero;
+  Numbers2::f(i);
+  Numbers2::g(i); // expected-error {{incompatible type passing 'int'}}
+
+  float f = Floats::zero;
+  Numbers2::f(f);
+  Numbers2::g(f); // expected-error {{incompatible type passing 'float'}}
+}

Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp?rev=83700&view=auto

==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p3.cpp Sat Oct 10 00:48:19 2009
@@ -0,0 +1,41 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// This is basically paraphrased from the standard.
+
+namespace Root {
+  int i = 0;
+  void f();
+}
+
+namespace A {
+  using namespace Root;
+}
+
+namespace B {
+  using namespace Root;
+}
+
+namespace AB {
+  using namespace A;
+  using namespace B;
+}
+
+void test() {
+  if (AB::i)
+    AB::f();
+}
+
+namespace C {
+  using Root::i;
+  using Root::f;
+}
+
+namespace AC {
+  using namespace A;
+  using namespace C;
+}
+
+void test2() {
+  if (AC::i)
+    AC::f();
+}

Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp?rev=83700&view=auto

==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p4.cpp Sat Oct 10 00:48:19 2009
@@ -0,0 +1,25 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace A {
+  int a;
+}
+
+namespace C {
+  int c;
+}
+
+namespace B {
+  using namespace C;
+  int b;
+}
+
+namespace C {
+  using namespace B;
+  using namespace A;
+}
+
+void test() {
+  C::a++;
+  C::b++;
+  C::c++;
+}

Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp?rev=83700&view=auto

==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.qual/namespace.qual/p5.cpp Sat Oct 10 00:48:19 2009
@@ -0,0 +1,35 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace A {
+  struct x {}; // expected-note {{candidate found by name lookup is 'A::x'}}
+  int x; // expected-note {{candidate found by name lookup is 'A::x'}}
+
+  struct y {}; // expected-note {{type declaration hidden}}
+
+  struct z;
+  void z(float);
+}
+
+namespace B {
+  struct x {}; // expected-note {{candidate found by name lookup is 'B::x'}}
+  float x; // expected-note {{candidate found by name lookup is 'B::x'}}
+
+  float y; // expected-note {{declaration hides type}}
+
+  void z(int);
+}
+
+namespace AB {
+  using namespace A;
+  using namespace B;
+}
+
+void test() {
+  struct AB::x foo; // expected-error {{reference to 'x' is ambiguous}}
+  int i = AB::x; // expected-error {{reference to 'x' is ambiguous}}
+
+  struct AB::y bar;
+  float f = AB::y; // expected-error {{a type named 'y' is hidden by a declaration in a different namespace}}
+  AB::z(i);
+  AB::z(f);
+}





More information about the cfe-commits mailing list