DR1442: In a range-based for statement, namespace 'std' is not an associated
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 18 Oct 2012 17:56:02 +0000 (17:56 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 18 Oct 2012 17:56:02 +0000 (17:56 +0000)
namespace.

llvm-svn: 166194

clang/include/clang/AST/ExprCXX.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/ExprCXX.cpp
clang/lib/Sema/SemaLookup.cpp
clang/lib/Sema/SemaOverload.cpp
clang/lib/Serialization/ASTReaderStmt.cpp
clang/lib/Serialization/ASTWriterStmt.cpp
clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
clang/test/CodeGenCXX/for-range.cpp
clang/test/PCH/cxx-for-range.h

index ff7fb81..96603eb 100644 (file)
@@ -2441,10 +2441,6 @@ class UnresolvedLookupExpr : public OverloadExpr {
   /// call.
   bool RequiresADL;
 
-  /// True if namespace ::std should be considered an associated namespace
-  /// for the purposes of argument-dependent lookup. See C++0x [stmt.ranged]p1.
-  bool StdIsAssociatedNamespace;
-
   /// True if these lookup results are overloaded.  This is pretty
   /// trivially rederivable if we urgently need to kill this field.
   bool Overloaded;
@@ -2463,19 +2459,16 @@ class UnresolvedLookupExpr : public OverloadExpr {
                        const DeclarationNameInfo &NameInfo,
                        bool RequiresADL, bool Overloaded,
                        const TemplateArgumentListInfo *TemplateArgs,
-                       UnresolvedSetIterator Begin, UnresolvedSetIterator End,
-                       bool StdIsAssociatedNamespace)
+                       UnresolvedSetIterator Begin, UnresolvedSetIterator End)
     : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, TemplateKWLoc,
                    NameInfo, TemplateArgs, Begin, End, false, false, false),
       RequiresADL(RequiresADL),
-      StdIsAssociatedNamespace(StdIsAssociatedNamespace),
       Overloaded(Overloaded), NamingClass(NamingClass)
   {}
 
   UnresolvedLookupExpr(EmptyShell Empty)
     : OverloadExpr(UnresolvedLookupExprClass, Empty),
-      RequiresADL(false), StdIsAssociatedNamespace(false), Overloaded(false),
-      NamingClass(0)
+      RequiresADL(false), Overloaded(false), NamingClass(0)
   {}
 
   friend class ASTStmtReader;
@@ -2487,14 +2480,10 @@ public:
                                       const DeclarationNameInfo &NameInfo,
                                       bool ADL, bool Overloaded,
                                       UnresolvedSetIterator Begin,
-                                      UnresolvedSetIterator End,
-                                      bool StdIsAssociatedNamespace = false) {
-    assert((ADL || !StdIsAssociatedNamespace) &&
-           "std considered associated namespace when not performing ADL");
+                                      UnresolvedSetIterator End) {
     return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
                                        SourceLocation(), NameInfo,
-                                       ADL, Overloaded, 0, Begin, End,
-                                       StdIsAssociatedNamespace);
+                                       ADL, Overloaded, 0, Begin, End);
   }
 
   static UnresolvedLookupExpr *Create(ASTContext &C,
@@ -2515,10 +2504,6 @@ public:
   /// argument-dependent lookup.
   bool requiresADL() const { return RequiresADL; }
 
-  /// True if namespace \::std should be artificially added to the set of
-  /// associated namespaces for argument-dependent lookup purposes.
-  bool isStdAssociatedNamespace() const { return StdIsAssociatedNamespace; }
-
   /// True if this lookup is overloaded.
   bool isOverloaded() const { return Overloaded; }
 
index e74c96b..01a5884 100644 (file)
@@ -1894,8 +1894,7 @@ public:
                                             llvm::ArrayRef<Expr *> Args,
                                 TemplateArgumentListInfo *ExplicitTemplateArgs,
                                             OverloadCandidateSet& CandidateSet,
-                                            bool PartialOverloading = false,
-                                        bool StdNamespaceIsAssociated = false);
+                                            bool PartialOverloading = false);
 
   // Emit as a 'note' the specific overload candidate
   void NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType = QualType());
@@ -2188,8 +2187,7 @@ public:
   void ArgumentDependentLookup(DeclarationName Name, bool Operator,
                                SourceLocation Loc,
                                llvm::ArrayRef<Expr *> Args,
-                               ADLResult &Functions,
-                               bool StdNamespaceIsAssociated = false);
+                               ADLResult &Functions);
 
   void LookupVisibleDecls(Scope *S, LookupNameKind Kind,
                           VisibleDeclConsumer &Consumer,
index 38e9dd1..9758b60 100644 (file)
@@ -247,7 +247,7 @@ UnresolvedLookupExpr::Create(ASTContext &C,
   return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc,
                                         TemplateKWLoc, NameInfo,
                                         ADL, /*Overload*/ true, Args,
-                                        Begin, End, /*StdIsAssociated=*/false);
+                                        Begin, End);
 }
 
 UnresolvedLookupExpr *
index e4dab05..f6987e7 100644 (file)
@@ -2649,8 +2649,7 @@ void ADLResult::insert(NamedDecl *New) {
 void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
                                    SourceLocation Loc,
                                    llvm::ArrayRef<Expr *> Args,
-                                   ADLResult &Result,
-                                   bool StdNamespaceIsAssociated) {
+                                   ADLResult &Result) {
   // Find all of the associated namespaces and classes based on the
   // arguments we have.
   AssociatedNamespaceSet AssociatedNamespaces;
@@ -2658,8 +2657,6 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator,
   FindAssociatedClassesAndNamespaces(Loc, Args,
                                      AssociatedNamespaces,
                                      AssociatedClasses);
-  if (StdNamespaceIsAssociated && StdNamespace)
-    AssociatedNamespaces.insert(getStdNamespace());
 
   QualType T1, T2;
   if (Operator) {
index bdc25ba..4d392ed 100644 (file)
@@ -7678,8 +7678,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
                                            llvm::ArrayRef<Expr *> Args,
                                  TemplateArgumentListInfo *ExplicitTemplateArgs,
                                            OverloadCandidateSet& CandidateSet,
-                                           bool PartialOverloading,
-                                           bool StdNamespaceIsAssociated) {
+                                           bool PartialOverloading) {
   ADLResult Fns;
 
   // FIXME: This approach for uniquing ADL results (and removing
@@ -7690,8 +7689,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
   // we supposed to consider on ADL candidates, anyway?
 
   // FIXME: Pass in the explicit template arguments?
-  ArgumentDependentLookup(Name, Operator, Loc, Args, Fns,
-                          StdNamespaceIsAssociated);
+  ArgumentDependentLookup(Name, Operator, Loc, Args, Fns);
 
   // Erase all of the candidates we already knew about.
   for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
@@ -9484,8 +9482,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE,
     AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false,
                                          ULE->getExprLoc(),
                                          Args, ExplicitTemplateArgs,
-                                         CandidateSet, PartialOverloading,
-                                         ULE->isStdAssociatedNamespace());
+                                         CandidateSet, PartialOverloading);
 }
 
 /// Attempt to recover from an ill-formed use of a non-dependent name in a
@@ -9769,9 +9766,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn,
 
     // We don't perform ADL in C.
     assert(getLangOpts().CPlusPlus && "ADL enabled in C");
-  } else
-    assert(!ULE->isStdAssociatedNamespace() &&
-           "std is associated namespace but not doing ADL");
+  }
 #endif
 
   UnbridgedCastsSet UnbridgedCasts;
@@ -11337,14 +11332,11 @@ Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
     }
   } else {
     UnresolvedSet<0> FoundNames;
-    // C++11 [stmt.ranged]p1: For the purposes of this name lookup, namespace
-    // std is an associated namespace.
     UnresolvedLookupExpr *Fn =
       UnresolvedLookupExpr::Create(Context, /*NamingClass=*/0,
                                    NestedNameSpecifierLoc(), NameInfo,
                                    /*NeedsADL=*/true, /*Overloaded=*/false,
-                                   FoundNames.begin(), FoundNames.end(),
-                                   /*LookInStdNamespace=*/true);
+                                   FoundNames.begin(), FoundNames.end());
 
     bool CandidateSetError = buildOverloadedCallSet(S, Fn, Fn, &Range, 1, Loc,
                                                     CandidateSet, CallExpr);
