diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 56 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 63 |
3 files changed, 108 insertions, 22 deletions
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 64a3ef0deb..6fee37dc02 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -18,6 +18,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/PrettyDeclStackTrace.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallString.h" #include "RAIIObjectsForParser.h" using namespace clang; @@ -1668,7 +1669,8 @@ VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const { /// virt-specifier-seq: /// virt-specifier /// virt-specifier-seq virt-specifier -void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { +void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS, + bool IsInterface) { while (true) { VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier(); if (Specifier == VirtSpecifiers::VS_None) @@ -1682,10 +1684,15 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); - Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_override_control_keyword : - diag::ext_override_control_keyword) - << VirtSpecifiers::getSpecifierName(Specifier); + if (IsInterface && Specifier == VirtSpecifiers::VS_Final) { + Diag(Tok.getLocation(), diag::err_override_control_interface) + << VirtSpecifiers::getSpecifierName(Specifier); + } else { + Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_override_control_keyword : + diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); + } ConsumeToken(); } } @@ -1906,7 +1913,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } - ParseOptionalCXX0XVirtSpecifierSeq(VS); + ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface); // If attributes exist after the declarator, but before an '{', parse them. MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); @@ -2027,7 +2034,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // FIXME: When g++ adds support for this, we'll need to check whether it // goes before or after the GNU attributes and __asm__. - ParseOptionalCXX0XVirtSpecifierSeq(VS); + ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface); InClassInitStyle HasInClassInit = ICIS_NoInit; if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { @@ -2256,6 +2263,15 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (S->isClassScope()) { // We're inside a class scope, so this is a nested class. NonNestedClass = false; + + // The Microsoft extension __interface does not permit nested classes. + if (getCurrentClass().IsInterface) { + Diag(RecordLoc, diag::err_invalid_member_in_interface) + << /*ErrorType=*/6 + << (isa<NamedDecl>(TagDecl) + ? cast<NamedDecl>(TagDecl)->getQualifiedNameAsString() + : "<anonymous>"); + } break; } @@ -2276,7 +2292,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope); // Note that we are parsing a new (potentially-nested) class definition. - ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass); + ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass, + TagType == DeclSpec::TST_interface); if (TagDecl) Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); @@ -2288,9 +2305,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, assert(isCXX0XFinalKeyword() && "not a class definition"); FinalLoc = ConsumeToken(); - Diag(FinalLoc, getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_override_control_keyword : - diag::ext_override_control_keyword) << "final"; + if (TagType == DeclSpec::TST_interface) { + Diag(FinalLoc, diag::err_override_control_interface) + << "final"; + } else { + Diag(FinalLoc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_override_control_keyword : + diag::ext_override_control_keyword) << "final"; + } } if (Tok.is(tok::colon)) { @@ -2375,6 +2397,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, << FixItHint::CreateInsertion(EndLoc, ":"); } + // The Microsoft extension __interface does not permit non-public + // access specifiers. + if (TagType == DeclSpec::TST_interface && CurAS != AS_public) { + Diag(ASLoc, diag::err_access_specifier_interface) + << (CurAS == AS_protected); + } + if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc, AccessAttrs.getList())) { // found another attribute than only annotations @@ -2754,10 +2783,11 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) { /// so push that class onto our stack of classes that is currently /// being parsed. Sema::ParsingClassState -Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass) { +Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass, + bool IsInterface) { assert((NonNestedClass || !ClassStack.empty()) && "Nested class without outer class"); - ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass)); + ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass, IsInterface)); return Actions.PushParsingClass(); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index fc2d1d6ae6..01aaf8be32 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5210,11 +5210,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setImplicitlyInline(); } - // if this is a method defined in an __interface, set pure - // (isVirtual will already return true) - if (CXXRecordDecl *Parent = dyn_cast<CXXRecordDecl>( - NewFD->getDeclContext())) { - if (Parent->getTagKind() == TTK_Interface) + // If this is a method defined in an __interface, and is not a constructor + // or an overloaded operator, then set the pure flag (isVirtual will already + // return true). + if (const CXXRecordDecl *Parent = + dyn_cast<CXXRecordDecl>(NewFD->getDeclContext())) { + if (Parent->isInterface() && cast<CXXMethodDecl>(NewFD)->isUserProvided()) NewFD->setPure(true); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a4ddba3740..dccce6ef90 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1178,10 +1178,21 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, // Okay, add this new base class. KnownBase = Bases[idx]; Bases[NumGoodBases++] = Bases[idx]; - if (const RecordType *Record = NewBaseType->getAs<RecordType>()) - if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl())) - if (RD->hasAttr<WeakAttr>()) - Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context)); + if (const RecordType *Record = NewBaseType->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); + if (Class->isInterface() && + (!RD->isInterface() || + KnownBase->getAccessSpecifier() != AS_public)) { + // The Microsoft extension __interface does not permit bases that + // are not themselves public interfaces. + Diag(KnownBase->getLocStart(), diag::err_invalid_base_in_interface) + << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getName() + << RD->getSourceRange(); + Invalid = true; + } + if (RD->hasAttr<WeakAttr>()) + Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context)); + } } } @@ -1512,6 +1523,50 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, bool isFunc = D.isDeclarationOfFunction(); + if (cast<CXXRecordDecl>(CurContext)->isInterface()) { + // The Microsoft extension __interface only permits public member functions + // and prohibits constructors, destructors, operators, non-public member + // functions, static methods and data members. + unsigned InvalidDecl; + bool ShowDeclName = true; + if (!isFunc) + InvalidDecl = (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) ? 0 : 1; + else if (AS != AS_public) + InvalidDecl = 2; + else if (DS.getStorageClassSpec() == DeclSpec::SCS_static) + InvalidDecl = 3; + else switch (Name.getNameKind()) { + case DeclarationName::CXXConstructorName: + InvalidDecl = 4; + ShowDeclName = false; + break; + + case DeclarationName::CXXDestructorName: + InvalidDecl = 5; + ShowDeclName = false; + break; + + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXConversionFunctionName: + InvalidDecl = 6; + break; + + default: + InvalidDecl = 0; + break; + } + + if (InvalidDecl) { + if (ShowDeclName) + Diag(Loc, diag::err_invalid_member_in_interface) + << (InvalidDecl-1) << Name; + else + Diag(Loc, diag::err_invalid_member_in_interface) + << (InvalidDecl-1) << ""; + return 0; + } + } + // C++ 9.2p6: A member shall not be declared to have automatic storage // duration (auto, register) or with the extern storage-class-specifier. // C++ 7.1.1p8: The mutable specifier can be applied only to names of class |