From dfc2f1035d23e294b298766a3cf51dfe249d53a2 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Sat, 22 Jan 2011 17:51:53 +0000 Subject: [PATCH] Mark classes as final or explicit. Diagnose when a class marked 'final' is used as a base. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124039 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 9 +++++---- include/clang/Sema/Sema.h | 1 + lib/Parse/ParseDeclCXX.cpp | 3 ++- lib/Sema/SemaDecl.cpp | 4 ++++ lib/Sema/SemaDeclCXX.cpp | 13 +++++++++++++ test/CXX/class/p2-0x.cpp | 8 ++++++++ 6 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 test/CXX/class/p2-0x.cpp diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 0743d16124..7d3c3c82c4 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -873,16 +873,17 @@ def err_auto_missing_trailing_return : Error< "'auto' return without trailing return type">; def err_trailing_return_without_auto : Error< "trailing return type without 'auto' return">; - -// C++0x attributes -def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">; // C++0x override control def override_keyword_only_allowed_on_virtual_member_functions : Error< "only virtual member functions can be marked '%0'">; - def err_function_marked_override_not_overriding : Error< "%0 marked 'override' but does not override any member functions">; +def err_class_marked_final_used_as_base : Error< + "base %0 is marked 'final'">; + +// C++0x attributes +def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">; // C++0x [[final]] def err_final_function_overridden : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 6e989ac006..90242e6192 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -884,6 +884,7 @@ public: /// C++ record definition's base-specifiers clause and are starting its /// member declarations. void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl, + ClassVirtSpecifiers &CVS, SourceLocation LBraceLoc); /// ActOnTagFinishDefinition - Invoked once we have finished parsing diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index e2bb751b87..9a23cf1be5 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1772,7 +1772,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation LBraceLoc = ConsumeBrace(); if (TagDecl) - Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, LBraceLoc); + Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, CVS, + LBraceLoc); // C++ 11p3: Members of a class defined with the keyword class are private // by default. Members of a class defined with the keywords struct or union diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a266b60ac3..7c6d9d9142 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -6423,6 +6423,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { } void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, + ClassVirtSpecifiers &CVS, SourceLocation LBraceLoc) { AdjustDeclIfTemplate(TagD); CXXRecordDecl *Record = cast(TagD); @@ -6432,6 +6433,9 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, if (!Record->getIdentifier()) return; + Record->setIsMarkedFinal(CVS.isFinalSpecified()); + Record->setIsMarkedExplicit(CVS.isExplicitSpecified()); + // C++ [class]p2: // [...] The class-name is also inserted into the scope of the // class itself; this is known as the injected-class-name. For diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 2f7640cd61..bf5addc34d 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -521,6 +521,19 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, CXXRecordDecl * CXXBaseDecl = cast(BaseDecl); assert(CXXBaseDecl && "Base type is not a C++ type"); + // C++ [class.derived]p2: + // If a class is marked with the class-virt-specifier final and it appears + // as a base-type-specifier in a base-clause (10 class.derived), the program + // is ill-formed. + if (CXXBaseDecl->isMarkedFinal()) { + Diag(BaseLoc, diag::err_class_marked_final_used_as_base) + << CXXBaseDecl->getDeclName(); + Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl) + << CXXBaseDecl->getDeclName(); + return 0; + } + + // FIXME: Get rid of this. // C++0x CWG Issue #817 indicates that [[final]] classes shouldn't be bases. if (CXXBaseDecl->hasAttr()) { Diag(BaseLoc, diag::err_final_base) << BaseType.getAsString(); diff --git a/test/CXX/class/p2-0x.cpp b/test/CXX/class/p2-0x.cpp new file mode 100644 index 0000000000..1164b8f0a2 --- /dev/null +++ b/test/CXX/class/p2-0x.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++0x +namespace Test1 { + +class A final { }; // expected-note {{'A' declared here}} +class B : A { }; // expected-error {{base 'A' is marked 'final'}} + +} + -- 2.50.1