|
23 | 23 | #include "swift/AST/Stmt.h"
|
24 | 24 | #include "swift/AST/TypeCheckRequests.h"
|
25 | 25 | #include "swift/Basic/Assertions.h"
|
| 26 | +#include "swift/ClangImporter/ClangImporterRequests.h" |
26 | 27 | #include "clang/AST/Mangle.h"
|
27 | 28 | #include "clang/Sema/DelayedDiagnostic.h"
|
28 | 29 |
|
@@ -2809,6 +2810,179 @@ synthesizeAvailabilityDomainPredicateBody(AbstractFunctionDecl *afd,
|
2809 | 2810 | return {body, /*isTypeChecked=*/false};
|
2810 | 2811 | }
|
2811 | 2812 |
|
| 2813 | +/// Mark the given declaration as always deprecated for the given reason. |
| 2814 | +static void markDeprecated(Decl *decl, llvm::Twine message) { |
| 2815 | + ASTContext &ctx = decl->getASTContext(); |
| 2816 | + decl->getAttrs().add( |
| 2817 | + AvailableAttr::createUniversallyDeprecated( |
| 2818 | + ctx, ctx.AllocateCopy(message.str()))); |
| 2819 | +} |
| 2820 | + |
| 2821 | +/// Find an explicitly-provided "destroy" operation specified for the |
| 2822 | +/// given Clang type and return it. |
| 2823 | +FuncDecl *SwiftDeclSynthesizer::findExplicitDestroy( |
| 2824 | + NominalTypeDecl *nominal, const clang::RecordDecl *clangType) { |
| 2825 | + if (!clangType->hasAttrs()) |
| 2826 | + return nullptr; |
| 2827 | + |
| 2828 | + llvm::SmallPtrSet<FuncDecl *, 2> matchingDestroyFuncs; |
| 2829 | + llvm::TinyPtrVector<FuncDecl *> nonMatchingDestroyFuncs; |
| 2830 | + for (auto attr : clangType->getAttrs()) { |
| 2831 | + auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr); |
| 2832 | + if (!swiftAttr) |
| 2833 | + continue; |
| 2834 | + |
| 2835 | + auto destroyFuncName = swiftAttr->getAttribute(); |
| 2836 | + if (!destroyFuncName.consume_front("destroy:")) |
| 2837 | + continue; |
| 2838 | + |
| 2839 | + auto decls = getValueDeclsForName( |
| 2840 | + clangType, nominal->getASTContext(), destroyFuncName); |
| 2841 | + for (auto decl : decls) { |
| 2842 | + auto func = dyn_cast<FuncDecl>(decl); |
| 2843 | + if (!func) |
| 2844 | + continue; |
| 2845 | + |
| 2846 | + auto params = func->getParameters(); |
| 2847 | + if (params->size() != 1) { |
| 2848 | + nonMatchingDestroyFuncs.push_back(func); |
| 2849 | + continue; |
| 2850 | + } |
| 2851 | + |
| 2852 | + if (!params->get(0)->getInterfaceType()->isEqual( |
| 2853 | + nominal->getDeclaredInterfaceType())) { |
| 2854 | + nonMatchingDestroyFuncs.push_back(func); |
| 2855 | + continue; |
| 2856 | + } |
| 2857 | + |
| 2858 | + matchingDestroyFuncs.insert(func); |
| 2859 | + } |
| 2860 | + } |
| 2861 | + |
| 2862 | + switch (matchingDestroyFuncs.size()) { |
| 2863 | + case 0: |
| 2864 | + if (!nonMatchingDestroyFuncs.empty()) { |
| 2865 | + markDeprecated( |
| 2866 | + nominal, |
| 2867 | + "destroy function '" + |
| 2868 | + nonMatchingDestroyFuncs.front()->getName().getBaseName() |
| 2869 | + .userFacingName() + |
| 2870 | + "' must have a single parameter with type '" + |
| 2871 | + nominal->getDeclaredInterfaceType().getString() + "'"); |
| 2872 | + } |
| 2873 | + |
| 2874 | + return nullptr; |
| 2875 | + |
| 2876 | + case 1: |
| 2877 | + // Handled below. |
| 2878 | + break; |
| 2879 | + |
| 2880 | + default: { |
| 2881 | + auto iter = matchingDestroyFuncs.begin(); |
| 2882 | + auto first = *iter++; |
| 2883 | + auto second = *iter; |
| 2884 | + markDeprecated( |
| 2885 | + nominal, |
| 2886 | + "multiple destroy operations ('" + |
| 2887 | + first->getName().getBaseName().userFacingName() + |
| 2888 | + "' and '" + |
| 2889 | + second->getName().getBaseName().userFacingName() + |
| 2890 | + "') provided for type"); |
| 2891 | + return nullptr; |
| 2892 | + } |
| 2893 | + } |
| 2894 | + |
| 2895 | + auto destroyFunc = *matchingDestroyFuncs.begin(); |
| 2896 | + |
| 2897 | + // If this type isn't imported as noncopyable, we can't respect the request |
| 2898 | + // for a destroy operation. |
| 2899 | + ASTContext &ctx = ImporterImpl.SwiftContext; |
| 2900 | + auto semanticsKind = evaluateOrDefault( |
| 2901 | + ctx.evaluator, |
| 2902 | + CxxRecordSemantics({clangType, ctx, &ImporterImpl}), {}); |
| 2903 | + switch (semanticsKind) { |
| 2904 | + case CxxRecordSemanticsKind::Owned: |
| 2905 | + case CxxRecordSemanticsKind::Reference: |
| 2906 | + if (auto cxxRecord = dyn_cast<clang::CXXRecordDecl>(clangType)) { |
| 2907 | + if (!cxxRecord->hasTrivialDestructor()) { |
| 2908 | + markDeprecated( |
| 2909 | + nominal, |
| 2910 | + "destroy operation '" + |
| 2911 | + destroyFunc->getName().getBaseName().userFacingName() + |
| 2912 | + "' is not allowed on types with a non-trivial destructor"); |
| 2913 | + return nullptr; |
| 2914 | + } |
| 2915 | + } |
| 2916 | + |
| 2917 | + LLVM_FALLTHROUGH; |
| 2918 | + |
| 2919 | + case CxxRecordSemanticsKind::Trivial: |
| 2920 | + markDeprecated( |
| 2921 | + nominal, |
| 2922 | + "destroy operation '" + |
| 2923 | + destroyFunc->getName().getBaseName().userFacingName() + |
| 2924 | + "' is only allowed on non-copyable types; " |
| 2925 | + "did you mean to use SWIFT_NONCOPYABLE?"); |
| 2926 | + return nullptr; |
| 2927 | + |
| 2928 | + case CxxRecordSemanticsKind::Iterator: |
| 2929 | + case CxxRecordSemanticsKind::MissingLifetimeOperation: |
| 2930 | + case CxxRecordSemanticsKind::SwiftClassType: |
| 2931 | + return nullptr; |
| 2932 | + |
| 2933 | + case CxxRecordSemanticsKind::MoveOnly: |
| 2934 | + case CxxRecordSemanticsKind::UnavailableConstructors: |
| 2935 | + // Handled below. |
| 2936 | + break; |
| 2937 | + } |
| 2938 | + if (semanticsKind != CxxRecordSemanticsKind::MoveOnly) { |
| 2939 | + return nullptr; |
| 2940 | + } |
| 2941 | + |
| 2942 | + return destroyFunc; |
| 2943 | +} |
| 2944 | + |
| 2945 | +/// Function body synthesizer for a deinit of a noncopyable type, which |
| 2946 | +/// passes "self" to the given "destroy" function. |
| 2947 | +static std::pair<BraceStmt *, bool> |
| 2948 | +synthesizeDeinitBodyForCustomDestroy( |
| 2949 | + AbstractFunctionDecl *deinitFunc, void *opaqueDestroyFunc) { |
| 2950 | + auto deinit = cast<DestructorDecl>(deinitFunc); |
| 2951 | + auto destroyFunc = static_cast<FuncDecl *>(opaqueDestroyFunc); |
| 2952 | + |
| 2953 | + ASTContext &ctx = deinit->getASTContext(); |
| 2954 | + auto funcRef = new (ctx) DeclRefExpr( |
| 2955 | + destroyFunc, DeclNameLoc(), /*Implicit=*/true); |
| 2956 | + auto selfRef = new (ctx) DeclRefExpr( |
| 2957 | + deinit->getImplicitSelfDecl(), DeclNameLoc(), /*Implicit=*/true); |
| 2958 | + auto callExpr = CallExpr::createImplicit( |
| 2959 | + ctx, funcRef, |
| 2960 | + ArgumentList::createImplicit( |
| 2961 | + ctx, |
| 2962 | + { Argument(SourceLoc(), Identifier(), selfRef)} |
| 2963 | + ) |
| 2964 | + ); |
| 2965 | + |
| 2966 | + auto braceStmt = BraceStmt::createImplicit(ctx, { ASTNode(callExpr) }); |
| 2967 | + return std::make_pair(braceStmt, /*typechecked=*/false); |
| 2968 | +} |
| 2969 | + |
| 2970 | +void SwiftDeclSynthesizer::addExplicitDeinitIfRequired( |
| 2971 | + NominalTypeDecl *nominal, const clang::RecordDecl *clangType) { |
| 2972 | + auto destroyFunc = findExplicitDestroy(nominal, clangType); |
| 2973 | + if (!destroyFunc) |
| 2974 | + return; |
| 2975 | + |
| 2976 | + ASTContext &ctx = nominal->getASTContext(); |
| 2977 | + auto destructor = new (ctx) DestructorDecl(SourceLoc(), nominal); |
| 2978 | + destructor->setSynthesized(true); |
| 2979 | + destructor->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/true); |
| 2980 | + destructor->setBodySynthesizer( |
| 2981 | + synthesizeDeinitBodyForCustomDestroy, destroyFunc); |
| 2982 | + |
| 2983 | + nominal->addMember(destructor); |
| 2984 | +} |
| 2985 | + |
2812 | 2986 | FuncDecl *SwiftDeclSynthesizer::makeAvailabilityDomainPredicate(
|
2813 | 2987 | const clang::VarDecl *var) {
|
2814 | 2988 | ASTContext &ctx = ImporterImpl.SwiftContext;
|
|
0 commit comments