Commit eddd1d19 authored by Alex Lorenz's avatar Alex Lorenz
Browse files

[clang] add a `swift_async_name` attribute

The swift_async_name attribute provides a name for a function/method that can be used
to call the async overload of this method from Swift. This name specified in this attribute
assumes that the last parameter in the function/method its applied to is removed when
Swift invokes it, as the the Swift's await/async transformation implicitly constructs the callback.

Differential Revision: https://reviews.llvm.org/D92355
parent 03dcd57e
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -2149,6 +2149,13 @@ def Regparm : TypeAttr {
  let ASTNode = 0;
}

def SwiftAsyncName : InheritableAttr {
  let Spellings = [GNU<"swift_async_name">];
  let Args = [StringArgument<"Name">];
  let Subjects = SubjectList<[ObjCMethod, Function], ErrorDiag>;
  let Documentation = [SwiftAsyncNameDocs];
}

def SwiftAttr : InheritableAttr {
  let Spellings = [GNU<"swift_attr">];
  let Args = [StringArgument<"Attribute">];
+21 −0
Original line number Diff line number Diff line
@@ -3628,6 +3628,27 @@ Swift.
  }];
}

def SwiftAsyncNameDocs : Documentation {
  let Category = SwiftDocs;
  let Heading = "swift_async_name";
  let Content = [{
The ``swift_async_name`` attribute provides the name of the ``async`` overload for
the given 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 or
method. The name may be a compound Swift name. The function or method with such
an attribute must have more than zero parameters, as its last parameter is
assumed to be a callback that's eliminated in the Swift ``async`` name.

  .. code-block:: objc

    @interface URL
    + (void) loadContentsFrom:(URL *)url callback:(void (^)(NSData *))data __attribute__((__swift_async_name__("URL.loadContentsFrom(_:)")))
    @end
  }];
}

def SwiftAttrDocs : Documentation {
  let Category = SwiftDocs;
  let Heading = "swift_attr";
+6 −1
Original line number Diff line number Diff line
@@ -4028,7 +4028,12 @@ 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)">,
  : Warning<"too %select{few|many}0 parameters in the signature specified by "
            "the %1 attribute (expected %2; got %3)">,
    InGroup<SwiftNameAttribute>;
def warn_attr_swift_name_decl_missing_params
  : Warning<"%0 attribute cannot be applied to a %select{function|method}1 "
            "with no parameters">,
    InGroup<SwiftNameAttribute>;
def err_attr_swift_error_no_error_parameter : Error<
+1 −1
Original line number Diff line number Diff line
@@ -1977,7 +1977,7 @@ public:
  ///
  /// \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);
                         const ParsedAttr &AL, bool IsAsync);
  /// 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.
+32 −6
Original line number Diff line number Diff line
@@ -5922,7 +5922,7 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc,
}

bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
                             const ParsedAttr &AL) {
                             const ParsedAttr &AL, bool IsAsync) {
  if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
    ArrayRef<ParmVarDecl*> Params;
    unsigned ParamCount;
@@ -5943,6 +5943,16 @@ bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
      }
    }

    // The async name drops the last callback parameter.
    if (IsAsync) {
      if (ParamCount == 0) {
        Diag(Loc, diag::warn_attr_swift_name_decl_missing_params)
            << AL << isa<ObjCMethodDecl>(D);
        return false;
      }
      ParamCount -= 1;
    }

    unsigned SwiftParamCount;
    bool IsSingleParamInit;
    if (!validateSwiftFunctionName(*this, AL, Loc, Name,
@@ -5976,10 +5986,11 @@ bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc,
          << SwiftParamCount;
      return false;
    }
  } else if (isa<EnumConstantDecl>(D) || isa<ObjCProtocolDecl>(D) ||
  } 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)) {
              isa<IndirectFieldDecl>(D) || isa<FieldDecl>(D)) &&
             !IsAsync) {
    StringRef ContextName, BaseName;

    std::tie(ContextName, BaseName) = Name.split('.');
@@ -6010,12 +6021,24 @@ static void handleSwiftName(Sema &S, Decl *D, const ParsedAttr &AL) {
  if (!S.checkStringLiteralArgumentAttr(AL, 0, Name, &Loc))
    return;

  if (!S.DiagnoseSwiftName(D, Name, Loc, AL))
  if (!S.DiagnoseSwiftName(D, Name, Loc, AL, /*IsAsync=*/false))
    return;

  D->addAttr(::new (S.Context) SwiftNameAttr(S.Context, AL, Name));
}

static void handleSwiftAsyncName(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, /*IsAsync=*/true))
    return;

  D->addAttr(::new (S.Context) SwiftAsyncNameAttr(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))
@@ -7951,6 +7974,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
    break;

  // Swift attributes.
  case ParsedAttr::AT_SwiftAsyncName:
    handleSwiftAsyncName(S, D, AL);
    break;
  case ParsedAttr::AT_SwiftAttr:
    handleSwiftAttrAttr(S, D, AL);
    break;
Loading