diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-03-17 23:06:31 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-03-17 23:06:31 +0000 |
commit | 42aceadbc3806868cee8ac576347d258ac99e1f6 (patch) | |
tree | 485d8f0e3546c1d43dfe552ea24878157fe0bb00 /lib/Sema/SemaDecl.cpp | |
parent | f3aae58296fd5f930f7c4c0709886924e6822ae7 (diff) |
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
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 68 |
1 files changed, 43 insertions, 25 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 574c18c2e3..15cd745d07 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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)) |