зеркало из https://github.com/microsoft/clang-1.git
Diagnose tag and class template declarations with qualified
declarator-ids that occur at class scope. Fixes PR8019. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153002 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
f3aae58296
Коммит
42aceadbc3
|
@ -1091,6 +1091,9 @@ public:
|
|||
const LookupResult &Previous,
|
||||
Scope *S);
|
||||
bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info);
|
||||
bool diagnoseQualifiedDeclInClass(CXXScopeSpec &SS, DeclContext *DC,
|
||||
DeclarationName Name,
|
||||
SourceLocation Loc);
|
||||
void DiagnoseFunctionSpecifiers(Declarator& D);
|
||||
void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
|
||||
void CheckShadow(Scope *S, VarDecl *D);
|
||||
|
|
|
@ -3235,7 +3235,44 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC,
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Diagnose a declaration that has a qualified name within a class,
|
||||
/// which is ill-formed but often recoverable.
|
||||
///
|
||||
/// \returns true if we cannot safely recover from this error, false otherwise.
|
||||
bool Sema::diagnoseQualifiedDeclInClass(CXXScopeSpec &SS, DeclContext *DC,
|
||||
DeclarationName Name,
|
||||
SourceLocation Loc) {
|
||||
// The user provided a superfluous scope specifier inside a class
|
||||
// definition:
|
||||
//
|
||||
// class X {
|
||||
// void X::f();
|
||||
// };
|
||||
if (CurContext->Equals(DC)) {
|
||||
Diag(Loc, diag::warn_member_extra_qualification)
|
||||
<< Name << FixItHint::CreateRemoval(SS.getRange());
|
||||
SS.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
Diag(Loc, diag::err_member_qualification)
|
||||
<< Name << SS.getRange();
|
||||
SS.clear();
|
||||
|
||||
// C++ constructors and destructors with incorrect scopes can break
|
||||
// our AST invariants by having the wrong underlying types. If
|
||||
// that's the case, then drop this declaration entirely.
|
||||
if ((Name.getNameKind() == DeclarationName::CXXConstructorName ||
|
||||
Name.getNameKind() == DeclarationName::CXXDestructorName) &&
|
||||
!Context.hasSameType(Name.getCXXNameType(),
|
||||
Context.getTypeDeclType(
|
||||
cast<CXXRecordDecl>(CurContext))))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
|
||||
MultiTemplateParamsArg TemplateParamLists) {
|
||||
// TODO: consider using NameInfo for diagnostic.
|
||||
|
@ -3294,31 +3331,9 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
|
|||
D.setInvalidType();
|
||||
} else if (isa<CXXRecordDecl>(CurContext) &&
|
||||
!D.getDeclSpec().isFriendSpecified()) {
|
||||
// The user provided a superfluous scope specifier inside a class
|
||||
// definition:
|
||||
//
|
||||
// class X {
|
||||
// void X::f();
|
||||
// };
|
||||
if (CurContext->Equals(DC)) {
|
||||
Diag(D.getIdentifierLoc(), diag::warn_member_extra_qualification)
|
||||
<< Name << FixItHint::CreateRemoval(D.getCXXScopeSpec().getRange());
|
||||
} else {
|
||||
Diag(D.getIdentifierLoc(), diag::err_member_qualification)
|
||||
<< Name << D.getCXXScopeSpec().getRange();
|
||||
|
||||
// C++ constructors and destructors with incorrect scopes can break
|
||||
// our AST invariants by having the wrong underlying types. If
|
||||
// that's the case, then drop this declaration entirely.
|
||||
if ((Name.getNameKind() == DeclarationName::CXXConstructorName ||
|
||||
Name.getNameKind() == DeclarationName::CXXDestructorName) &&
|
||||
!Context.hasSameType(Name.getCXXNameType(),
|
||||
Context.getTypeDeclType(cast<CXXRecordDecl>(CurContext))))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Pretend that this qualifier was not here.
|
||||
D.getCXXScopeSpec().clear();
|
||||
if (diagnoseQualifiedDeclInClass(D.getCXXScopeSpec(), DC,
|
||||
Name, D.getIdentifierLoc()))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8004,6 +8019,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
<< SS.getRange();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isa<CXXRecordDecl>(CurContext))
|
||||
diagnoseQualifiedDeclInClass(SS, DC, Name, NameLoc);
|
||||
}
|
||||
|
||||
if (RequireCompleteDeclContext(SS, DC))
|
||||
|
|
|
@ -886,7 +886,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
ContextRAII SavedContext(*this, SemanticContext);
|
||||
if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
|
||||
Invalid = true;
|
||||
}
|
||||
} else if (CurContext->isRecord() && TUK != TUK_Friend &&
|
||||
TUK != TUK_Reference)
|
||||
diagnoseQualifiedDeclInClass(SS, SemanticContext, Name, NameLoc);
|
||||
|
||||
LookupQualifiedName(Previous, SemanticContext);
|
||||
} else {
|
||||
|
@ -1065,7 +1067,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
|||
PrevClassTemplate->setMemberSpecialization();
|
||||
|
||||
// Set the access specifier.
|
||||
if (!Invalid && TUK != TUK_Friend)
|
||||
if (!Invalid && TUK != TUK_Friend && NewTemplate->getDeclContext()->isRecord())
|
||||
SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
|
||||
|
||||
// Set the lexical context of these templates
|
||||
|
|
|
@ -481,7 +481,7 @@ namespace test21 {
|
|||
};
|
||||
template <class T> class A<T>::Inner {};
|
||||
class B {
|
||||
template <class T> class A<T>::Inner;
|
||||
template <class T> class A<T>::Inner; // expected-error{{non-friend class member 'Inner' cannot have a qualified name}}
|
||||
};
|
||||
|
||||
void test() {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
namespace PR8019 {
|
||||
struct x;
|
||||
template<typename T> struct x2;
|
||||
struct y {
|
||||
struct PR8019::x { int x; }; // expected-error{{non-friend class member 'x' cannot have a qualified name}}
|
||||
|
||||
struct inner;
|
||||
struct y::inner { }; // expected-warning{{extra qualification on member 'inner'}}
|
||||
|
||||
template<typename T>
|
||||
struct PR8019::x2 { }; // expected-error{{non-friend class member 'x2' cannot have a qualified name}}
|
||||
|
||||
template<typename T>
|
||||
struct inner_template;
|
||||
|
||||
template<typename T>
|
||||
struct y::inner_template { }; // expected-warning{{extra qualification on member 'inner_template'}}
|
||||
};
|
||||
|
||||
}
|
|
@ -274,7 +274,8 @@ struct A {
|
|||
protected:
|
||||
struct B;
|
||||
struct B::C; // expected-error {{requires a template parameter list}} \
|
||||
// expected-error {{no struct named 'C'}}
|
||||
// expected-error {{no struct named 'C'}} \
|
||||
// expected-error{{non-friend class member 'C' cannot have a qualified name}}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
|
Загрузка…
Ссылка в новой задаче