[clang] 296d883 - Sema: add support for `__attribute__((__swift_newtype__))`

Saleem Abdulrasool via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 24 08:41:34 PDT 2020


Author: Saleem Abdulrasool
Date: 2020-09-24T15:17:35Z
New Revision: 296d8832a3b5fe97725be62c5bbc721cc0e2cd20

URL: https://github.com/llvm/llvm-project/commit/296d8832a3b5fe97725be62c5bbc721cc0e2cd20
DIFF: https://github.com/llvm/llvm-project/commit/296d8832a3b5fe97725be62c5bbc721cc0e2cd20.diff

LOG: Sema: add support for `__attribute__((__swift_newtype__))`

Add the `swift_newtype` attribute which allows a type definition to be
imported into Swift as a new type.  The imported type must be either an
enumerated type (enum) or an object type (struct).

This is based on the work of the original changes in
https://github.com/llvm/llvm-project-staging/commit/8afaf3aad2af43cfedca7a24cd817848c4e95c0c

Differential Revision: https://reviews.llvm.org/D87652
Reviewed By: Aaron Ballman

Added: 
    clang/test/AST/attr-swift_newtype.m
    clang/test/SemaObjC/attr-swift_newtype.m

Modified: 
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Parse/Parser.h
    clang/lib/Parse/ParseDecl.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/test/Misc/pragma-attribute-supported-attributes-list.test

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 7222f396089e..a9cee8c770f9 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2168,6 +2168,15 @@ def SwiftName : InheritableAttr {
   let Documentation = [SwiftNameDocs];
 }
 
+def SwiftNewType : InheritableAttr {
+  let Spellings = [GNU<"swift_newtype">, GNU<"swift_wrapper">];
+  let Args = [EnumArgument<"NewtypeKind", "NewtypeKind",
+                           ["struct", "enum"], ["NK_Struct", "NK_Enum"]>];
+  let Subjects = SubjectList<[TypedefName], ErrorDiag>;
+  let Documentation = [SwiftNewTypeDocs];
+  let HasCustomParsing = 1;
+}
+
 def NoDeref : TypeAttr {
   let Spellings = [Clang<"noderef">];
   let Documentation = [NoDerefDocs];

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 753c4dd235fa..8930b61cced9 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -3622,6 +3622,36 @@ must be a simple or qualified identifier.
   }];
 }
 
+def SwiftNewTypeDocs : Documentation {
+  let Category = SwiftDocs;
+  let Heading = "swift_newtype";
+  let Content = [{
+The ``swift_newtype`` attribute indicates that the typedef to which the
+attribute appertains is imported as a new Swift type of the typedef's name.
+Previously, the attribute was spelt ``swift_wrapper``.  While the behaviour of
+the attribute is identical with either spelling, ``swift_wrapper`` is
+deprecated, only exists for compatibility purposes, and should not be used in
+new code.
+
+* ``swift_newtype(struct)`` means that a Swift struct will be created for this
+typedef.
+
+* ``swift_newtype(enum)`` means that a Swift enum will be created for this
+ypedef.
+
+  .. code-block:: c
+
+    // Import UIFontTextStyle as an enum type, with enumerated values being
+    // constants.
+    typedef NSString * UIFontTextStyle __attribute__((__swift_newtype__(enum)));
+
+    // Import UIFontDescriptorFeatureKey as a structure type, with enumerated
+    // values being members of the type structure.
+    typedef NSString * UIFontDescriptorFeatureKey __attribute__((__swift_newtype__(struct)));
+
+  }];
+}
+
 def OMPDeclareSimdDocs : Documentation {
   let Category = DocCatFunction;
   let Heading = "#pragma omp declare simd";

diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 211827e99de8..570f60fb9479 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2804,6 +2804,14 @@ class Parser : public CodeCompletionHandler {
                                        SourceLocation ScopeLoc,
                                        ParsedAttr::Syntax Syntax);
 
+  void ParseSwiftNewTypeAttribute(IdentifierInfo &AttrName,
+                                  SourceLocation AttrNameLoc,
+                                  ParsedAttributes &Attrs,
+                                  SourceLocation *EndLoc,
+                                  IdentifierInfo *ScopeName,
+                                  SourceLocation ScopeLoc,
+                                  ParsedAttr::Syntax Syntax);
+
   void ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
                                         SourceLocation AttrNameLoc,
                                         ParsedAttributes &Attrs,

diff  --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 38df6be17efe..d6b2eb8a9877 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -23,6 +23,7 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/Scope.h"
+#include "clang/Sema/SemaDiagnostic.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallString.h"
@@ -452,6 +453,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
     ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
                                     ScopeName, ScopeLoc, Syntax);
     return;
+  } else if (AttrKind == ParsedAttr::AT_SwiftNewType) {
+    ParseSwiftNewTypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+                               ScopeLoc, Syntax);
+    return;
   } else if (AttrKind == ParsedAttr::AT_TypeTagForDatatype) {
     ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
                                      ScopeName, ScopeLoc, Syntax);
@@ -506,6 +511,10 @@ unsigned Parser::ParseClangAttributeArgs(
     ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
                                     ScopeName, ScopeLoc, Syntax);
     break;
+  case ParsedAttr::AT_SwiftNewType:
+    ParseSwiftNewTypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
+                               ScopeLoc, Syntax);
+    break;
   case ParsedAttr::AT_TypeTagForDatatype:
     ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
                                      ScopeName, ScopeLoc, Syntax);
@@ -1409,6 +1418,49 @@ void Parser::ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
                Syntax);
 }
 
+
+void Parser::ParseSwiftNewTypeAttribute(
+    IdentifierInfo &AttrName, SourceLocation AttrNameLoc,
+    ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
+    SourceLocation ScopeLoc, ParsedAttr::Syntax Syntax) {
+  BalancedDelimiterTracker T(*this, tok::l_paren);
+
+  // Opening '('
+  if (T.consumeOpen()) {
+    Diag(Tok, diag::err_expected) << tok::l_paren;
+    return;
+  }
+
+  if (Tok.is(tok::r_paren)) {
+    Diag(Tok.getLocation(), diag::err_argument_required_after_attribute);
+    T.consumeClose();
+    return;
+  }
+  if (Tok.isNot(tok::kw_struct) && Tok.isNot(tok::kw_enum)) {
+    Diag(Tok, diag::warn_attribute_type_not_supported)
+        << &AttrName << Tok.getIdentifierInfo();
+    if (!isTokenSpecial())
+      ConsumeToken();
+    T.consumeClose();
+    return;
+  }
+
+  auto *SwiftType = IdentifierLoc::create(Actions.Context, Tok.getLocation(),
+                                          Tok.getIdentifierInfo());
+  ConsumeToken();
+
+  // Closing ')'
+  if (T.consumeClose())
+    return;
+  if (EndLoc)
+    *EndLoc = T.getCloseLocation();
+
+  ArgsUnion Args[] = {SwiftType};
+  Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, T.getCloseLocation()),
+               ScopeName, ScopeLoc, Args, llvm::array_lengthof(Args), Syntax);
+}
+
+
 void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
                                               SourceLocation AttrNameLoc,
                                               ParsedAttributes &Attrs,

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index d15ef232a5fb..00cad5c11c32 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -5946,6 +5946,33 @@ static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) {
   D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name));
 }
 
+static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) {
+  // Make sure that there is an identifier as the annotation's single argument.
+  if (!checkAttributeNumArgs(S, AL, 1))
+    return;
+
+  if (!AL.isArgIdent(0)) {
+    S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
+        << AL << AANT_ArgumentIdentifier;
+    return;
+  }
+
+  SwiftNewTypeAttr::NewtypeKind Kind;
+  IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
+  if (!SwiftNewTypeAttr::ConvertStrToNewtypeKind(II->getName(), Kind)) {
+    S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
+    return;
+  }
+
+  if (!isa<TypedefNameDecl>(D)) {
+    S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str)
+        << AL << "typedefs";
+    return;
+  }
+
+  D->addAttr(::new (S.Context) SwiftNewTypeAttr(S.Context, AL, Kind));
+}
+
 //===----------------------------------------------------------------------===//
 // Microsoft specific attribute handlers.
 //===----------------------------------------------------------------------===//
@@ -7871,6 +7898,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
   case ParsedAttr::AT_SwiftName:
     handleSwiftName(S, D, AL);
     break;
+  case ParsedAttr::AT_SwiftNewType:
+    handleSwiftNewType(S, D, AL);
+    break;
   case ParsedAttr::AT_SwiftObjCMembers:
     handleSimpleAttribute<SwiftObjCMembersAttr>(S, D, AL);
     break;

diff  --git a/clang/test/AST/attr-swift_newtype.m b/clang/test/AST/attr-swift_newtype.m
new file mode 100644
index 000000000000..04ec62426d8c
--- /dev/null
+++ b/clang/test/AST/attr-swift_newtype.m
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -ast-dump %s | FileCheck %s
+
+typedef int T1 __attribute__((__swift_newtype__(struct)));
+typedef int T2 __attribute__((__swift_newtype__(enum)));
+
+typedef int T3 __attribute__((__swift_wrapper__(struct)));
+typedef int T4 __attribute__((__swift_wrapper__(enum)));
+
+typedef int T5;
+typedef int T5 __attribute__((__swift_wrapper__(struct)));
+typedef int T5;
+// CHECK-LABEL: TypedefDecl {{.+}} T5 'int'
+// CHECK-NEXT: BuiltinType {{.+}} 'int'
+// CHECK-NEXT: TypedefDecl {{.+}} T5 'int'
+// CHECK-NEXT: BuiltinType {{.+}} 'int'
+// CHECK-NEXT: SwiftNewTypeAttr {{.+}} NK_Struct
+// CHECK-NEXT: TypedefDecl {{.+}} T5 'int'
+// CHECK-NEXT: BuiltinType {{.+}} 'int'
+// CHECK-NEXT: SwiftNewTypeAttr {{.+}} NK_Struct

diff  --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index 024081b02e3e..d385b858986c 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -151,6 +151,7 @@
 // CHECK-NEXT: SwiftError (SubjectMatchRule_function, SubjectMatchRule_objc_method)
 // CHECK-NEXT: SwiftErrorResult (SubjectMatchRule_variable_is_parameter)
 // CHECK-NEXT: SwiftIndirectResult (SubjectMatchRule_variable_is_parameter)
+// CHECK-NEXT: SwiftNewType (SubjectMatchRule_type_alias)
 // CHECK-NEXT: SwiftObjCMembers (SubjectMatchRule_objc_interface)
 // CHECK-NEXT: TLSModel (SubjectMatchRule_variable_is_thread_local)
 // CHECK-NEXT: Target (SubjectMatchRule_function)

diff  --git a/clang/test/SemaObjC/attr-swift_newtype.m b/clang/test/SemaObjC/attr-swift_newtype.m
new file mode 100644
index 000000000000..f8be66ebef2b
--- /dev/null
+++ b/clang/test/SemaObjC/attr-swift_newtype.m
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef int Bad1 __attribute__((swift_newtype(invalid)));
+// expected-warning at -1 {{'swift_newtype' attribute argument not supported: 'invalid'}}
+typedef int Bad2 __attribute__((swift_newtype()));
+// expected-error at -1 {{argument required after attribute}}
+typedef int Bad3 __attribute__((swift_newtype(invalid, ignored)));
+// expected-error at -1 {{expected ')'}}
+// expected-note at -2 {{to match this '('}}
+// expected-warning at -3 {{'swift_newtype' attribute argument not supported: 'invalid'}}
+
+struct __attribute__((__swift_newtype__(struct))) Bad4 {};
+// expected-error at -1 {{'__swift_newtype__' attribute only applies to typedefs}}


        


More information about the cfe-commits mailing list