diff options
author | Saleem Abdulrasool <compnerd@compnerd.org> | 2020-09-08 21:19:43 +0000 |
---|---|---|
committer | Saleem Abdulrasool <compnerd@compnerd.org> | 2020-09-11 21:20:38 +0000 |
commit | f5ab5b20fb2aae5567e6c50cc642ff63eb2146d4 (patch) | |
tree | fd363e7505b07835e25bd1406111e7f907adda7e /clang/lib | |
parent | ccb4124a4172bf2cb2e1cd7c253f0f1654fce294 (diff) | |
download | llvm-f5ab5b20fb2aae5567e6c50cc642ff63eb2146d4.zip llvm-f5ab5b20fb2aae5567e6c50cc642ff63eb2146d4.tar.gz llvm-f5ab5b20fb2aae5567e6c50cc642ff63eb2146d4.tar.bz2 |
Sema: add support for `__attribute__((__swift_error__))`
Introduce a new attribute that is used to indicate the error handling
convention used by a function. This is used to translate the error
semantics from the decorated interface to a compatible Swift interface.
The supported error convention is one of:
- none: no error handling
- nonnull_error: a non-null error parameter indicates an error signifier
- null_result: a return value of NULL is an error signifier
- zero_result: a return value of 0 is an error signifier
- nonzero_result: a non-zero return value is an error signifier
Since this is the first of the attributes needed to support the semantic
annotation for Swift, this change also includes the necessary supporting
infrastructure for a new category of attributes (Swift).
This is based on the work of the original changes in
https://github.com/llvm/llvm-project-staging/commit/8afaf3aad2af43cfedca7a24cd817848c4e95c0c
Differential Revision: https://reviews.llvm.org/D87331
Reviewed By: John McCall, Aaron Ballman, Dmitri Gribenko
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 49fd22f..e317211 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5524,6 +5524,102 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) ObjCPreciseLifetimeAttr(S.Context, AL)); } +static bool isErrorParameter(Sema &S, QualType QT) { + const auto *PT = QT->getAs<PointerType>(); + if (!PT) + return false; + + QualType Pointee = PT->getPointeeType(); + + // Check for NSError**. + if (const auto *OPT = Pointee->getAs<ObjCObjectPointerType>()) + if (const auto *ID = OPT->getInterfaceDecl()) + if (ID->getIdentifier() == S.getNSErrorIdent()) + return true; + + // Check for CFError**. + if (const auto *PT = Pointee->getAs<PointerType>()) + if (const auto *RT = PT->getPointeeType()->getAs<RecordType>()) + if (S.isCFError(RT->getDecl())) + return true; + + return false; +} + +static void handleSwiftError(Sema &S, Decl *D, const ParsedAttr &AL) { + auto hasErrorParameter = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { + for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) { + if (isErrorParameter(S, getFunctionOrMethodParamType(D, I))) + return true; + } + + S.Diag(AL.getLoc(), diag::err_attr_swift_error_no_error_parameter) + << AL << isa<ObjCMethodDecl>(D); + return false; + }; + + auto hasPointerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { + // - C, ObjC, and block pointers are definitely okay. + // - References are definitely not okay. + // - nullptr_t is weird, but acceptable. + QualType RT = getFunctionOrMethodResultType(D); + if (RT->hasPointerRepresentation() && !RT->isReferenceType()) + return true; + + S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type) + << AL << AL.getArgAsIdent(0)->Ident->getName() << isa<ObjCMethodDecl>(D) + << /*pointer*/ 1; + return false; + }; + + auto hasIntegerResult = [](Sema &S, Decl *D, const ParsedAttr &AL) -> bool { + QualType RT = getFunctionOrMethodResultType(D); + if (RT->isIntegralType(S.Context)) + return true; + + S.Diag(AL.getLoc(), diag::err_attr_swift_error_return_type) + << AL << AL.getArgAsIdent(0)->Ident->getName() << isa<ObjCMethodDecl>(D) + << /*integral*/ 0; + return false; + }; + + if (D->isInvalidDecl()) + return; + + IdentifierLoc *Loc = AL.getArgAsIdent(0); + SwiftErrorAttr::ConventionKind Convention; + if (!SwiftErrorAttr::ConvertStrToConventionKind(Loc->Ident->getName(), + Convention)) { + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) + << AL << Loc->Ident; + return; + } + + switch (Convention) { + case SwiftErrorAttr::None: + // No additional validation required. + break; + + case SwiftErrorAttr::NonNullError: + if (!hasErrorParameter(S, D, AL)) + return; + break; + + case SwiftErrorAttr::NullResult: + if (!hasErrorParameter(S, D, AL) || !hasPointerResult(S, D, AL)) + return; + break; + + case SwiftErrorAttr::NonZeroResult: + case SwiftErrorAttr::ZeroResult: + if (!hasErrorParameter(S, D, AL) || !hasIntegerResult(S, D, AL)) + return; + break; + } + + D->addAttr(::new (S.Context) SwiftErrorAttr(S.Context, AL, Convention)); +} + //===----------------------------------------------------------------------===// // Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// @@ -7436,6 +7532,11 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleTypeTagForDatatypeAttr(S, D, AL); break; + // Swift attributes. + case ParsedAttr::AT_SwiftError: + handleSwiftError(S, D, AL); + break; + // XRay attributes. case ParsedAttr::AT_XRayLogArgs: handleXRayLogArgsAttr(S, D, AL); |