index 3a02e76..52b4435 100644 (file)
@@ -1368,8 +1368,6 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
 void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
   VisitOverloadExpr(E);
   E->RequiresADL = Record[Idx++];
-  if (E->RequiresADL)
-    E->StdIsAssociatedNamespace = Record[Idx++];
   E->Overloaded = Record[Idx++];
   E->NamingClass = ReadDeclAs<CXXRecordDecl>(Record, Idx);
 }
index 0337089..121d4d6 100644 (file)
@@ -1385,8 +1385,6 @@ void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
 void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
   VisitOverloadExpr(E);
   Record.push_back(E->requiresADL());
-  if (E->requiresADL())
-    Record.push_back(E->isStdAssociatedNamespace());
   Record.push_back(E->isOverloaded());
   Writer.AddDeclRef(E->getNamingClass(), Record);
   Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP;
index 6c6fe09..3952afd 100644 (file)
@@ -8,15 +8,19 @@ struct pr12960 {
   }
 };
 
-namespace std {
+struct null_t {
+  operator int*();
+};
+
+namespace X {
   template<typename T>
-    auto begin(T &&t) -> decltype(t.begin()) { return t.begin(); } // expected-note 4{{ignored: substitution failure}}
+    auto begin(T &&t) -> decltype(t.begin()) { return t.begin(); } // expected-note 2{{ignored: substitution failure}}
   template<typename T>
     auto end(T &&t) -> decltype(t.end()) { return t.end(); } // expected-note {{candidate template ignored: substitution failure [with T = }}
 
   template<typename T>
     auto begin(T &&t) -> decltype(t.alt_begin()) { return t.alt_begin(); } // expected-note {{selected 'begin' template [with T = }} \
-                                                                              expected-note 4{{candidate template ignored: substitution failure [with T = }}
+                                                                              expected-note 2{{candidate template ignored: substitution failure [with T = }}
   template<typename T>
     auto end(T &&t) -> decltype(t.alt_end()) { return t.alt_end(); } // expected-note {{candidate template ignored: substitution failure [with T = }}
 
@@ -27,19 +31,28 @@ namespace std {
   }
 
   using namespace inner;
-}
 
-struct A { // expected-note 2 {{candidate constructor}}
-  A();
-  int *begin(); // expected-note 3{{selected 'begin' function with iterator type 'int *'}} expected-note {{'begin' declared here}}
-  int *end();
-};
+  struct A { // expected-note 2 {{candidate constructor}}
+    A();
+    int *begin(); // expected-note 3{{selected 'begin' function with iterator type 'int *'}} expected-note {{'begin' declared here}}
+    int *end();
+  };
 
-struct B {
-  B();
-  int *alt_begin();
-  int *alt_end();
-};
+  struct B {
+    B();
+    int *alt_begin();
+    int *alt_end();
+  };
+
+  struct NoBeginADL {
+    null_t alt_end();
+  };
+  struct NoEndADL {
+    null_t alt_begin();
+  };
+}
+
+using X::A;
 
 void f();
 void f(int);
@@ -49,19 +62,19 @@ void g() {
     A __begin;
   for (char *a : A()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
   }
-  for (char *a : B()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
+  for (char *a : X::B()) { // expected-error {{cannot initialize a variable of type 'char *' with an lvalue of type 'int'}}
   }
   // FIXME: Terrible diagnostic here. auto deduction should fail, but does not!
   for (double a : f) { // expected-error {{cannot use type '<overloaded function type>' as a range}}
   }
   for (auto a : A()) {
   }
-  for (auto a : B()) {
+  for (auto a : X::B()) {
   }
   for (auto *a : A()) { // expected-error {{variable 'a' with type 'auto *' has incompatible initializer of type 'int'}}
   }
   // : is not a typo for :: here.
-  for (A NS:A()) { // expected-error {{no viable conversion from 'int' to 'A'}}
+  for (A NS:A()) { // expected-error {{no viable conversion from 'int' to 'X::A'}}
   }
   for (auto not_in_scope : not_in_scope) { // expected-error {{use of undeclared identifier 'not_in_scope'}}
   }
@@ -92,9 +105,6 @@ void g() {
   for (auto a : VoidBegin()) // expected-error {{cannot use type 'void' as an iterator}}
     ;
 
-  struct null_t {
-    operator int*();
-  };
   struct Differ {
     int *begin(); // expected-note {{selected 'begin' function with iterator type 'int *'}}
     null_t end(); // expected-note {{selected 'end' function with iterator type 'null_t'}}
@@ -110,15 +120,9 @@ void g() {
   for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}}
   for (constexpr int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'constexpr'}}
 
-  struct NoBeginADL {
-    null_t alt_end();
-  };
-  struct NoEndADL {
-    null_t alt_begin();
-  };
-  for (auto u : NoBeginADL()) { // expected-error {{invalid range expression of type 'NoBeginADL'; no viable 'begin' function available}}
+  for (auto u : X::NoBeginADL()) { // expected-error {{invalid range expression of type 'X::NoBeginADL'; no viable 'begin' function available}}
   }
-  for (auto u : NoEndADL()) { // expected-error {{invalid range expression of type 'NoEndADL'; no viable 'end' function available}}
+  for (auto u : X::NoEndADL()) { // expected-error {{invalid range expression of type 'X::NoEndADL'; no viable 'end' function available}}
   }
 
   struct NoBegin {
@@ -178,7 +182,7 @@ void g() {
 
 template<typename T, typename U>
 void h(T t) {
-  for (U u : t) { // expected-error {{no viable conversion from 'A' to 'int'}}
+  for (U u : t) { // expected-error {{no viable conversion from 'X::A' to 'int'}}
   }
   for (auto u : t) {
   }
@@ -191,7 +195,7 @@ template void h<A(&)[13], int>(A(&)[13]); // expected-note {{requested here}}
 
 template<typename T>
 void i(T t) {
-  for (auto u : t) { // expected-error {{invalid range expression of type 'A *'; no viable 'begin' function available}} \
+  for (auto u : t) { // expected-error {{invalid range expression of type 'X::A *'; no viable 'begin' function available}} \
                         expected-error {{member function 'begin' not viable}} \
                         expected-note {{when looking up 'begin' function}}
 
@@ -200,6 +204,15 @@ void i(T t) {
 template void i<A[13]>(A*); // expected-note {{requested here}}
 template void i<const A>(const A); // expected-note {{requested here}}
 
+struct StdBeginEnd {};
+namespace std {
+  int *begin(StdBeginEnd);
+  int *end(StdBeginEnd);
+}
+void DR1442() {
+  for (auto a : StdBeginEnd()) {} // expected-error {{invalid range expression of type 'StdBeginEnd'; no viable 'begin'}}
+}
+
 namespace NS {
   class ADL {};
   int *begin(ADL); // expected-note {{no known conversion from 'NS::NoADL' to 'NS::ADL'}}
index 0f35dda..929e33c 100644 (file)
@@ -27,10 +27,8 @@ struct D {
   B *end();
 };
 
-namespace std {
-  B *begin(C&);
-  B *end(C&);
-}
+B *begin(C&);
+B *end(C&);
 
 extern B array[5];
 
@@ -69,8 +67,8 @@ void for_range() {
   A a;
   for (B b : C()) {
     // CHECK: call void @_ZN1CC1Ev(
-    // CHECK: = call %struct.B* @_ZSt5beginR1C(
-    // CHECK: = call %struct.B* @_ZSt3endR1C(
+    // CHECK: = call %struct.B* @_Z5beginR1C(
+    // CHECK: = call %struct.B* @_Z3endR1C(
     // CHECK: br label %[[COND:.*]]
 
     // CHECK: [[COND]]:
index f15c7e7..8f50f2f 100644 (file)
@@ -9,11 +9,12 @@ struct T { };
 char *begin(T);
 char *end(T);
 
-struct U { };
-namespace std {
+namespace NS {
+  struct U { };
   char *begin(U);
   char *end(U);
 }
+using NS::U;
 
 void f() {
   char a[3] = { 0, 1, 2 };