forked from OSchip/llvm-project
Fix for r163013 regression and further __interface enhancement.
Patch by Andy Gibbs! llvm-svn: 164590
This commit is contained in:
parent
b0433eeb2e
commit
db632ac004
|
@ -1565,9 +1565,9 @@ public:
|
|||
CXXMethodDecl *CD =
|
||||
cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl());
|
||||
|
||||
// Methods declared in interfaces are automatically (pure) virtual
|
||||
// Methods declared in interfaces are automatically (pure) virtual.
|
||||
if (CD->isVirtualAsWritten() ||
|
||||
CD->getParent()->getTagKind() == TTK_Interface)
|
||||
(CD->getParent()->isInterface() && CD->isUserProvided()))
|
||||
return true;
|
||||
|
||||
return (CD->begin_overridden_methods() != CD->end_overridden_methods());
|
||||
|
|
|
@ -644,6 +644,11 @@ def ext_override_control_keyword : ExtWarn<
|
|||
def warn_cxx98_compat_override_control_keyword : Warning<
|
||||
"'%0' keyword is incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
def err_override_control_interface : Error<
|
||||
"'%0' keyword not permitted with interface types">;
|
||||
|
||||
def err_access_specifier_interface : Error<
|
||||
"interface types cannot specify '%select{private|protected}0' access">;
|
||||
|
||||
def err_duplicate_virt_specifier : Error<
|
||||
"class member already marked '%0'">;
|
||||
|
|
|
@ -812,6 +812,14 @@ def err_friend_def_in_local_class : Error<
|
|||
def err_friend_not_first_in_declaration : Error<
|
||||
"'friend' must appear first in a non-function declaration">;
|
||||
|
||||
def err_invalid_member_in_interface : Error<
|
||||
"%select{data member |non-public member function |static member function |"
|
||||
"user-declared constructor|user-declared destructor|operator |"
|
||||
"nested class }0%1 is not permitted within an interface type">;
|
||||
def err_invalid_base_in_interface : Error<
|
||||
"interface type cannot inherit from "
|
||||
"%select{'struct|non-public 'interface|'class}0 %1'">;
|
||||
|
||||
def err_abstract_type_in_decl : Error<
|
||||
"%select{return|parameter|variable|field|instance variable}0 type %1 is an abstract class">;
|
||||
def err_allocation_of_abstract_type : Error<
|
||||
|
|
|
@ -925,9 +925,9 @@ private:
|
|||
/// any member function declarations or definitions that need to be
|
||||
/// parsed after the corresponding top-level class is complete.
|
||||
struct ParsingClass {
|
||||
ParsingClass(Decl *TagOrTemplate, bool TopLevelClass)
|
||||
ParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface)
|
||||
: TopLevelClass(TopLevelClass), TemplateScope(false),
|
||||
TagOrTemplate(TagOrTemplate) { }
|
||||
IsInterface(IsInterface), TagOrTemplate(TagOrTemplate) { }
|
||||
|
||||
/// \brief Whether this is a "top-level" class, meaning that it is
|
||||
/// not nested within another class.
|
||||
|
@ -938,6 +938,9 @@ private:
|
|||
/// othewise, it is a tag declaration.
|
||||
bool TemplateScope : 1;
|
||||
|
||||
/// \brief Whether this class is an __interface.
|
||||
bool IsInterface : 1;
|
||||
|
||||
/// \brief The class or class template whose definition we are parsing.
|
||||
Decl *TagOrTemplate;
|
||||
|
||||
|
@ -964,9 +967,10 @@ private:
|
|||
Sema::ParsingClassState State;
|
||||
|
||||
public:
|
||||
ParsingClassDefinition(Parser &P, Decl *TagOrTemplate, bool TopLevelClass)
|
||||
ParsingClassDefinition(Parser &P, Decl *TagOrTemplate, bool TopLevelClass,
|
||||
bool IsInterface)
|
||||
: P(P), Popped(false),
|
||||
State(P.PushParsingClass(TagOrTemplate, TopLevelClass)) {
|
||||
State(P.PushParsingClass(TagOrTemplate, TopLevelClass, IsInterface)) {
|
||||
}
|
||||
|
||||
/// \brief Pop this class of the stack.
|
||||
|
@ -1054,7 +1058,7 @@ private:
|
|||
void LateTemplateParser(const FunctionDecl *FD);
|
||||
|
||||
Sema::ParsingClassState
|
||||
PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass);
|
||||
PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass, bool IsInterface);
|
||||
void DeallocateParsedClasses(ParsingClass *Class);
|
||||
void PopParsingClass(Sema::ParsingClassState);
|
||||
|
||||
|
@ -1931,7 +1935,7 @@ private:
|
|||
VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const {
|
||||
return isCXX0XVirtSpecifier(Tok);
|
||||
}
|
||||
void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS);
|
||||
void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface);
|
||||
|
||||
bool isCXX0XFinalKeyword() const;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -fms-extensions -Wno-microsoft -triple=i386-pc-win32 -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
__interface I {
|
||||
int test() {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
struct S : I {
|
||||
virtual int test() override {
|
||||
return I::test();
|
||||
}
|
||||
};
|
||||
|
||||
int fn() {
|
||||
S s;
|
||||
return s.test();
|
||||
}
|
||||
|
||||
// CHECK: @_ZTV1S = linkonce_odr unnamed_addr constant [3 x i8*] [i8* null, i8* bitcast ({ i8*, i8*, i8* }* @_ZTI1S to i8*), i8* bitcast (i32 (%struct.S*)* @_ZN1S4testEv to i8*)]
|
||||
|
||||
// CHECK: define i32 @_Z2fnv()
|
||||
// CHECK: call void @_ZN1SC1Ev(%struct.S* %s)
|
||||
// CHECK: %call = call i32 @_ZN1S4testEv(%struct.S* %s)
|
||||
|
||||
// CHECK: define linkonce_odr void @_ZN1SC1Ev(%struct.S* %this)
|
||||
// CHECK: call void @_ZN1SC2Ev(%struct.S* %this1)
|
||||
|
||||
// CHECK: define linkonce_odr i32 @_ZN1S4testEv(%struct.S* %this)
|
||||
// CHECK: %call = call i32 @_ZN1I4testEv(%__interface.I* %0)
|
||||
|
||||
// CHECK: define linkonce_odr i32 @_ZN1I4testEv(%__interface.I* %this)
|
||||
// CHECK: ret i32 1
|
||||
|
||||
// CHECK: define linkonce_odr void @_ZN1SC2Ev(%struct.S* %this)
|
||||
// CHECK: call void @_ZN1IC2Ev(%__interface.I* %0)
|
||||
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1S, i64 0, i64 2), i8*** %1
|
||||
|
||||
// CHECK: define linkonce_odr void @_ZN1IC2Ev(%__interface.I* %this)
|
||||
// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1I, i64 0, i64 2), i8*** %0
|
||||
|
||||
// CHECK-NOT: define linkonce_odr %__interface.I* @_ZN1IaSERKS_(%__interface.I* %this, %__interface.I*)
|
||||
// CHECK-NOT: define linkonce_odr %__interface.I* @_ZN1IaSEOS_(%__interface.I* %this, %__interface.I*)
|
|
@ -0,0 +1,73 @@
|
|||
// RUN: %clang_cc1 %s -fsyntax-only -verify -fms-extensions -Wno-microsoft -std=c++11
|
||||
|
||||
__interface I1 {
|
||||
// expected-error@+1 {{user-declared constructor is not permitted within an interface type}}
|
||||
I1();
|
||||
// expected-error@+1 {{user-declared destructor is not permitted within an interface type}}
|
||||
~I1();
|
||||
virtual void fn1() const;
|
||||
// expected-error@+1 {{operator 'operator!' is not permitted within an interface type}}
|
||||
bool operator!();
|
||||
// expected-error@+1 {{operator 'operator int' is not permitted within an interface type}}
|
||||
operator int();
|
||||
// expected-error@+1 {{nested class I1::<anonymous> is not permitted within an interface type}}
|
||||
struct { int a; };
|
||||
void fn2() {
|
||||
struct A { }; // should be ignored: not a nested class
|
||||
}
|
||||
protected: // expected-error {{interface types cannot specify 'protected' access}}
|
||||
typedef void void_t;
|
||||
using int_t = int;
|
||||
private: // expected-error {{interface types cannot specify 'private' access}}
|
||||
static_assert(true, "oops");
|
||||
};
|
||||
|
||||
__interface I2 {
|
||||
// expected-error@+1 {{data member 'i' is not permitted within an interface type}}
|
||||
int i;
|
||||
// expected-error@+1 {{static member function 'fn1' is not permitted within an interface type}}
|
||||
static int fn1();
|
||||
private: // expected-error {{interface types cannot specify 'private' access}}
|
||||
// expected-error@+1 {{non-public member function 'fn2' is not permitted within an interface type}}
|
||||
void fn2();
|
||||
protected: // expected-error {{interface types cannot specify 'protected' access}}
|
||||
// expected-error@+1 {{non-public member function 'fn3' is not permitted within an interface type}}
|
||||
void fn3();
|
||||
public:
|
||||
void fn4();
|
||||
};
|
||||
|
||||
// expected-error@+1 {{'final' keyword not permitted with interface types}}
|
||||
__interface I3 final {
|
||||
};
|
||||
|
||||
__interface I4 : I1, I2 {
|
||||
void fn1() const override;
|
||||
// expected-error@+1 {{'final' keyword not permitted with interface types}}
|
||||
void fn2() final;
|
||||
};
|
||||
|
||||
// expected-error@+1 {{interface type cannot inherit from non-public 'interface I1'}}
|
||||
__interface I5 : private I1 {
|
||||
};
|
||||
|
||||
template <typename X>
|
||||
__interface I6 : X {
|
||||
};
|
||||
|
||||
struct S { };
|
||||
class C { };
|
||||
__interface I { };
|
||||
|
||||
// expected-error@55 {{interface type cannot inherit from 'struct S'}}
|
||||
// expected-note@+1 {{in instantiation of template class 'I6<S>' requested here}}
|
||||
struct S1 : I6<S> {
|
||||
};
|
||||
|
||||
// expected-error@55 {{interface type cannot inherit from 'class C'}}
|
||||
// expected-note@+1 {{in instantiation of template class 'I6<C>' requested here}}
|
||||
class C1 : I6<C> {
|
||||
};
|
||||
|
||||
class C2 : I6<I> {
|
||||
};
|
Loading…
Reference in New Issue