From b1502bcd67fb593a95cbf73ec3814f4015666da0 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 18 Oct 2012 17:56:02 +0000 Subject: [PATCH] DR1442: In a range-based for statement, namespace 'std' is not an associated namespace. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166194 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ExprCXX.h | 23 +----- include/clang/Sema/Sema.h | 6 +- lib/AST/ExprCXX.cpp | 2 +- lib/Sema/SemaLookup.cpp | 5 +- lib/Sema/SemaOverload.cpp | 18 ++--- lib/Serialization/ASTReaderStmt.cpp | 2 - lib/Serialization/ASTWriterStmt.cpp | 2 - .../stmt.stmt/stmt.iter/stmt.ranged/p1.cpp | 73 +++++++++++-------- test/CodeGenCXX/for-range.cpp | 10 +-- test/PCH/cxx-for-range.h | 5 +- 10 files changed, 63 insertions(+), 83 deletions(-) diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index ff7fb8142a..96603ebd64 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -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; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index e74c96b180..01a588423f 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1894,8 +1894,7 @@ public: llvm::ArrayRef 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 Args, - ADLResult &Functions, - bool StdNamespaceIsAssociated = false); + ADLResult &Functions); void LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 38e9dd1ba5..9758b60727 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -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 * diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index e4dab053e2..f6987e7bfb 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -2649,8 +2649,7 @@ void ADLResult::insert(NamedDecl *New) { void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, SourceLocation Loc, llvm::ArrayRef 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) { diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index bdc25ba39c..4d392edb78 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -7678,8 +7678,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, llvm::ArrayRef 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); diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 3a02e76d19..52b4435944 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -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(Record, Idx); } diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 0337089659..121d4d6dcd 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -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; diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp index 6c6fe09165..3952afdeff 100644 --- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp +++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp @@ -8,15 +8,19 @@ struct pr12960 { } }; -namespace std { +struct null_t { + operator int*(); +}; + +namespace X { template - 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 auto end(T &&t) -> decltype(t.end()) { return t.end(); } // expected-note {{candidate template ignored: substitution failure [with T = }} template 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 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 '' 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 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]); // expected-note {{requested here}} template 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*); // expected-note {{requested here}} template void i(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'}} diff --git a/test/CodeGenCXX/for-range.cpp b/test/CodeGenCXX/for-range.cpp index 0f35dda737..929e33ca96 100644 --- a/test/CodeGenCXX/for-range.cpp +++ b/test/CodeGenCXX/for-range.cpp @@ -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]]: diff --git a/test/PCH/cxx-for-range.h b/test/PCH/cxx-for-range.h index f15c7e73df..8f50f2f269 100644 --- a/test/PCH/cxx-for-range.h +++ b/test/PCH/cxx-for-range.h @@ -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 }; -- 2.40.0