aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorSaleem Abdulrasool <compnerd@compnerd.org>2020-09-08 21:19:43 +0000
committerSaleem Abdulrasool <compnerd@compnerd.org>2020-09-11 21:20:38 +0000
commitf5ab5b20fb2aae5567e6c50cc642ff63eb2146d4 (patch)
treefd363e7505b07835e25bd1406111e7f907adda7e /clang/lib
parentccb4124a4172bf2cb2e1cd7c253f0f1654fce294 (diff)
downloadllvm-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.cpp101
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);