aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Parse/ParseDeclCXX.cpp56
-rw-r--r--lib/Sema/SemaDecl.cpp11
-rw-r--r--lib/Sema/SemaDeclCXX.cpp63
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