Skip to content

Commit 296d883

Browse files
committed
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 llvm/llvm-project-staging@8afaf3a Differential Revision: https://reviews.llvm.org/D87652 Reviewed By: Aaron Ballman
1 parent 31a3c5f commit 296d883

File tree

8 files changed

+162
-0
lines changed

8 files changed

+162
-0
lines changed

clang/include/clang/Basic/Attr.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2168,6 +2168,15 @@ def SwiftName : InheritableAttr {
21682168
let Documentation = [SwiftNameDocs];
21692169
}
21702170

2171+
def SwiftNewType : InheritableAttr {
2172+
let Spellings = [GNU<"swift_newtype">, GNU<"swift_wrapper">];
2173+
let Args = [EnumArgument<"NewtypeKind", "NewtypeKind",
2174+
["struct", "enum"], ["NK_Struct", "NK_Enum"]>];
2175+
let Subjects = SubjectList<[TypedefName], ErrorDiag>;
2176+
let Documentation = [SwiftNewTypeDocs];
2177+
let HasCustomParsing = 1;
2178+
}
2179+
21712180
def NoDeref : TypeAttr {
21722181
let Spellings = [Clang<"noderef">];
21732182
let Documentation = [NoDerefDocs];

clang/include/clang/Basic/AttrDocs.td

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3622,6 +3622,36 @@ must be a simple or qualified identifier.
36223622
}];
36233623
}
36243624

3625+
def SwiftNewTypeDocs : Documentation {
3626+
let Category = SwiftDocs;
3627+
let Heading = "swift_newtype";
3628+
let Content = [{
3629+
The ``swift_newtype`` attribute indicates that the typedef to which the
3630+
attribute appertains is imported as a new Swift type of the typedef's name.
3631+
Previously, the attribute was spelt ``swift_wrapper``. While the behaviour of
3632+
the attribute is identical with either spelling, ``swift_wrapper`` is
3633+
deprecated, only exists for compatibility purposes, and should not be used in
3634+
new code.
3635+
3636+
* ``swift_newtype(struct)`` means that a Swift struct will be created for this
3637+
typedef.
3638+
3639+
* ``swift_newtype(enum)`` means that a Swift enum will be created for this
3640+
ypedef.
3641+
3642+
.. code-block:: c
3643+
3644+
// Import UIFontTextStyle as an enum type, with enumerated values being
3645+
// constants.
3646+
typedef NSString * UIFontTextStyle __attribute__((__swift_newtype__(enum)));
3647+
3648+
// Import UIFontDescriptorFeatureKey as a structure type, with enumerated
3649+
// values being members of the type structure.
3650+
typedef NSString * UIFontDescriptorFeatureKey __attribute__((__swift_newtype__(struct)));
3651+
3652+
}];
3653+
}
3654+
36253655
def OMPDeclareSimdDocs : Documentation {
36263656
let Category = DocCatFunction;
36273657
let Heading = "#pragma omp declare simd";

clang/include/clang/Parse/Parser.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2804,6 +2804,14 @@ class Parser : public CodeCompletionHandler {
28042804
SourceLocation ScopeLoc,
28052805
ParsedAttr::Syntax Syntax);
28062806

2807+
void ParseSwiftNewTypeAttribute(IdentifierInfo &AttrName,
2808+
SourceLocation AttrNameLoc,
2809+
ParsedAttributes &Attrs,
2810+
SourceLocation *EndLoc,
2811+
IdentifierInfo *ScopeName,
2812+
SourceLocation ScopeLoc,
2813+
ParsedAttr::Syntax Syntax);
2814+
28072815
void ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
28082816
SourceLocation AttrNameLoc,
28092817
ParsedAttributes &Attrs,

clang/lib/Parse/ParseDecl.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "clang/Sema/Lookup.h"
2424
#include "clang/Sema/ParsedTemplate.h"
2525
#include "clang/Sema/Scope.h"
26+
#include "clang/Sema/SemaDiagnostic.h"
2627
#include "llvm/ADT/Optional.h"
2728
#include "llvm/ADT/SmallSet.h"
2829
#include "llvm/ADT/SmallString.h"
@@ -452,6 +453,10 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName,
452453
ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
453454
ScopeName, ScopeLoc, Syntax);
454455
return;
456+
} else if (AttrKind == ParsedAttr::AT_SwiftNewType) {
457+
ParseSwiftNewTypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
458+
ScopeLoc, Syntax);
459+
return;
455460
} else if (AttrKind == ParsedAttr::AT_TypeTagForDatatype) {
456461
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
457462
ScopeName, ScopeLoc, Syntax);
@@ -506,6 +511,10 @@ unsigned Parser::ParseClangAttributeArgs(
506511
ParseObjCBridgeRelatedAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
507512
ScopeName, ScopeLoc, Syntax);
508513
break;
514+
case ParsedAttr::AT_SwiftNewType:
515+
ParseSwiftNewTypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName,
516+
ScopeLoc, Syntax);
517+
break;
509518
case ParsedAttr::AT_TypeTagForDatatype:
510519
ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc,
511520
ScopeName, ScopeLoc, Syntax);
@@ -1409,6 +1418,49 @@ void Parser::ParseObjCBridgeRelatedAttribute(IdentifierInfo &ObjCBridgeRelated,
14091418
Syntax);
14101419
}
14111420

1421+
1422+
void Parser::ParseSwiftNewTypeAttribute(
1423+
IdentifierInfo &AttrName, SourceLocation AttrNameLoc,
1424+
ParsedAttributes &Attrs, SourceLocation *EndLoc, IdentifierInfo *ScopeName,
1425+
SourceLocation ScopeLoc, ParsedAttr::Syntax Syntax) {
1426+
BalancedDelimiterTracker T(*this, tok::l_paren);
1427+
1428+
// Opening '('
1429+
if (T.consumeOpen()) {
1430+
Diag(Tok, diag::err_expected) << tok::l_paren;
1431+
return;
1432+
}
1433+
1434+
if (Tok.is(tok::r_paren)) {
1435+
Diag(Tok.getLocation(), diag::err_argument_required_after_attribute);
1436+
T.consumeClose();
1437+
return;
1438+
}
1439+
if (Tok.isNot(tok::kw_struct) && Tok.isNot(tok::kw_enum)) {
1440+
Diag(Tok, diag::warn_attribute_type_not_supported)
1441+
<< &AttrName << Tok.getIdentifierInfo();
1442+
if (!isTokenSpecial())
1443+
ConsumeToken();
1444+
T.consumeClose();
1445+
return;
1446+
}
1447+
1448+
auto *SwiftType = IdentifierLoc::create(Actions.Context, Tok.getLocation(),
1449+
Tok.getIdentifierInfo());
1450+
ConsumeToken();
1451+
1452+
// Closing ')'
1453+
if (T.consumeClose())
1454+
return;
1455+
if (EndLoc)
1456+
*EndLoc = T.getCloseLocation();
1457+
1458+
ArgsUnion Args[] = {SwiftType};
1459+
Attrs.addNew(&AttrName, SourceRange(AttrNameLoc, T.getCloseLocation()),
1460+
ScopeName, ScopeLoc, Args, llvm::array_lengthof(Args), Syntax);
1461+
}
1462+
1463+
14121464
void Parser::ParseTypeTagForDatatypeAttribute(IdentifierInfo &AttrName,
14131465
SourceLocation AttrNameLoc,
14141466
ParsedAttributes &Attrs,

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5946,6 +5946,33 @@ static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) {
59465946
D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name));
59475947
}
59485948

