diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 68 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 6 |
2 files changed, 47 insertions, 27 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 574c18c2e39..15cd745d079 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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)) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 37c7cefb0da..afa6c0e15b8 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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 |