diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2168,6 +2168,17 @@ let Documentation = [SwiftNameDocs]; } +def SwiftNewType : InheritableAttr { + // `swift_wrapper` is a "deprecated" alias and kept for compatibility with + // shipped toolchains. New users should prefer the `swift_newtype` spelling. + 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 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -3596,6 +3596,32 @@ }]; } +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. + + .. 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/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3271,7 +3271,8 @@ "|types and namespaces" "|variables, functions and classes" "|kernel functions" - "|non-K&R-style functions}1">, + "|non-K&R-style functions" + "|typedefs}1">, InGroup; def err_attribute_wrong_decl_type : Error; def warn_type_attribute_wrong_type : Warning< diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/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, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- 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 @@ 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, diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5942,6 +5942,33 @@ 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(D)) { + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL << /* typedefs */13; + return; + } + + D->addAttr(::new (S.Context) SwiftNewTypeAttr(S.Context, AL, Kind)); +} + //===----------------------------------------------------------------------===// // Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// @@ -7867,6 +7894,9 @@ case ParsedAttr::AT_SwiftName: handleSwiftName(S, D, AL); break; + case ParsedAttr::AT_SwiftNewType: + handleSwiftNewType(S, D, AL); + break; case ParsedAttr::AT_SwiftObjCMembers: handleSimpleAttribute(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 --- /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 --- 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 --- /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@-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 {{'__swift_newtype__' attribute only applies to typedefs}}