forked from OSchip/llvm-project
A typename specifier can end up referring to a unresolved using
declaration that is a value in ill-formed code. Instead of crashing, treat this as a dependent typename specifier and suggest that the using add "typename" into the using declaration. Fixes <rdar://problem/8740998>. llvm-svn: 121322
This commit is contained in:
parent
bbf91a8975
commit
aed2efbbb5
|
@ -1782,6 +1782,11 @@ def err_typename_missing : Error<
|
|||
"missing 'typename' prior to dependent type name '%0%1'">;
|
||||
def ext_typename_outside_of_template : ExtWarn<
|
||||
"'typename' occurs outside of a template">, InGroup<CXX0x>;
|
||||
def err_typename_refers_to_using_value_decl : Error<
|
||||
"typename specifier refers to a dependent using declaration for a value "
|
||||
"%0 in %1">;
|
||||
def note_using_value_decl_missing_typename : Note<
|
||||
"add 'typename' to treat this using declaration as a type">;
|
||||
|
||||
def err_template_kw_refers_to_non_template : Error<
|
||||
"%0 following the 'template' keyword does not refer to a template">;
|
||||
|
|
|
@ -5699,6 +5699,23 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
|
|||
case LookupResult::NotFound:
|
||||
DiagID = diag::err_typename_nested_not_found;
|
||||
break;
|
||||
|
||||
case LookupResult::FoundUnresolvedValue: {
|
||||
// We found a using declaration that is a value. Most likely, the using
|
||||
// declaration itself is meant to have the 'typename' keyword.
|
||||
SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : NNSRange.getBegin(),
|
||||
IILoc);
|
||||
Diag(IILoc, diag::err_typename_refers_to_using_value_decl)
|
||||
<< Name << Ctx << FullRange;
|
||||
if (UnresolvedUsingValueDecl *Using
|
||||
= dyn_cast<UnresolvedUsingValueDecl>(Result.getRepresentativeDecl())){
|
||||
SourceLocation Loc = Using->getTargetNestedNameRange().getBegin();
|
||||
Diag(Loc, diag::note_using_value_decl_missing_typename)
|
||||
<< FixItHint::CreateInsertion(Loc, "typename ");
|
||||
}
|
||||
}
|
||||
// Fall through to create a dependent typename type, from which we can recover
|
||||
// better.
|
||||
|
||||
case LookupResult::NotFoundInCurrentInstantiation:
|
||||
// Okay, it's a member of an unknown instantiation.
|
||||
|
@ -5716,7 +5733,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
|
|||
Referenced = Result.getFoundDecl();
|
||||
break;
|
||||
|
||||
case LookupResult::FoundUnresolvedValue:
|
||||
|
||||
llvm_unreachable("unresolved using decl in non-dependent context");
|
||||
return QualType();
|
||||
|
||||
|
|
|
@ -134,3 +134,23 @@ namespace PR7419 {
|
|||
template <typename T> typename T::Y::Z::W *S<T>::f() { }
|
||||
template <typename T> typename T::template Y<int>::template Z<float>::template W<double> S<T>::g() { }
|
||||
}
|
||||
|
||||
namespace rdar8740998 {
|
||||
template<typename T>
|
||||
struct X : public T {
|
||||
using T::iterator; // expected-note{{add 'typename' to treat this using declaration as a type}} \
|
||||
// expected-error{{dependent using declaration resolved to type without 'typename'}}
|
||||
|
||||
void f() {
|
||||
typename X<T>::iterator i; // expected-error{{typename specifier refers to a dependent using declaration for a value 'iterator' in 'X<T>'}}
|
||||
}
|
||||
};
|
||||
|
||||
struct HasIterator {
|
||||
typedef int *iterator; // expected-note{{target of using declaration}}
|
||||
};
|
||||
|
||||
void test_X(X<HasIterator> xi) { // expected-note{{in instantiation of template class}}
|
||||
xi.f();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue