compnerd created this revision.
compnerd added a reviewer: aaron.ballman.
Herald added a reviewer: jdoerfert.
Herald added a project: clang.
compnerd requested review of this revision.
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
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D87652
Files:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/AttrDocs.td
clang/include/clang/Basic/DiagnosticSemaKinds.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
clang/test/SemaObjC/attr-swift-newtype.m
Index: clang/test/SemaObjC/attr-swift-newtype.m
===================================================================
--- /dev/null
+++ clang/test/SemaObjC/attr-swift-newtype.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -verify -fsyntax-only %s
+// RUN: not %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
+
+typedef int Bad1 __attribute__((swift_newtype(invalid)));
+// expected-warning@-1 {{'swift_newtype' attribute argument not supported: 'invalid'}}
+typedef int Bad2 __attribute__((swift_newtype()));
+// expected-error@-1 {{argument required after attribute}}
+typedef int Bad3 __attribute__((swift_newtype(invalid, ignored)));
+// expected-error@-1 {{expected ')'}}
+// expected-note@-2 {{to match this '('}}
+// expected-warning@-3 {{'swift_newtype' attribute argument not supported: 'invalid'}}
+
+struct __attribute__((__swift_newtype__(struct))) Bad4 { };
+// expected-error@-1 {{error: '__swift_newtype__' attribute only applies to typedefs}}
Index: clang/test/Misc/pragma-attribute-supported-attributes-list.test
===================================================================
--- clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ 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)
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ clang/lib/Sema/SemaDeclAttr.cpp
@@ -5889,6 +5889,39 @@
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)) {
+ AL.setInvalid();
+ return;
+ }
+ if (!AL.isArgIdent(0)) {
+ S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL
+ << AANT_ArgumentIdentifier;
+ AL.setInvalid();
+ return;
+ }
+
+ IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
+ SwiftNewTypeAttr::NewtypeKind Kind;
+ if (II->isStr("struct")) {
+ Kind = SwiftNewTypeAttr::NK_Struct;
+ } else if (II->isStr("enum")) {
+ Kind = SwiftNewTypeAttr::NK_Enum;
+ } else {
+ S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
+ AL.setInvalid();
+ return;
+ }
+
+ if (!isa<TypedefNameDecl>(D)) {
+ S.Diag(AL.getLoc(), diag::warn_swift_newtype_attribute_non_typedef) << AL;
+ return;
+ }
+
+ D->addAttr(::new (S.Context) SwiftNewTypeAttr(S.Context, AL, Kind));
+}
+
//===----------------------------------------------------------------------===//
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
@@ -7814,6 +7847,9 @@
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;
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ 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 @@
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 @@
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,52 @@
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,
Index: clang/include/clang/Parse/Parser.h
===================================================================
--- clang/include/clang/Parse/Parser.h
+++ clang/include/clang/Parse/Parser.h
@@ -2804,6 +2804,14 @@
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,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4034,6 +4034,10 @@
"%0 attribute with '%1' convention can only be applied to a "
"%select{function|method}2 returning %select{an integral type|a pointer}3">;
+def warn_swift_newtype_attribute_non_typedef
+ : Warning<"%0 attribute may be put on a typedef only; attribute is ignored">,
+ InGroup<DiagGroup<"swift-newtype-attribute">>;
+
def warn_ignored_objc_externally_retained : Warning<
"'objc_externally_retained' can only be applied to local variables "
"%select{of retainable type|with strong ownership}0">,
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ clang/include/clang/Basic/AttrDocs.td
@@ -3570,6 +3570,21 @@
}];
}
+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.
+
+* ``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.
+ }];
+}
+
def OMPDeclareSimdDocs : Documentation {
let Category = DocCatFunction;
let Heading = "#pragma omp declare simd";
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ clang/include/clang/Basic/Attr.td
@@ -2175,6 +2175,14 @@
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];
+}
+
def NoDeref : TypeAttr {
let Spellings = [Clang<"noderef">];
let Documentation = [NoDerefDocs];
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits