DR1442: In a range-based for statement, namespace 'std' is not an associated
namespace. llvm-svn: 166194
This commit is contained in:
parent
0eea516789
commit
b6626748c2
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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'}}
|
||||
|
|
|
@ -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]]:
|
||||
|
|
|
@ -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 };
|
||||
|
|
Loading…
Reference in New Issue