diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index c9db43bbb4dcfb441f5bb1e8e067188ca4fe0442..2fc4d587643790bf82aed3069fe0193e0baa5c97 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -395,7 +395,8 @@ def FastCall : InheritableAttr { } def Final : InheritableAttr { - let Spellings = []; + let Spellings = [Keyword<"final">, Keyword<"sealed">]; + let Accessors = [Accessor<"isSpelledAsSealed", [Keyword<"sealed">]>]; let SemaHandler = 0; } diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index b470bb4e78e5ac06dbcd3a2c6cb57e12c5a0fc79..774e9e9acb58c45d034be684fa25c64fd39609ac 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -704,6 +704,9 @@ def warn_cxx98_compat_override_control_keyword : Warning< InGroup<CXX98Compat>, DefaultIgnore; def err_override_control_interface : Error< "'%0' keyword not permitted with interface types">; +def ext_ms_sealed_keyword : ExtWarn< + "'sealed' keyword is a Microsoft extension">, + InGroup<Microsoft>; def err_access_specifier_interface : Error< "interface types cannot specify '%select{private|protected}0' access">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 9d6ea40c69338090fbf2123971c41a85df377a6b..d8fef68d48c401878535c6e76ed62fe0e1324627 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1552,16 +1552,16 @@ def override_keyword_hides_virtual_member_function : Error< 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'">; + "base %0 is marked '%select{final|sealed}1'">; def warn_abstract_final_class : Warning< - "abstract class is marked 'final'">, InGroup<AbstractFinalClass>; + "abstract class is marked '%select{final|sealed}0'">, InGroup<AbstractFinalClass>; // C++11 attributes def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">; // C++11 final def err_final_function_overridden : Error< - "declaration of %0 overrides a 'final' function">; + "declaration of %0 overrides a '%select{final|sealed}1' function">; // C++11 scoped enumerations def err_enum_invalid_underlying : Error< diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index d7636321648a4b89cff1537aefea6d0be558715a..d995985dc3ea1b614fd14aa64fa088a92c563075 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -350,6 +350,7 @@ KEYWORD(typeof , KEYGNU) // MS Extensions KEYWORD(L__FUNCTION__ , KEYMS) +KEYWORD(__is_sealed , KEYMS) // GNU and MS Type Traits KEYWORD(__has_nothrow_assign , KEYCXX) diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h index 16457969862aa46bfd8dc304d26b186f46b8e0b5..fc53527188bba31368d988fff9e466b48eabba68 100644 --- a/include/clang/Basic/TypeTraits.h +++ b/include/clang/Basic/TypeTraits.h @@ -57,6 +57,7 @@ namespace clang { UTT_IsReference, UTT_IsRvalueReference, UTT_IsScalar, + UTT_IsSealed, UTT_IsSigned, UTT_IsStandardLayout, UTT_IsTrivial, diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index fd69192aecea42cd6ed8230b3aadb0455954751b..1fd1d866b239b7ecf60f1c931be473aebb52b654 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -102,6 +102,7 @@ class Parser : public CodeCompletionHandler { /// Contextual keywords for Microsoft extensions. IdentifierInfo *Ident__except; + mutable IdentifierInfo *Ident_sealed; /// Ident_super - IdentifierInfo for "super", to support fast /// comparison. diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index a21bb3094b60c181a7c31dc6f836850ee4a2fc28..773e31edbdb6579b36760b1c5b84ddb9a9a4b420 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -2107,7 +2107,8 @@ public: enum Specifier { VS_None = 0, VS_Override = 1, - VS_Final = 2 + VS_Final = 2, + VS_Sealed = 4 }; VirtSpecifiers() : Specifiers(0) { } @@ -2118,7 +2119,8 @@ public: bool isOverrideSpecified() const { return Specifiers & VS_Override; } SourceLocation getOverrideLoc() const { return VS_overrideLoc; } - bool isFinalSpecified() const { return Specifiers & VS_Final; } + bool isFinalSpecified() const { return Specifiers & (VS_Final | VS_Sealed); } + bool isFinalSpelledSealed() const { return Specifiers & VS_Sealed; } SourceLocation getFinalLoc() const { return VS_finalLoc; } void clear() { Specifiers = 0; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index f5a93d442ca952466b4dd2c39cdda3b976c025ad..769998012310affc90d130c7574e914d76c2f075 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1725,6 +1725,7 @@ public: /// member declarations. void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl, SourceLocation FinalLoc, + bool IsFinalSpelledSealed, SourceLocation LBraceLoc); /// ActOnTagFinishDefinition - Invoked once we have finished parsing diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 55cfd3f813494d4dc86c9ea481bf6ee0a6ff9b03..29e8e9f97f9fdb1c38521076bda964104f99c13c 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1712,6 +1712,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) { case UTT_IsReference: return "__is_reference"; case UTT_IsRvalueReference: return "__is_rvalue_reference"; case UTT_IsScalar: return "__is_scalar"; + case UTT_IsSealed: return "__is_sealed"; case UTT_IsSigned: return "__is_signed"; case UTT_IsStandardLayout: return "__is_standard_layout"; case UTT_IsTrivial: return "__is_trivial"; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 9c998eac2a572f73b1e6411800343bd192fd4d99..f20633fda8c9ec887e82f95f949e1c83d61bd1d0 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -983,6 +983,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("is_standard_layout", LangOpts.CPlusPlus) .Case("is_pod", LangOpts.CPlusPlus) .Case("is_polymorphic", LangOpts.CPlusPlus) + .Case("is_sealed", LangOpts.MicrosoftExt) .Case("is_trivial", LangOpts.CPlusPlus) .Case("is_trivially_assignable", LangOpts.CPlusPlus) .Case("is_trivially_constructible", LangOpts.CPlusPlus) diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 21b24bfd79eb6893b639b05b28e939cdb1b24445..4625745c5e2f33e1e787f98c3b255c3936ec457e 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1837,12 +1837,17 @@ VirtSpecifiers::Specifier Parser::isCXX11VirtSpecifier(const Token &Tok) const { // Initialize the contextual keywords. if (!Ident_final) { Ident_final = &PP.getIdentifierTable().get("final"); + if (getLangOpts().MicrosoftExt) + Ident_sealed = &PP.getIdentifierTable().get("sealed"); Ident_override = &PP.getIdentifierTable().get("override"); } if (II == Ident_override) return VirtSpecifiers::VS_Override; + if (II == Ident_sealed) + return VirtSpecifiers::VS_Sealed; + if (II == Ident_final) return VirtSpecifiers::VS_Final; } @@ -1870,14 +1875,18 @@ void Parser::ParseOptionalCXX11VirtSpecifierSeq(VirtSpecifiers &VS, << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); - if (IsInterface && Specifier == VirtSpecifiers::VS_Final) { + if (IsInterface && (Specifier == VirtSpecifiers::VS_Final || + Specifier == VirtSpecifiers::VS_Sealed)) { Diag(Tok.getLocation(), diag::err_override_control_interface) << VirtSpecifiers::getSpecifierName(Specifier); + } else if (Specifier == VirtSpecifiers::VS_Sealed) { + Diag(Tok.getLocation(), diag::ext_ms_sealed_keyword); } else { - Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_override_control_keyword : - diag::ext_override_control_keyword) - << VirtSpecifiers::getSpecifierName(Specifier); + Diag(Tok.getLocation(), + getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_override_control_keyword + : diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); } ConsumeToken(); } @@ -1895,10 +1904,13 @@ bool Parser::isCXX11FinalKeyword() const { // Initialize the contextual keywords. if (!Ident_final) { Ident_final = &PP.getIdentifierTable().get("final"); + if (getLangOpts().MicrosoftExt) + Ident_sealed = &PP.getIdentifierTable().get("sealed"); Ident_override = &PP.getIdentifierTable().get("override"); } - - return Tok.getIdentifierInfo() == Ident_final; + + return Tok.getIdentifierInfo() == Ident_final || + Tok.getIdentifierInfo() == Ident_sealed; } /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. @@ -1929,6 +1941,7 @@ bool Parser::isCXX11FinalKeyword() const { /// virt-specifier: /// override /// final +/// [MS] sealed /// /// pure-specifier: /// '= 0' @@ -2520,20 +2533,27 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); SourceLocation FinalLoc; + bool IsFinalSpelledSealed = false; // Parse the optional 'final' keyword. if (getLangOpts().CPlusPlus && Tok.is(tok::identifier)) { - assert(isCXX11FinalKeyword() && "not a class definition"); + VirtSpecifiers::Specifier Specifier = isCXX11VirtSpecifier(Tok); + assert((Specifier == VirtSpecifiers::VS_Final || + Specifier == VirtSpecifiers::VS_Sealed) && + "not a class definition"); FinalLoc = ConsumeToken(); + IsFinalSpelledSealed = Specifier == VirtSpecifiers::VS_Sealed; - if (TagType == DeclSpec::TST_interface) { + if (TagType == DeclSpec::TST_interface) Diag(FinalLoc, diag::err_override_control_interface) - << "final"; - } else { - Diag(FinalLoc, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_override_control_keyword : - diag::ext_override_control_keyword) << "final"; - } + << VirtSpecifiers::getSpecifierName(Specifier); + else if (Specifier == VirtSpecifiers::VS_Final) + Diag(FinalLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_override_control_keyword + : diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); + else if (Specifier == VirtSpecifiers::VS_Sealed) + Diag(FinalLoc, diag::ext_ms_sealed_keyword); // Parse any C++11 attributes after 'final' keyword. // These attributes are not allowed to appear here, @@ -2560,6 +2580,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc, + IsFinalSpelledSealed, T.getOpenLocation()); // C++ 11p3: Members of a class defined with the keyword class are private diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index a82d5cea63590146ef63b73d67315ecef092b6e1..8867b08e4ff252dbac182bc75a0862c613a7e25c 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -591,6 +591,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// '__is_final' /// '__is_pod' /// '__is_polymorphic' +/// '__is_sealed' [MS] /// '__is_trivial' /// '__is_union' /// @@ -1200,6 +1201,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_trivially_copyable: case tok::kw___is_union: case tok::kw___is_final: + case tok::kw___is_sealed: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_move_constructor: case tok::kw___has_trivial_copy: diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index e9a5a88c7606ed496e288506ee039faf5a963ca8..4dd63e3763b81c69a8e66809df171dc1b122b7fa 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -2669,6 +2669,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___is_reference: return UTT_IsReference; case tok::kw___is_rvalue_reference: return UTT_IsRvalueReference; case tok::kw___is_scalar: return UTT_IsScalar; + case tok::kw___is_sealed: return UTT_IsSealed; case tok::kw___is_signed: return UTT_IsSigned; case tok::kw___is_standard_layout: return UTT_IsStandardLayout; case tok::kw___is_trivial: return UTT_IsTrivial; diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 7d1475c3a6b6b2c987ce8e6b166b65ac0e8fc287..2dc16d3b0b2491fe142356e9acf87d1fe6a185a5 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -962,6 +962,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_literal_type: case tok::kw___is_pod: case tok::kw___is_polymorphic: + case tok::kw___is_sealed: case tok::kw___is_trivial: case tok::kw___is_trivially_assignable: case tok::kw___is_trivially_constructible: diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f0a3d9190c391857b3ffe53c574034fab56044be..9b6c97ac195fb06071b8a83d20dd757edadb67db 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -486,6 +486,7 @@ void Parser::Initialize() { Ident_instancetype = 0; Ident_final = 0; + Ident_sealed = 0; Ident_override = 0; Ident_super = &PP.getIdentifierTable().get("super"); diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 5d4fce787ee5a19a7604fd6225200083dd691681..46914f68040299318b6c40bbdb48e1b950938ada 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -1118,6 +1118,7 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, switch (VS) { default: llvm_unreachable("Unknown specifier!"); case VS_Override: VS_overrideLoc = Loc; break; + case VS_Sealed: case VS_Final: VS_finalLoc = Loc; break; } @@ -1129,5 +1130,6 @@ const char *VirtSpecifiers::getSpecifierName(Specifier VS) { default: llvm_unreachable("Unknown specifier"); case VS_Override: return "override"; case VS_Final: return "final"; + case VS_Sealed: return "sealed"; } } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f56ef429329dd85ff19863e0201a853f607c07a8..632cc19c4854ebfcd39f8d1142eaf3733204cb8e 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -10957,6 +10957,7 @@ Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, SourceLocation FinalLoc, + bool IsFinalSpelledSealed, SourceLocation LBraceLoc) { AdjustDeclIfTemplate(TagD); CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD); @@ -10967,8 +10968,9 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, return; if (FinalLoc.isValid()) - Record->addAttr(new (Context) FinalAttr(FinalLoc, Context)); - + Record->addAttr(new (Context) + FinalAttr(FinalLoc, Context, IsFinalSpelledSealed)); + // 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 bd864b3adbc77bb4b2ac8ec72f59691a640cb9d8..81283e1f7825091c7d6bcf91fa0fbf75015af714 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1373,9 +1373,10 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // C++ [class]p3: // If a class is marked final and it appears as a base-type-specifier in // base-clause, the program is ill-formed. - if (CXXBaseDecl->hasAttr<FinalAttr>()) { + if (FinalAttr *FA = CXXBaseDecl->getAttr<FinalAttr>()) { Diag(BaseLoc, diag::err_class_marked_final_used_as_base) - << CXXBaseDecl->getDeclName(); + << CXXBaseDecl->getDeclName() + << FA->isSpelledAsSealed(); Diag(CXXBaseDecl->getLocation(), diag::note_previous_decl) << CXXBaseDecl->getDeclName(); return 0; @@ -1762,7 +1763,8 @@ void Sema::CheckOverrideControl(NamedDecl *D) { } else if (FinalAttr *FA = D->getAttr<FinalAttr>()) { Diag(FA->getLocation(), diag::override_keyword_hides_virtual_member_function) - << "final" << (OverloadedMethods.size() > 1); + << (FA->isSpelledAsSealed() ? "sealed" : "final") + << (OverloadedMethods.size() > 1); } NoteHiddenVirtualMethods(MD, OverloadedMethods); MD->setInvalidDecl(); @@ -1782,7 +1784,8 @@ void Sema::CheckOverrideControl(NamedDecl *D) { if (FinalAttr *FA = D->getAttr<FinalAttr>()) { Diag(FA->getLocation(), diag::override_keyword_only_allowed_on_virtual_member_functions) - << "final" << FixItHint::CreateRemoval(FA->getLocation()); + << (FA->isSpelledAsSealed() ? "sealed" : "final") + << FixItHint::CreateRemoval(FA->getLocation()); D->dropAttr<FinalAttr>(); } return; @@ -1804,11 +1807,13 @@ void Sema::CheckOverrideControl(NamedDecl *D) { /// C++11 [class.virtual]p4. bool Sema::CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - if (!Old->hasAttr<FinalAttr>()) + FinalAttr *FA = Old->getAttr<FinalAttr>(); + if (!FA) return false; Diag(New->getLocation(), diag::err_final_function_overridden) - << New->getDeclName(); + << New->getDeclName() + << FA->isSpelledAsSealed(); Diag(Old->getLocation(), diag::note_overridden_virtual_function); return true; } @@ -2067,7 +2072,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, if (VS.isOverrideSpecified()) Member->addAttr(new (Context) OverrideAttr(VS.getOverrideLoc(), Context)); if (VS.isFinalSpecified()) - Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context)); + Member->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context, + VS.isFinalSpelledSealed())); if (VS.getLastLocation().isValid()) { // Update the end location of a method that has a virt-specifiers. @@ -4406,9 +4412,12 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { diag::warn_non_virtual_dtor) << Context.getRecordType(Record); } - if (Record->isAbstract() && Record->hasAttr<FinalAttr>()) { - Diag(Record->getLocation(), diag::warn_abstract_final_class); - DiagnoseAbstractType(Record); + if (Record->isAbstract()) { + if (FinalAttr *FA = Record->getAttr<FinalAttr>()) { + Diag(Record->getLocation(), diag::warn_abstract_final_class) + << FA->isSpelledAsSealed(); + DiagnoseAbstractType(Record); + } } if (!Record->isDependentType()) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 837d383a1bb6d52f10068dd44e11e8ed0c69fdbe..323cd265e6c9aa9e3e543334379d03fb002f1025 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -3131,6 +3131,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, // These traits require a complete type. case UTT_IsFinal: + case UTT_IsSealed: // These trait expressions are designed to help implement predicates in // [meta.unary.prop] despite not being named the same. They are specified @@ -3304,6 +3305,11 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasAttr<FinalAttr>(); return false; + case UTT_IsSealed: + if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + if (FinalAttr *FA = RD->getAttr<FinalAttr>()) + return FA->isSpelledAsSealed(); + return false; case UTT_IsSigned: return T->isSignedIntegerType(); case UTT_IsUnsigned: diff --git a/test/SemaCXX/MicrosoftExtensions.cpp b/test/SemaCXX/MicrosoftExtensions.cpp index 723beb4efca70106c95a2b66dc2d5042f82d4c6b..c5b45a2905c8bbf3e2fddaf1e52502ebc2f63257 100644 --- a/test/SemaCXX/MicrosoftExtensions.cpp +++ b/test/SemaCXX/MicrosoftExtensions.cpp @@ -385,3 +385,28 @@ namespace rdar14250378 { } } } + +// expected-error@+1 {{'sealed' keyword not permitted with interface types}} +__interface InterfaceWithSealed sealed { +}; + +struct SomeBase { + virtual void OverrideMe(); + + // expected-note@+2 {{overridden virtual function is here}} + // expected-warning@+1 {{'sealed' keyword is a Microsoft extension}} + virtual void SealedFunction() sealed; +}; + +// expected-note@+2 {{'SealedType' declared here}} +// expected-warning@+1 {{'sealed' keyword is a Microsoft extension}} +struct SealedType sealed : SomeBase { + // expected-error@+1 {{declaration of 'SealedFunction' overrides a 'sealed' function}} + virtual void SealedFunction(); + + // expected-warning@+1 {{'override' keyword is a C++11 extension}} + virtual void OverrideMe() override; +}; + +// expected-error@+1 {{base 'SealedType' is marked 'sealed'}} +struct InheritFromSealed : SealedType {}; diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index d73b2d8995301d08af3131a23fec1ea36ca15357..3e479215838e4dcbf5e2e2dcf5fdd1c41577a0ae 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fms-extensions -Wno-microsoft %s #define T(b) (b) ? 1 : -1 #define F(b) (b) ? -1 : 1 @@ -308,6 +308,37 @@ void is_final() { int arr[F(__is_final(PotentiallyFinal<float>))]; } } +struct SealedClass sealed { +}; + +template<typename T> +struct PotentiallySealed { }; + +template<typename T> +struct PotentiallySealed<T*> sealed { }; + +template<> +struct PotentiallySealed<int> sealed { }; + +void is_sealed() +{ + { int arr[T(__is_sealed(SealedClass))]; } + { int arr[T(__is_sealed(PotentiallySealed<float*>))]; } + { int arr[T(__is_sealed(PotentiallySealed<int>))]; } + + { int arr[F(__is_sealed(int))]; } + { int arr[F(__is_sealed(Union))]; } + { int arr[F(__is_sealed(Int))]; } + { int arr[F(__is_sealed(IntAr))]; } + { int arr[F(__is_sealed(UnionAr))]; } + { int arr[F(__is_sealed(Derives))]; } + { int arr[F(__is_sealed(ClassType))]; } + { int arr[F(__is_sealed(cvoid))]; } + { int arr[F(__is_sealed(IntArNB))]; } + { int arr[F(__is_sealed(HasAnonymousUnion))]; } + { int arr[F(__is_sealed(PotentiallyFinal<float>))]; } +} + typedef HasVirt Polymorph; struct InheritPolymorph : Polymorph {};