5949+
static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) {
5950+
// Make sure that there is an identifier as the annotation's single argument.
5951+
if (!checkAttributeNumArgs(S, AL, 1))
5952+
return;
5953+
5954+
if (!AL.isArgIdent(0)) {
5955+
S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
5956+
<< AL << AANT_ArgumentIdentifier;
5957+
return;
5958+
}
5959+
5960+
SwiftNewTypeAttr::NewtypeKind Kind;
5961+
IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
5962+
if (!SwiftNewTypeAttr::ConvertStrToNewtypeKind(II->getName(), Kind)) {
5963+
S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
5964+
return;
5965+
}
5966+
5967+
if (!isa<TypedefNameDecl>(D)) {
5968+
S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str)
5969+
<< AL << "typedefs";
5970+
return;
5971+
}
5972+
5973+
D->addAttr(::new (S.Context) SwiftNewTypeAttr(S.Context, AL, Kind));
5974+
}
5975+
59495976
//===----------------------------------------------------------------------===//
59505977
// Microsoft specific attribute handlers.
59515978
//===----------------------------------------------------------------------===//
@@ -7871,6 +7898,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
78717898
case ParsedAttr::AT_SwiftName:
78727899
handleSwiftName(S, D, AL);
78737900
break;
7901+
case ParsedAttr::AT_SwiftNewType:
7902+
handleSwiftNewType(S, D, AL);
7903+
break;
78747904
case ParsedAttr::AT_SwiftObjCMembers:
78757905
handleSimpleAttribute<SwiftObjCMembersAttr>(S, D, AL);
78767906
break;

clang/test/AST/attr-swift_newtype.m

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clang_cc1 -ast-dump %s | FileCheck %s
2+
3+
typedef int T1 __attribute__((__swift_newtype__(struct)));
4+
typedef int T2 __attribute__((__swift_newtype__(enum)));
5+
6+
typedef int T3 __attribute__((__swift_wrapper__(struct)));
7+
typedef int T4 __attribute__((__swift_wrapper__(enum)));
8+
9+
typedef int T5;
10+
typedef int T5 __attribute__((__swift_wrapper__(struct)));
11+
typedef int T5;
12+
// CHECK-LABEL: TypedefDecl {{.+}} T5 'int'
13+
// CHECK-NEXT: BuiltinType {{.+}} 'int'
14+
// CHECK-NEXT: TypedefDecl {{.+}} T5 'int'
15+
// CHECK-NEXT: BuiltinType {{.+}} 'int'
16+
// CHECK-NEXT: SwiftNewTypeAttr {{.+}} NK_Struct
17+
// CHECK-NEXT: TypedefDecl {{.+}} T5 'int'
18+
// CHECK-NEXT: BuiltinType {{.+}} 'int'
19+
// CHECK-NEXT: SwiftNewTypeAttr {{.+}} NK_Struct

clang/test/Misc/pragma-attribute-supported-attributes-list.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
// CHECK-NEXT: SwiftError (SubjectMatchRule_function, SubjectMatchRule_objc_method)
152152
// CHECK-NEXT: SwiftErrorResult (SubjectMatchRule_variable_is_parameter)
153153
// CHECK-NEXT: SwiftIndirectResult (SubjectMatchRule_variable_is_parameter)
154+
// CHECK-NEXT: SwiftNewType (SubjectMatchRule_type_alias)
154155
// CHECK-NEXT: SwiftObjCMembers (SubjectMatchRule_objc_interface)
155156
// CHECK-NEXT: TLSModel (SubjectMatchRule_variable_is_thread_local)
156157
// CHECK-NEXT: Target (SubjectMatchRule_function)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify %s
2+
3+
typedef int Bad1 __attribute__((swift_newtype(invalid)));
4+
// expected-warning@-1 {{'swift_newtype' attribute argument not supported: 'invalid'}}
5+
typedef int Bad2 __attribute__((swift_newtype()));
6+
// expected-error@-1 {{argument required after attribute}}
7+
typedef int Bad3 __attribute__((swift_newtype(invalid, ignored)));
8+
// expected-error@-1 {{expected ')'}}
9+
// expected-note@-2 {{to match this '('}}
10+
// expected-warning@-3 {{'swift_newtype' attribute argument not supported: 'invalid'}}
11+
12+
struct __attribute__((__swift_newtype__(struct))) Bad4 {};
13+
// expected-error@-1 {{'__swift_newtype__' attribute only applies to typedefs}}

0 commit comments

Comments
 (0)