This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. compnerd marked 4 inline comments as done. Closed by commit rG9bb5ecf1f760: Sema: introduce `__attribute__((__swift_name__))` (authored by compnerd).
Changed prior to commit: https://reviews.llvm.org/D87534?vs=292548&id=293470#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D87534/new/ https://reviews.llvm.org/D87534 Files: clang/include/clang/Basic/Attr.td clang/include/clang/Basic/AttrDocs.td clang/include/clang/Basic/DiagnosticGroups.td clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaDecl.cpp clang/lib/Sema/SemaDeclAttr.cpp clang/test/SemaObjC/attr-swift_name.m
Index: clang/test/SemaObjC/attr-swift_name.m =================================================================== --- /dev/null +++ clang/test/SemaObjC/attr-swift_name.m @@ -0,0 +1,174 @@ +// RUN: %clang_cc1 -verify -fsyntax-only -fobjc-arc %s + +#define SWIFT_NAME(name) __attribute__((__swift_name__(name))) + +typedef struct { + float x, y, z; +} Point3D; + +__attribute__((__swift_name__("PType"))) +@protocol P +@end + +__attribute__((__swift_name__("IClass"))) +@interface I<P> +- (instancetype)init SWIFT_NAME("init()"); +- (instancetype)initWithValue:(int)value SWIFT_NAME("iWithValue(_:)"); + ++ (void)refresh SWIFT_NAME("refresh()"); + +- (instancetype)i SWIFT_NAME("i()"); + +- (I *)iWithValue:(int)value SWIFT_NAME("i(value:)"); +- (I *)iWithValue:(int)value value:(int)value2 SWIFT_NAME("i(value:extra:)"); +- (I *)iWithValueConvertingValue:(int)value value:(int)value2 SWIFT_NAME("i(_:extra:)"); + ++ (I *)iWithOtheValue:(int)value SWIFT_NAME("init"); +// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}} + ++ (I *)iWithAnotherValue:(int)value SWIFT_NAME("i()"); +// expected-warning@-1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}} + ++ (I *)iWithYetAnotherValue:(int)value SWIFT_NAME("i(value:extra:)"); +// expected-warning@-1 {{too many parameters in '__swift_name__' attribute (expected 1; got 2}} + ++ (I *)iAndReturnErrorCode:(int *)errorCode SWIFT_NAME("i()"); // no-warning ++ (I *)iWithValue:(int)value andReturnErrorCode:(int *)errorCode SWIFT_NAME("i(value:)"); // no-warning + ++ (I *)iFromErrorCode:(const int *)errorCode SWIFT_NAME("i()"); +// expected-warning@-1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}} + ++ (I *)iWithPointerA:(int *)value andReturnErrorCode:(int *)errorCode SWIFT_NAME("i()"); // no-warning ++ (I *)iWithPointerB:(int *)value andReturnErrorCode:(int *)errorCode SWIFT_NAME("i(pointer:)"); // no-warning ++ (I *)iWithPointerC:(int *)value andReturnErrorCode:(int *)errorCode SWIFT_NAME("i(pointer:errorCode:)"); // no-warning + ++ (I *)iWithOtherI:(I *)other SWIFT_NAME("i()"); +// expected-warning@-1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}} + ++ (instancetype)specialI SWIFT_NAME("init(options:)"); ++ (instancetype)specialJ SWIFT_NAME("init(options:extra:)"); +// expected-warning@-1 {{too many parameters in '__swift_name__' attribute (expected 0; got 2)}} ++ (instancetype)specialK SWIFT_NAME("init(_:)"); +// expected-warning@-1 {{too many parameters in '__swift_name__' attribute (expected 0; got 1)}} ++ (instancetype)specialL SWIFT_NAME("i(options:)"); +// expected-warning@-1 {{too many parameters in '__swift_name__' attribute (expected 0; got 1)}} + ++ (instancetype)trailingParen SWIFT_NAME("foo("); +// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}} ++ (instancetype)trailingColon SWIFT_NAME("foo:"); +// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}} ++ (instancetype)initialIgnore:(int)value SWIFT_NAME("_(value:)"); +// expected-warning@-1 {{'__swift_name__' attribute has invalid identifier for the base name}} ++ (instancetype)middleOmitted:(int)value SWIFT_NAME("i(:)"); +// expected-warning@-1 {{'__swift_name__' attribute has invalid identifier for the parameter name}} + +@property(strong) id someProp SWIFT_NAME("prop"); +@end + +enum SWIFT_NAME("E") E { + value1, + value2, + value3 SWIFT_NAME("three"), + value4 SWIFT_NAME("four()"), // expected-warning {{'__swift_name__' attribute has invalid identifier for the base name}} +}; + +struct SWIFT_NAME("TStruct") SStruct { + int i, j, k SWIFT_NAME("kay"); +}; + +int i SWIFT_NAME("g_i"); + +void f0(int i) SWIFT_NAME("f_0"); +// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}} + +void f1(int i) SWIFT_NAME("f_1()"); +// expected-warning@-1 {{too few parameters in '__swift_name__' attribute (expected 1; got 0)}} + +void f2(int i) SWIFT_NAME("f_2(a:b:)"); +// expected-warning@-1 {{too many parameters in '__swift_name__' attribute (expected 1; got 2)}} + +void f3(int x, int y) SWIFT_NAME("fWithX(_:y:)"); +void f4(int x, int *error) SWIFT_NAME("fWithX(_:)"); + +typedef int int_t SWIFT_NAME("IntType"); + +struct Point3D createPoint3D(float x, float y, float z) SWIFT_NAME("Point3D.init(x:y:z:)"); +struct Point3D rotatePoint3D(Point3D point, float radians) SWIFT_NAME("Point3D.rotate(self:radians:)"); +struct Point3D badRotatePoint3D(Point3D point, float radians) SWIFT_NAME("Point3D.rotate(radians:)"); +// expected-warning@-1 {{too few parameters in '__swift_name__' attribute (expected 2; got 1)}} + +extern struct Point3D identityPoint SWIFT_NAME("Point3D.identity"); + +float Point3DGetMagnitude(Point3D point) SWIFT_NAME("getter:Point3D.magnitude(self:)"); +float Point3DGetMagnitudeAndSomethingElse(Point3D point, float f) SWIFT_NAME("getter:Point3D.magnitude(self:f:)"); +// expected-warning@-1 {{'__swift_name__' attribute for getter must not have any parameters besides 'self:'}} + +float Point3DGetRadius(Point3D point) SWIFT_NAME("getter:Point3D.radius(self:)"); +void Point3DSetRadius(Point3D point, float radius) SWIFT_NAME("setter:Point3D.radius(self:newValue:)"); + +float Point3DPreGetRadius(Point3D point) SWIFT_NAME("getter:Point3D.preRadius(self:)"); +void Point3DPreSetRadius(float radius, Point3D point) SWIFT_NAME("setter:Point3D.preRadius(newValue:self:)"); + +void Point3DSetRadiusAndSomethingElse(Point3D point, float radius, float f) SWIFT_NAME("setter:Point3D.radius(self:newValue:f:)"); +// expected-warning@-1 {{'__swift_name__' attribute for setter must have one parameter for new value}} + +float Point3DGetComponent(Point3D point, unsigned index) SWIFT_NAME("getter:Point3D.subscript(self:_:)"); +float Point3DSetComponent(Point3D point, unsigned index, float value) SWIFT_NAME("setter:Point3D.subscript(self:_:newValue:)"); + +float Point3DGetMatrixComponent(Point3D point, unsigned x, unsigned y) SWIFT_NAME("getter:Point3D.subscript(self:x:y:)"); +void Point3DSetMatrixComponent(Point3D point, unsigned x, float value, unsigned y) SWIFT_NAME("setter:Point3D.subscript(self:x:newValue:y:)"); + +float Point3DSetWithoutNewValue(Point3D point, unsigned x, unsigned y) SWIFT_NAME("setter:Point3D.subscript(self:x:y:)"); +// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' setter must have a 'newValue:' parameter}} + +float Point3DSubscriptButNotGetterSetter(Point3D point, unsigned x) SWIFT_NAME("Point3D.subscript(self:_:)"); +// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' must be a getter or setter}} + +void Point3DSubscriptSetterTwoNewValues(Point3D point, unsigned x, float a, float b) SWIFT_NAME("setter:Point3D.subscript(self:_:newValue:newValue:)"); +// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' setter cannot have multiple 'newValue:' parameters}} + +float Point3DSubscriptGetterNewValue(Point3D point, unsigned x, float a, float b) SWIFT_NAME("getter:Point3D.subscript(self:_:newValue:newValue:)"); +// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' getter cannot have a 'newValue:' parameter}} + +void Point3DMethodWithNewValue(Point3D point, float newValue) SWIFT_NAME("Point3D.method(self:newValue:)"); +void Point3DMethodWithNewValues(Point3D point, float newValue, float newValueB) SWIFT_NAME("Point3D.method(self:newValue:newValue:)"); + +float Point3DStaticSubscript(unsigned x) SWIFT_NAME("getter:Point3D.subscript(_:)"); +// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' must have a 'self:' parameter}} + +float Point3DStaticSubscriptNoArgs(void) SWIFT_NAME("getter:Point3D.subscript()"); +// expected-warning@-1 {{'__swift_name__' attribute for 'subscript' must have at least one parameter}} + +float Point3DPreGetComponent(Point3D point, unsigned index) SWIFT_NAME("getter:Point3D.subscript(self:_:)"); + +Point3D getCurrentPoint3D(void) SWIFT_NAME("getter:currentPoint3D()"); + +void setCurrentPoint3D(Point3D point) SWIFT_NAME("setter:currentPoint3D(newValue:)"); + +Point3D getLastPoint3D(void) SWIFT_NAME("getter:lastPoint3D()"); + +void setLastPoint3D(Point3D point) SWIFT_NAME("setter:lastPoint3D(newValue:)"); + +Point3D getZeroPoint(void) SWIFT_NAME("getter:Point3D.zero()"); +void setZeroPoint(Point3D point) SWIFT_NAME("setter:Point3D.zero(newValue:)"); +Point3D getZeroPointNoPrototype() SWIFT_NAME("getter:Point3D.zeroNoPrototype()"); +// expected-warning@-1 {{'__swift_name__' attribute only applies to non-K&R-style functions}} + +Point3D badGetter1(int x) SWIFT_NAME("getter:bad1(_:)"); +// expected-warning@-1 {{'__swift_name__' attribute for getter must not have any parameters besides 'self:'}} + +void badSetter1(void) SWIFT_NAME("getter:bad1())"); +// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}} + +Point3D badGetter2(Point3D point) SWIFT_NAME("getter:bad2(_:))"); +// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}} + +void badSetter2(Point3D point) SWIFT_NAME("setter:bad2(self:))"); +// expected-warning@-1 {{'__swift_name__' attribute argument must be a string literal specifying a Swift function name}} + +void g(int i) SWIFT_NAME("function(int:)"); +// expected-note@-1 {{conflicting attribute is here}} + +// expected-error@+1 {{'swift_name' and 'swift_name' attributes are not compatible}} +void g(int i) SWIFT_NAME("function(_:)") { +} Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -4277,6 +4277,25 @@ return ::new (Context) NoSpeculativeLoadHardeningAttr(Context, AL); } +SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA, + StringRef Name, bool Override) { + if (const auto *PrevSNA = D->getAttr<SwiftNameAttr>()) { + if (Override) { + // FIXME: warn about incompatible override + return nullptr; + } + + if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) { + Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible) + << PrevSNA << &SNA; + Diag(SNA.getLoc(), diag::note_conflicting_attribute); + } + + D->dropAttr<SwiftNameAttr>(); + } + return ::new (Context) SwiftNameAttr(Context, SNA, Name); +} + OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D, const AttributeCommonInfo &CI) { if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) { @@ -5636,6 +5655,293 @@ D->addAttr(::new (S.Context) SwiftErrorAttr(S.Context, AL, Convention)); } +// For a function, this will validate a compound Swift name, e.g. +// <code>init(foo:bar:baz:)</code> or <code>controllerForName(_:)</code>, and +// the function will output the number of parameter names, and whether this is a +// single-arg initializer. +// +// For a type, enum constant, property, or variable declaration, this will +// validate either a simple identifier, or a qualified +// <code>context.identifier</code> name. +static bool +validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc, + StringRef Name, unsigned &SwiftParamCount, + bool &IsSingleParamInit) { + SwiftParamCount = 0; + IsSingleParamInit = false; + + // Check whether this will be mapped to a getter or setter of a property. + bool IsGetter = false, IsSetter = false; + if (Name.startswith("getter:")) { + IsGetter = true; + Name = Name.substr(7); + } else if (Name.startswith("setter:")) { + IsSetter = true; + Name = Name.substr(7); + } + + if (Name.back() != ')') { + S.Diag(Loc, diag::warn_attr_swift_name_function) << AL; + return false; + } + + bool IsMember = false; + StringRef ContextName, BaseName, Parameters; + + std::tie(BaseName, Parameters) = Name.split('('); + + // Split at the first '.', if it exists, which separates the context name + // from the base name. + std::tie(ContextName, BaseName) = BaseName.split('.'); + if (BaseName.empty()) { + BaseName = ContextName; + ContextName = StringRef(); + } else if (ContextName.empty() || !isValidIdentifier(ContextName)) { + S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*context*/ 1; + return false; + } else { + IsMember = true; + } + + if (!isValidIdentifier(BaseName) || BaseName == "_") { + S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*basename*/ 0; + return false; + } + + bool IsSubscript = BaseName == "subscript"; + // A subscript accessor must be a getter or setter. + if (IsSubscript && !IsGetter && !IsSetter) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) + << AL << /* getter or setter */ 0; + return false; + } + + if (Parameters.empty()) { + S.Diag(Loc, diag::warn_attr_swift_name_missing_parameters) << AL; + return false; + } + + assert(Parameters.back() == ')' && "expected ')'"); + Parameters = Parameters.drop_back(); // ')' + + if (Parameters.empty()) { + // Setters and subscripts must have at least one parameter. + if (IsSubscript) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) + << AL << /* have at least one parameter */1; + return false; + } + + if (IsSetter) { + S.Diag(Loc, diag::warn_attr_swift_name_setter_parameters) << AL; + return false; + } + + return true; + } + + if (Parameters.back() != ':') { + S.Diag(Loc, diag::warn_attr_swift_name_function) << AL; + return false; + } + + StringRef CurrentParam; + llvm::Optional<unsigned> SelfLocation; + unsigned NewValueCount = 0; + llvm::Optional<unsigned> NewValueLocation; + do { + std::tie(CurrentParam, Parameters) = Parameters.split(':'); + + if (!isValidIdentifier(CurrentParam)) { + S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) + << AL << /*parameter*/2; + return false; + } + + if (IsMember && CurrentParam == "self") { + // "self" indicates the "self" argument for a member. + + // More than one "self"? + if (SelfLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_multiple_selfs) << AL; + return false; + } + + // The "self" location is the current parameter. + SelfLocation = SwiftParamCount; + } else if (CurrentParam == "newValue") { + // "newValue" indicates the "newValue" argument for a setter. + + // There should only be one 'newValue', but it's only significant for + // subscript accessors, so don't error right away. + ++NewValueCount; + + NewValueLocation = SwiftParamCount; + } + + ++SwiftParamCount; + } while (!Parameters.empty()); + + // Only instance subscripts are currently supported. + if (IsSubscript && !SelfLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_invalid_parameter) + << AL << /*have a 'self:' parameter*/2; + return false; + } + + IsSingleParamInit = + SwiftParamCount == 1 && BaseName == "init" && CurrentParam != "_"; + + // Check the number of parameters for a getter/setter. + if (IsGetter || IsSetter) { + // Setters have one parameter for the new value. + unsigned NumExpectedParams = IsGetter ? 0 : 1; + unsigned ParamDiag = + IsGetter ? diag::warn_attr_swift_name_getter_parameters + : diag::warn_attr_swift_name_setter_parameters; + + // Instance methods have one parameter for "self". + if (SelfLocation) + ++NumExpectedParams; + + // Subscripts may have additional parameters beyond the expected params for + // the index. + if (IsSubscript) { + if (SwiftParamCount < NumExpectedParams) { + S.Diag(Loc, ParamDiag) << AL; + return false; + } + + // A subscript setter must explicitly label its newValue parameter to + // distinguish it from index parameters. + if (IsSetter) { + if (!NewValueLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_no_newValue) + << AL; + return false; + } + if (NewValueCount > 1) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_setter_multiple_newValues) + << AL; + return false; + } + } else { + // Subscript getters should have no 'newValue:' parameter. + if (NewValueLocation) { + S.Diag(Loc, diag::warn_attr_swift_name_subscript_getter_newValue) + << AL; + return false; + } + } + } else { + // Property accessors must have exactly the number of expected params. + if (SwiftParamCount != NumExpectedParams) { + S.Diag(Loc, ParamDiag) << AL; + return false; + } + } + } + + return true; +} + +bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc, + const ParsedAttr &AL) { + if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) { + ArrayRef<ParmVarDecl*> Params; + unsigned ParamCount; + + if (const auto *Method = dyn_cast<ObjCMethodDecl>(D)) { + ParamCount = Method->getSelector().getNumArgs(); + Params = Method->parameters().slice(0, ParamCount); + } else { + const auto *F = cast<FunctionDecl>(D); + + ParamCount = F->getNumParams(); + Params = F->parameters(); + + if (!F->hasWrittenPrototype()) { + Diag(Loc, diag::warn_attribute_wrong_decl_type) << AL + << /* non-K&R-style functions */12; + return false; + } + } + + unsigned SwiftParamCount; + bool IsSingleParamInit; + if (!validateSwiftFunctionName(*this, AL, Loc, Name, + SwiftParamCount, IsSingleParamInit)) + return false; + + bool ParamCountValid; + if (SwiftParamCount == ParamCount) { + ParamCountValid = true; + } else if (SwiftParamCount > ParamCount) { + ParamCountValid = IsSingleParamInit && ParamCount == 0; + } else { + // We have fewer Swift parameters than Objective-C parameters, but that + // might be because we've transformed some of them. Check for potential + // "out" parameters and err on the side of not warning. + unsigned MaybeOutParamCount = + std::count_if(Params.begin(), Params.end(), + [](const ParmVarDecl *Param) -> bool { + QualType ParamTy = Param->getType(); + if (ParamTy->isReferenceType() || ParamTy->isPointerType()) + return !ParamTy->getPointeeType().isConstQualified(); + return false; + }); + + ParamCountValid = SwiftParamCount + MaybeOutParamCount >= ParamCount; + } + + if (!ParamCountValid) { + Diag(Loc, diag::warn_attr_swift_name_num_params) + << (SwiftParamCount > ParamCount) << AL << ParamCount + << SwiftParamCount; + return false; + } + } else if (isa<EnumConstantDecl>(D) || isa<ObjCProtocolDecl>(D) || + isa<ObjCInterfaceDecl>(D) || isa<ObjCPropertyDecl>(D) || + isa<VarDecl>(D) || isa<TypedefNameDecl>(D) || isa<TagDecl>(D) || + isa<IndirectFieldDecl>(D) || isa<FieldDecl>(D)) { + StringRef ContextName, BaseName; + + std::tie(ContextName, BaseName) = Name.split('.'); + if (BaseName.empty()) { + BaseName = ContextName; + ContextName = StringRef(); + } else if (!isValidIdentifier(ContextName)) { + Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL + << /*context*/1; + return false; + } + + if (!isValidIdentifier(BaseName)) { + Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL + << /*basename*/0; + return false; + } + } else { + Diag(Loc, diag::warn_attr_swift_name_decl_kind) << AL; + return false; + } + return true; +} + +static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Name; + SourceLocation Loc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc)) + return; + + if (!S.DiagnoseSwiftName(D, Name, Loc, AL)) + return; + + D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name)); +} + //===----------------------------------------------------------------------===// // Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// @@ -7558,6 +7864,9 @@ case ParsedAttr::AT_SwiftError: handleSwiftError(S, D, AL); break; + case ParsedAttr::AT_SwiftName: + handleSwiftName(S, D, AL); + break; case ParsedAttr::AT_SwiftObjCMembers: handleSimpleAttribute<SwiftObjCMembersAttr>(S, D, AL); break; Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -2592,6 +2592,9 @@ return false; } else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr)) NewAttr = S.mergeMinSizeAttr(D, *MA); + else if (const auto *SNA = dyn_cast<SwiftNameAttr>(Attr)) + NewAttr = S.mergeSwiftNameAttr(D, *SNA, SNA->getName(), + AMK == Sema::AMK_Override); else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr)) NewAttr = S.mergeOptimizeNoneAttr(D, *OA); else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr)) Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -1834,6 +1834,16 @@ } }; + /// Do a check to make sure \p Name looks like a legal argument for the + /// swift_name attribute applied to decl \p D. Raise a diagnostic if the name + /// is invalid for the given declaration. + /// + /// \p AL is used to provide caret diagnostics in case of a malformed name. + /// + /// \returns true if the name is a valid swift name for \p D, false otherwise. + bool DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc, + const ParsedAttr &AL); + /// A derivative of BoundTypeDiagnoser for which the diagnostic's type /// parameter is preceded by a 0/1 enum that is 1 if the type is sizeless. /// For example, a diagnostic with no other parameters would generally have @@ -3059,6 +3069,8 @@ SpeculativeLoadHardeningAttr * mergeSpeculativeLoadHardeningAttr(Decl *D, const SpeculativeLoadHardeningAttr &AL); + SwiftNameAttr *mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA, + StringRef Name, bool Override); OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, const AttributeCommonInfo &CI); InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL); Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3974,6 +3974,46 @@ def err_objc_attr_protocol_requires_definition : Error< "attribute %0 can only be applied to @protocol definitions, not forward declarations">; +// Swift attributes. +def warn_attr_swift_name_function + : Warning<"%0 attribute argument must be a string literal specifying a Swift function name">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_invalid_identifier + : Warning<"%0 attribute has invalid identifier for the %select{base|context|parameter}1 name">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_decl_kind + : Warning<"%0 attribute cannot be applied to this declaration">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_subscript_invalid_parameter + : Warning<"%0 attribute for 'subscript' must %select{be a getter or setter|" + "have at least one parameter|" + "have a 'self:' parameter}1">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_missing_parameters + : Warning<"%0 attribute is missing parameter label clause">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_setter_parameters + : Warning<"%0 attribute for setter must have one parameter for new value">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_multiple_selfs + : Warning<"%0 attribute cannot specify more than one 'self:' parameter">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_getter_parameters + : Warning<"%0 attribute for getter must not have any parameters besides 'self:'">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_subscript_setter_no_newValue + : Warning<"%0 attribute for 'subscript' setter must have a 'newValue:' parameter">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_subscript_setter_multiple_newValues + : Warning<"%0 attribute for 'subscript' setter cannot have multiple 'newValue:' parameters">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_subscript_getter_newValue + : Warning<"%0 attribute for 'subscript' getter cannot have a 'newValue:' parameter">, + InGroup<SwiftNameAttribute>; +def warn_attr_swift_name_num_params + : Warning<"too %select{few|many}0 parameters in %1 attribute (expected %2; got %3)">, + InGroup<SwiftNameAttribute>; + def err_attr_swift_error_no_error_parameter : Error< "%0 attribute can only be applied to a %select{function|method}1 with an " "error parameter">; Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -557,6 +557,7 @@ def StringPlusInt : DiagGroup<"string-plus-int">; def StringPlusChar : DiagGroup<"string-plus-char">; def StrncatSize : DiagGroup<"strncat-size">; +def SwiftNameAttribute : DiagGroup<"swift-name-attribute">; def IntInBoolContext : DiagGroup<"int-in-bool-context">; def TautologicalTypeLimitCompare : DiagGroup<"tautological-type-limit-compare">; def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">; Index: clang/include/clang/Basic/AttrDocs.td =================================================================== --- clang/include/clang/Basic/AttrDocs.td +++ clang/include/clang/Basic/AttrDocs.td @@ -3572,6 +3572,30 @@ }]; } +def SwiftNameDocs : Documentation { + let Category = SwiftDocs; + let Heading = "swift_name"; + let Content = [{ +The ``swift_name`` attribute provides the name of the declaration in Swift. If +this attribute is absent, the name is transformed according to the algorithm +built into the Swift compiler. + +The argument is a string literal that contains the Swift name of the function, +variable, or type. When renaming a function, the name may be a compound Swift +name. For a type, enum constant, property, or variable declaration, the name +must be a simple or qualified identifier. + + .. code-block:: c + + @interface URL + - (void) initWithString:(NSString *)s __attribute__((__swift_name__("URL.init(_:)"))) + @end + + void __attribute__((__swift_name__("squareRoot()"))) sqrt(double v) { + } + }]; +} + 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 @@ -2162,6 +2162,12 @@ let Documentation = [SwiftErrorDocs]; } +def SwiftName : InheritableAttr { + let Spellings = [GNU<"swift_name">]; + let Args = [StringArgument<"Name">]; + let Documentation = [SwiftNameDocs]; +} + def NoDeref : TypeAttr { let Spellings = [Clang<"noderef">]; let Documentation = [NoDerefDocs];
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits