[cfe-commits] r164590 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticParseKinds.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Parser.h lib/Parse/ParseDeclCXX.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/CodeGenCXX/microsoft-interface.cpp test/SemaCXX/ms-interface.cpp
John McCall
rjmccall at apple.com
Tue Sep 25 00:32:39 PDT 2012
Author: rjmccall
Date: Tue Sep 25 02:32:39 2012
New Revision: 164590
URL: http://llvm.org/viewvc/llvm-project?rev=164590&view=rev
Log:
Fix for r163013 regression and further __interface enhancement.
Patch by Andy Gibbs!
Added:
cfe/trunk/test/CodeGenCXX/microsoft-interface.cpp
cfe/trunk/test/SemaCXX/ms-interface.cpp
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=164590&r1=164589&r2=164590&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Tue Sep 25 02:32:39 2012
@@ -1565,9 +1565,9 @@
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());
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=164590&r1=164589&r2=164590&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Tue Sep 25 02:32:39 2012
@@ -644,6 +644,11 @@
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'">;
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=164590&r1=164589&r2=164590&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Sep 25 02:32:39 2012
@@ -812,6 +812,14 @@
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<
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=164590&r1=164589&r2=164590&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Sep 25 02:32:39 2012
@@ -925,9 +925,9 @@
/// 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 @@
/// 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 @@
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 @@
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 @@
VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const {
return isCXX0XVirtSpecifier(Tok);
}
- void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS);
+ void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS, bool IsInterface);
bool isCXX0XFinalKeyword() const;
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=164590&r1=164589&r2=164590&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Sep 25 02:32:39 2012
@@ -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 @@
/// 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 @@
<< 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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
<< 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 @@
/// 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();
}
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=164590&r1=164589&r2=164590&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Sep 25 02:32:39 2012
@@ -5210,11 +5210,12 @@
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);
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=164590&r1=164589&r2=164590&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Sep 25 02:32:39 2012
@@ -1178,10 +1178,21 @@
// 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 @@
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
Added: cfe/trunk/test/CodeGenCXX/microsoft-interface.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-interface.cpp?rev=164590&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-interface.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/microsoft-interface.cpp Tue Sep 25 02:32:39 2012
@@ -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*)
Added: cfe/trunk/test/SemaCXX/ms-interface.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/ms-interface.cpp?rev=164590&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/ms-interface.cpp (added)
+++ cfe/trunk/test/SemaCXX/ms-interface.cpp Tue Sep 25 02:32:39 2012
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 %s -fsyntax-only -verify -fms-extensions -Wno-microsoft -std=c++11
+
+__interface I1 {
+ // expected-error at +1 {{user-declared constructor is not permitted within an interface type}}
+ I1();
+ // expected-error at +1 {{user-declared destructor is not permitted within an interface type}}
+ ~I1();
+ virtual void fn1() const;
+ // expected-error at +1 {{operator 'operator!' is not permitted within an interface type}}
+ bool operator!();
+ // expected-error at +1 {{operator 'operator int' is not permitted within an interface type}}
+ operator int();
+ // expected-error at +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 at +1 {{data member 'i' is not permitted within an interface type}}
+ int i;
+ // expected-error at +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 at +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 at +1 {{non-public member function 'fn3' is not permitted within an interface type}}
+ void fn3();
+public:
+ void fn4();
+};
+
+// expected-error at +1 {{'final' keyword not permitted with interface types}}
+__interface I3 final {
+};
+
+__interface I4 : I1, I2 {
+ void fn1() const override;
+ // expected-error at +1 {{'final' keyword not permitted with interface types}}
+ void fn2() final;
+};
+
+// expected-error at +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 at 55 {{interface type cannot inherit from 'struct S'}}
+// expected-note at +1 {{in instantiation of template class 'I6<S>' requested here}}
+struct S1 : I6<S> {
+};
+
+// expected-error at 55 {{interface type cannot inherit from 'class C'}}
+// expected-note at +1 {{in instantiation of template class 'I6<C>' requested here}}
+class C1 : I6<C> {
+};
+
+class C2 : I6<I> {
+};
More information about the cfe-commits
mailing list