DR1442: In a range-based for statement, namespace 'std' is not an associated

namespace.

llvm-svn: 166194
This commit is contained in:
Richard Smith 2012-10-18 17:56:02 +00:00
parent 0eea516789
commit b6626748c2
10 changed files with 63 additions and 83 deletions

View 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; }

View 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,

View 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 *

View 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) {

View 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);

View 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);
}

View 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;

View 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 B {
B();
int *alt_begin();
int *alt_end();
};
struct NoBeginADL {
null_t alt_end();
};
struct NoEndADL {
null_t alt_begin();
};
}
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();
};
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'}}

View 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]]:

View 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 };