[cfe-dev] [PATCH] extend __interface support

David Robins llvm at davidrobins.net
Sun Aug 12 23:50:33 PDT 2012


Please find attached a patch that extends the support for the
Microsoft-specific __interface keyword, currently supported as an alias
for struct. I do not have commit access, and if this were to be accepted
I would need someone to commit it for me.

This patch adds the semantics of making all member functions defined in
the interface into pure virtuals, as MSVC does
(http://msdn.microsoft.com/en-us/library/50h7kwtb%28v=vs.100%29.aspx).

It is implemented as a keyword which translates to struct with a new
MS-specific attribute "ms_interface", which causes member functions to
be set to pure virtual (it is not an error to declare either on top of
the automatic setting; additional pure/virtual specifiers are ignored as
in MSVC).

The MicrosoftExtension.cpp test is also updated to do an override of a
base interface method not explicitly declared virtual, which would fail
without this change.

Thank you for your comments/consideration.
-------------- next part --------------
Index: test/Parser/MicrosoftExtensions.cpp
===================================================================
--- test/Parser/MicrosoftExtensions.cpp	(revision 161741)
+++ test/Parser/MicrosoftExtensions.cpp	(working copy)
@@ -174,13 +174,21 @@
 
 __interface MicrosoftInterface;
 __interface MicrosoftInterface {
-   virtual void foo1() = 0;
+   void foo1() = 0;
    virtual void foo2() = 0;
 };
 
+__interface MicrosoftDerivedInterface : public MicrosoftInterface {
+  void foo1();
+  void foo2() override;
+  void foo3();
+};
+
 void interface_test() {
   MicrosoftInterface* a;
   a->foo1();
+  MicrosoftDerivedInterface* b;
+  b->foo2();
 }
 
 __int64 x7 = __int64(0);
Index: include/clang/Basic/Attr.td
===================================================================
--- include/clang/Basic/Attr.td	(revision 161741)
+++ include/clang/Basic/Attr.td	(working copy)
@@ -832,6 +832,11 @@
   let Spellings = [Declspec<"ms_struct">];
 }
 
+def MsInterface : InheritableAttr {
+  let Spellings = [Declspec<"ms_interface">];
+  let Subjects = [CXXRecord];
+}
+
 def DLLExport : InheritableAttr {
   let Spellings = [Declspec<"dllexport">];
 }
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def	(revision 161741)
+++ include/clang/Basic/TokenKinds.def	(working copy)
@@ -505,6 +505,7 @@
 KEYWORD(__single_inheritance          , KEYMS)
 KEYWORD(__multiple_inheritance        , KEYMS)
 KEYWORD(__virtual_inheritance         , KEYMS)
+KEYWORD(__interface                   , KEYMS)
 ALIAS("__int8"           , char       , KEYMS)
 ALIAS("__int16"          , short      , KEYMS)
 ALIAS("__int32"          , int        , KEYMS)
@@ -518,7 +519,6 @@
 ALIAS("_uuidof"          , __uuidof   , KEYMS | KEYBORLAND)
 ALIAS("_inline"          , inline     , KEYMS)
 ALIAS("_declspec"        , __declspec , KEYMS)
-ALIAS("__interface"      , struct     , KEYMS)
 
 // Borland Extensions which should be disabled in strict conformance mode.
 ALIAS("_pascal"      , __pascal   , KEYBORLAND)
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp	(revision 161741)
+++ lib/Sema/SemaDeclAttr.cpp	(working copy)
@@ -932,6 +932,13 @@
     S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
 }
 
+static void handleMsInterfaceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+  if (TagDecl *TD = dyn_cast<TagDecl>(D))
+    TD->addAttr(::new (S.Context) MsInterfaceAttr(Attr.getRange(), S.Context));
+  else
+    S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+}
+
 static void handleIBAction(Sema &S, Decl *D, const AttributeList &Attr) {
   // check the attribute arguments.
   if (!checkAttributeNumArgs(S, Attr, 0))
@@ -4257,6 +4264,9 @@
   case AttributeList::AT_MsStruct:
     handleMsStructAttr(S, D, Attr);
     break;
+  case AttributeList::AT_MsInterface:
+    handleMsInterfaceAttr(S, D, Attr);
+    break;
   case AttributeList::AT_Uuid:
     handleUuidAttr(S, D, Attr);
     break;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 161741)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -5138,6 +5138,16 @@
       NewFD->setImplicitlyInline();
     }
 
+    // if this is a method defined in an __interface, set pure virtual
+    if (CXXRecordDecl *Parent = dyn_cast<CXXRecordDecl>(NewFD->getDeclContext())) {
+      if (Parent->hasAttr<MsInterfaceAttr>()) {
+        const char *PrevSpec = 0;
+        unsigned DiagID = 0;
+        NewFD->setVirtualAsWritten(true);
+        NewFD->setPure(true);
+      }
+    }
+
     SetNestedNameSpecifier(NewFD, D);
     isExplicitSpecialization = false;
     isFunctionTemplateSpecialization = false;
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp	(revision 161741)
+++ lib/Parse/ParseDecl.cpp	(working copy)
@@ -2637,6 +2637,7 @@
     // class-specifier:
     case tok::kw_class:
     case tok::kw_struct:
+    case tok::kw___interface:
     case tok::kw_union: {
       tok::TokenKind Kind = Tok.getKind();
       ConsumeToken();
@@ -3457,6 +3458,7 @@
     // struct-or-union-specifier (C99) or class-specifier (C++)
   case tok::kw_class:
   case tok::kw_struct:
+  case tok::kw___interface:
   case tok::kw_union:
     // enum-specifier
   case tok::kw_enum:
@@ -3528,6 +3530,7 @@
     // struct-or-union-specifier (C99) or class-specifier (C++)
   case tok::kw_class:
   case tok::kw_struct:
+  case tok::kw___interface:
   case tok::kw_union:
     // enum-specifier
   case tok::kw_enum:
@@ -3666,6 +3669,7 @@
   case tok::kw_class:
   case tok::kw_struct:
   case tok::kw_union:
+  case tok::kw___interface:
     // enum-specifier
   case tok::kw_enum:
 
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp	(revision 161741)
+++ lib/Parse/ParseDeclCXX.cpp	(working copy)
@@ -1032,7 +1032,7 @@
                                  AccessSpecifier AS, 
                                  bool EnteringContext, DeclSpecContext DSC) {
   DeclSpec::TST TagType;
-  if (TagTokKind == tok::kw_struct)
+  if (TagTokKind == tok::kw_struct || TagTokKind == tok::kw___interface)
     TagType = DeclSpec::TST_struct;
   else if (TagTokKind == tok::kw_class)
     TagType = DeclSpec::TST_class;
@@ -1110,6 +1110,14 @@
     Tok.setKind(tok::identifier);
   }
 
+  // __interface is a Microsoft extension that resolves to a struct
+  // with an 'ms_interface' attribute.
+  if (TagTokKind == tok::kw___interface) {
+    attrs.addNewInteger(
+        Actions.getASTContext(),
+        PP.getIdentifierInfo("ms_interface"), StartLoc, 0);
+  }
+
   // Parse the (optional) nested-name-specifier.
   CXXScopeSpec &SS = DS.getTypeSpecScope();
   if (getLangOpts().CPlusPlus) {


More information about the cfe-dev mailing list