|
20 | 20 | #include "swift/AST/Pattern.h"
|
21 | 21 | #include "swift/AST/Stmt.h"
|
22 | 22 | #include "swift/Basic/Assertions.h"
|
23 |
| -#include "swift/ClangImporter/CXXMethodBridging.h" |
| 23 | +#include "swift/ClangImporter/ClangImporterRequests.h" |
24 | 24 | #include "clang/AST/Mangle.h"
|
25 | 25 | #include "clang/Sema/DelayedDiagnostic.h"
|
26 | 26 |
|
@@ -2729,3 +2729,216 @@ SwiftDeclSynthesizer::synthesizeStaticFactoryForCXXForeignRef(
|
2729 | 2729 |
|
2730 | 2730 | return synthesizedFactories;
|
2731 | 2731 | }
|
| 2732 | + |
| 2733 | +/// Mark the given declaration as always deprecated for the given reason. |
| 2734 | +static void markDeprecated(Decl *decl, llvm::Twine message) { |
| 2735 | + ASTContext &ctx = decl->getASTContext(); |
| 2736 | + decl->getAttrs().add( |
| 2737 | + AvailableAttr::createUniversallyDeprecated( |
| 2738 | + ctx, ctx.AllocateCopy(message.str()))); |
| 2739 | +} |
| 2740 | + |
| 2741 | +/// Find an explicitly-provided "destroy" operation specified for the |
| 2742 | +/// given Clang type and return it. |
| 2743 | +FuncDecl *SwiftDeclSynthesizer::findExplicitDestroy( |
| 2744 | + NominalTypeDecl *nominal, const clang::RecordDecl *clangType) { |
| 2745 | + if (!clangType->hasAttrs()) |
| 2746 | + return nullptr; |
| 2747 | + |
| 2748 | + llvm::SmallPtrSet<FuncDecl *, 2> matchingDestroyFuncs; |
| 2749 | + llvm::TinyPtrVector<FuncDecl *> nonMatchingDestroyFuncs; |
| 2750 | + for (auto attr : clangType->getAttrs()) { |
| 2751 | + auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr); |
| 2752 | + if (!swiftAttr) |
| 2753 | + continue; |
| 2754 | + |
| 2755 | + auto destroyFuncName = swiftAttr->getAttribute(); |
| 2756 | + if (!destroyFuncName.consume_front("destroy:")) |
| 2757 | + continue; |
| 2758 | + |
| 2759 | + auto decls = getValueDeclsForName( |
| 2760 | + clangType, nominal->getASTContext(), destroyFuncName); |
| 2761 | + for (auto decl : decls) { |
| 2762 | + auto func = dyn_cast<FuncDecl>(decl); |
| 2763 | + if (!func) |
| 2764 | + continue; |
| 2765 | + |
| 2766 | + auto params = func->getParameters(); |
| 2767 | + if (params->size() != 1) { |
| 2768 | + nonMatchingDestroyFuncs.push_back(func); |
| 2769 | + continue; |
| 2770 | + } |
| 2771 | + |
| 2772 | + if (!params->get(0)->getInterfaceType()->isEqual( |
| 2773 | + nominal->getDeclaredInterfaceType())) { |
| 2774 | + nonMatchingDestroyFuncs.push_back(func); |
| 2775 | + continue; |
| 2776 | + } |
| 2777 | + |
| 2778 | + matchingDestroyFuncs.insert(func); |
| 2779 | + } |
| 2780 | + } |
| 2781 | + |
| 2782 | + switch (matchingDestroyFuncs.size()) { |
| 2783 | + case 0: |
| 2784 | + if (!nonMatchingDestroyFuncs.empty()) { |
| 2785 | + markDeprecated( |
| 2786 | + nominal, |
| 2787 | + "destroy function '" + |
| 2788 | + nonMatchingDestroyFuncs.front()->getName().getBaseName() |
| 2789 | + .userFacingName() + |
| 2790 | + "' must have a single parameter with type '" + |
| 2791 | + nominal->getDeclaredInterfaceType().getString() + "'"); |
| 2792 | + } |
| 2793 | + |
| 2794 | + return nullptr; |
| 2795 | + |
| 2796 | + case 1: |
| 2797 | + // Handled below. |
| 2798 | + break; |
| 2799 | + |
| 2800 | + default: { |
| 2801 | + auto iter = matchingDestroyFuncs.begin(); |
| 2802 | + auto first = *iter++; |
| 2803 | + auto second = *iter; |
| 2804 | + markDeprecated( |
| 2805 | + nominal, |
| 2806 | + "multiple destroy operations ('" + |
| 2807 | + first->getName().getBaseName().userFacingName() + |
| 2808 | + "' and '" + |
| 2809 | + second->getName().getBaseName().userFacingName() + |
| 2810 | + "') provided for type"); |
| 2811 | + return nullptr; |
| 2812 | + } |
| 2813 | + } |
| 2814 | + |
| 2815 | + auto destroyFunc = *matchingDestroyFuncs.begin(); |
| 2816 | + |
| 2817 | + // If this type isn't imported as noncopyable, we can't respect the request |
| 2818 | + // for a destroy operation. |
| 2819 | + ASTContext &ctx = ImporterImpl.SwiftContext; |
| 2820 | + auto semanticsKind = evaluateOrDefault( |
| 2821 | + ctx.evaluator, |
| 2822 | + CxxRecordSemantics({clangType, ctx, &ImporterImpl}), {}); |
| 2823 | + switch (semanticsKind) { |
| 2824 | + case CxxRecordSemanticsKind::Owned: |
| 2825 | + case CxxRecordSemanticsKind::Reference: |
| 2826 | + if (auto cxxRecord = dyn_cast<clang::CXXRecordDecl>(clangType)) { |
| 2827 | + if (!cxxRecord->hasTrivialDestructor()) { |
| 2828 | + markDeprecated( |
| 2829 | + nominal, |
| 2830 | + "destroy operation '" + |
| 2831 | + destroyFunc->getName().getBaseName().userFacingName() + |
| 2832 | + "' is not allowed on types with a non-trivial destructor"); |
| 2833 | + return nullptr; |
| 2834 | + } |
| 2835 | + } |
| 2836 | + |
| 2837 | + LLVM_FALLTHROUGH; |
| 2838 | + |
| 2839 | + case CxxRecordSemanticsKind::Trivial: |
| 2840 | + markDeprecated( |
| 2841 | + nominal, |
| 2842 | + "destroy operation '" + |
| 2843 | + destroyFunc->getName().getBaseName().userFacingName() + |
| 2844 | + "' is only allowed on non-copyable types; " |
| 2845 | + "did you mean to use SWIFT_NONCOPYABLE?"); |
| 2846 | + return nullptr; |
| 2847 | + |
| 2848 | + case CxxRecordSemanticsKind::Iterator: |
| 2849 | + case CxxRecordSemanticsKind::MissingLifetimeOperation: |
| 2850 | + case CxxRecordSemanticsKind::SwiftClassType: |
| 2851 | + return nullptr; |
| 2852 | + |
| 2853 | + case CxxRecordSemanticsKind::MoveOnly: |
| 2854 | + case CxxRecordSemanticsKind::UnavailableConstructors: |
| 2855 | + // Handled below. |
| 2856 | + break; |
| 2857 | + } |
| 2858 | + if (semanticsKind != CxxRecordSemanticsKind::MoveOnly) { |
| 2859 | + return nullptr; |
| 2860 | + } |
| 2861 | + |
| 2862 | + return destroyFunc; |
| 2863 | +} |
| 2864 | + |
| 2865 | +/// Function body synthesizer for a deinit of a noncopyable type, which |
| 2866 | +/// passes "self" to the given "destroy" function. |
| 2867 | +static std::pair<BraceStmt *, bool> |
| 2868 | +synthesizeDeinitBodyForCustomDestroy( |
| 2869 | + AbstractFunctionDecl *deinitFunc, void *opaqueDestroyFunc) { |
| 2870 | + auto deinit = cast<DestructorDecl>(deinitFunc); |
| 2871 | + auto destroyFunc = static_cast<FuncDecl *>(opaqueDestroyFunc); |
| 2872 | + |
| 2873 | + ASTContext &ctx = deinit->getASTContext(); |
| 2874 | + auto funcRef = new (ctx) DeclRefExpr( |
| 2875 | + destroyFunc, DeclNameLoc(), /*Implicit=*/true); |
| 2876 | + auto selfRef = new (ctx) DeclRefExpr( |
| 2877 | + deinit->getImplicitSelfDecl(), DeclNameLoc(), /*Implicit=*/true); |
| 2878 | + auto callExpr = CallExpr::createImplicit( |
| 2879 | + ctx, funcRef, |
| 2880 | + ArgumentList::createImplicit( |
| 2881 | + ctx, |
| 2882 | + { Argument(SourceLoc(), Identifier(), selfRef)} |
| 2883 | + ) |
| 2884 | + ); |
| 2885 | + |
| 2886 | + auto braceStmt = BraceStmt::createImplicit(ctx, { ASTNode(callExpr) }); |
| 2887 | + return std::make_pair(braceStmt, /*typechecked=*/false); |
| 2888 | +} |
| 2889 | + |
| 2890 | +void SwiftDeclSynthesizer::addExplicitDeinitIfRequired( |
| 2891 | + NominalTypeDecl *nominal, const clang::RecordDecl *clangType) { |
| 2892 | + auto destroyFunc = findExplicitDestroy(nominal, clangType); |
| 2893 | + if (!destroyFunc) |
| 2894 | + return; |
| 2895 | + |
| 2896 | + ASTContext &ctx = nominal->getASTContext(); |
| 2897 | + auto destructor = new (ctx) DestructorDecl(SourceLoc(), nominal); |
| 2898 | + destructor->setSynthesized(true); |
| 2899 | + destructor->copyFormalAccessFrom(nominal, /*sourceIsParentContext*/true); |
| 2900 | + destructor->setBodySynthesizer( |
| 2901 | + synthesizeDeinitBodyForCustomDestroy, destroyFunc); |
| 2902 | + |
| 2903 | + nominal->addMember(destructor); |
| 2904 | +} |
| 2905 | + |
| 2906 | +FuncDecl *SwiftDeclSynthesizer::makeAvailabilityDomainPredicate( |
| 2907 | + const clang::VarDecl *var) { |
| 2908 | + ASTContext &ctx = ImporterImpl.SwiftContext; |
| 2909 | + clang::ASTContext &clangCtx = var->getASTContext(); |
| 2910 | + auto featureInfo = |
| 2911 | + clangCtx.getFeatureAvailInfo(const_cast<clang::VarDecl *>(var)); |
| 2912 | + |
| 2913 | + // If the decl doesn't represent and availability domain, skip it. |
| 2914 | + if (featureInfo.first.empty()) |
| 2915 | + return nullptr; |
| 2916 | + |
| 2917 | + // Only dynamic availability domains require a predicate function. |
| 2918 | + if (featureInfo.second.Kind != clang::FeatureAvailKind::Dynamic) |
| 2919 | + return nullptr; |
| 2920 | + |
| 2921 | + if (!featureInfo.second.Call) |
| 2922 | + return nullptr; |
| 2923 | + |
| 2924 | + // Synthesize `func __swift_XYZ_isAvailable() -> Builtin.Int1 { ... }`. |
| 2925 | + std::string s; |
| 2926 | + llvm::raw_string_ostream os(s); |
| 2927 | + os << "__swift_" << featureInfo.first << "_isAvailable"; |
| 2928 | + DeclName funcName(ctx, DeclBaseName(ctx.getIdentifier(s)), |
| 2929 | + ParameterList::createEmpty(ctx)); |
| 2930 | + |
| 2931 | + auto funcDecl = FuncDecl::createImplicit( |
| 2932 | + ctx, StaticSpellingKind::None, funcName, SourceLoc(), /*Async=*/false, |
| 2933 | + /*Throws=*/false, Type(), {}, ParameterList::createEmpty(ctx), |
| 2934 | + BuiltinIntegerType::get(1, ctx), ImporterImpl.ImportedHeaderUnit); |
| 2935 | + funcDecl->setBodySynthesizer(synthesizeAvailabilityDomainPredicateBody, |
| 2936 | + (void *)var); |
| 2937 | + funcDecl->setAccess(AccessLevel::Public); |
| 2938 | + funcDecl->getAttrs().add(new (ctx) |
| 2939 | + AlwaysEmitIntoClientAttr(/*IsImplicit=*/true)); |
| 2940 | + |
| 2941 | + ImporterImpl.availabilityDomainPredicates[var] = funcDecl; |
| 2942 | + |
| 2943 | + return funcDecl; |
| 2944 | +} |
0 commit comments