From b80ab98ac04d2bcf97d1f9f7636140768bdf3524 Mon Sep 17 00:00:00 2001 From: John Hui Date: Thu, 6 Nov 2025 23:44:16 -0800 Subject: [PATCH 1/6] [cxx-interop] Check template argument safety in ClangDeclExplicitSafety Checking this upon import may overlook annotations that explicitly mark a type as safe (or unsafe). Instead, we consolidate this logic in the ClangDeclExplicitSafety request. rdar://163196609 --- lib/ClangImporter/ClangImporter.cpp | 59 ++++++++++++++----- .../Interop/Cxx/class/safe-interop-mode.swift | 29 +++++++++ 2 files changed, 73 insertions(+), 15 deletions(-) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 6694955b31392..e42622fdfc37d 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -8777,14 +8777,14 @@ static bool hasUnsafeType(Evaluator &evaluator, clang::QualType clangType) { // Function pointers are okay. if (pointeeType->isFunctionType()) return false; - + // Pointers to record types are okay if they come in as foreign reference // types. - if (auto recordDecl = pointeeType->getAsRecordDecl()) { + if (auto *recordDecl = pointeeType->getAsRecordDecl()) { if (hasImportAsRefAttr(recordDecl)) return false; } - + // All other pointers are considered unsafe. return true; } @@ -8793,19 +8793,25 @@ static bool hasUnsafeType(Evaluator &evaluator, clang::QualType clangType) { if (auto recordDecl = clangType->getAsTagDecl()) { // If we reached this point the types is not imported as a shared reference, // so we don't need to check the bases whether they are shared references. - auto safety = evaluateOrDefault( - evaluator, ClangDeclExplicitSafety({recordDecl, false}), - ExplicitSafety::Unspecified); - switch (safety) { - case ExplicitSafety::Unsafe: - return true; - - case ExplicitSafety::Safe: - case ExplicitSafety::Unspecified: - return false; - } + auto req = ClangDeclExplicitSafety({recordDecl, false}); + if (evaluator.hasActiveRequest(req)) + // Normally, using hasActiveRequest() to avoid cycles is an anti-pattern + // because cycles should be treated as errors. However, cycles are allowed + // in C++ template, e.g.: + // + // template class Foo { ... }; // throws away template arg + // template class Bar : Foo> { ... }; + // + // A common use case of cyclic templates is the CRTP pattern. + // + // We need to avoid request cycles, so if there is already an active + // request for this type, just assume it is not explicitly unsafe for now + // (i.e., as if it were unspecified). + return false; + return evaluateOrDefault(evaluator, req, ExplicitSafety::Unspecified) == + ExplicitSafety::Unsafe; } - + // Everything else is safe. return false; } @@ -8845,6 +8851,29 @@ ClangDeclExplicitSafety::evaluate(Evaluator &evaluator, ClangTypeEscapability({recordDecl->getTypeForDecl(), nullptr}), CxxEscapability::Unknown) != CxxEscapability::Unknown) return ExplicitSafety::Safe; + + // A template class is unsafe if any of its type arguments are unsafe. + // Note that this does not rely on the record being defined. + if (const auto *ctsd = + dyn_cast(recordDecl)) { + for (auto arg : ctsd->getTemplateArgs().asArray()) { + switch (arg.getKind()) { + case clang::TemplateArgument::Type: + if (hasUnsafeType(evaluator, arg.getAsType())) + return ExplicitSafety::Unsafe; + break; + case clang::TemplateArgument::Pack: + for (auto pkArg : arg.getPackAsArray()) { + if (pkArg.getKind() == clang::TemplateArgument::Type && + hasUnsafeType(evaluator, pkArg.getAsType())) + return ExplicitSafety::Unsafe; + } + break; + default: + continue; + } + } + } // If we don't have a definition, leave it unspecified. recordDecl = recordDecl->getDefinition(); diff --git a/test/Interop/Cxx/class/safe-interop-mode.swift b/test/Interop/Cxx/class/safe-interop-mode.swift index 2696b88b19c2e..11eac1ce830f4 100644 --- a/test/Interop/Cxx/class/safe-interop-mode.swift +++ b/test/Interop/Cxx/class/safe-interop-mode.swift @@ -83,6 +83,17 @@ struct OwnedData { void takeSharedObject(SharedObject *) const; }; +// A class template that throws away its type argument. +// +// If this template is instantiated with an unsafe type, it should be considered +// unsafe even if that type is never used. +template struct TTake {}; + +using TTakeInt = TTake; +using TTakePtr = TTake; +using TTakeSafeTuple = TTake; +using TTakeUnsafeTuple = TTake; + struct HoldsShared { SharedObject* obj; @@ -184,3 +195,21 @@ func useSharedReference(frt: DerivedFromSharedObject, h: HoldsShared) { let _ = frt let _ = h.getObj() } + +func useTTakeInt(x: TTakeInt) { + _ = x +} + +func useTTakePtr(x: TTakePtr) { + // expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}} + _ = x // expected-note{{reference to parameter 'x' involves unsafe type}} +} + +func useTTakeSafeTuple(x: TTakeSafeTuple) { + _ = x +} + +func useTTakeUnsafeTuple(x: TTakeUnsafeTuple) { + // expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}} + _ = x // expected-note{{reference to parameter 'x' involves unsafe type}} +} From 3255ffbd74aa77536939891ee251561f4ef4a3eb Mon Sep 17 00:00:00 2001 From: John Hui Date: Thu, 6 Nov 2025 23:45:46 -0800 Subject: [PATCH 2/6] [cxx-interop] Do not import template type arguments Prior to this patch, we eagerly imported template type arguments. A consequence of doing so is that we over-instantiate (potentially unused) type arguments, which causes unnecessary errors. The only apparent use we have for these type arguments are to check whether they are unsafe, so that we can mark the instantiated type as unsafe as well... even if the instantiated type does not use its unsafe template type argument at all. Using un-instantiatable types in template type arguments is supported in C++. The test case included in this patch validates this behavior, for both missing member and incomplete type errors. Note, also, that as of this patch, dumping the module interface of CxxModule actually causes swift-ide-test to emit compiler errors, since it tries to instantiate the invalid types MissingMember and IncompleteField. However, these errors are simply swallowed by swift-ide-test, so they should be harmless, though we should probably get rid of them entirely in future work. rdar://145238539 --- lib/ClangImporter/ImportDecl.cpp | 28 ---------- .../sfinae-template-type-arguments.swift | 53 +++++++++++++++++++ 2 files changed, 53 insertions(+), 28 deletions(-) create mode 100644 test/Interop/Cxx/templates/sfinae-template-type-arguments.swift diff --git a/lib/ClangImporter/ImportDecl.cpp b/lib/ClangImporter/ImportDecl.cpp index 3a5312f4ce622..02eca57db7aeb 100644 --- a/lib/ClangImporter/ImportDecl.cpp +++ b/lib/ClangImporter/ImportDecl.cpp @@ -2299,34 +2299,6 @@ namespace { } } - // We have to do this after populating ImportedDecls to avoid importing - // the same decl multiple times. Also after we imported the bases. - if (const auto *ctsd = - dyn_cast(decl)) { - for (auto arg : ctsd->getTemplateArgs().asArray()) { - llvm::SmallVector nonPackArgs; - if (arg.getKind() == clang::TemplateArgument::Pack) { - auto pack = arg.getPackAsArray(); - nonPackArgs.assign(pack.begin(), pack.end()); - } else { - nonPackArgs.push_back(arg); - } - for (auto realArg : nonPackArgs) { - if (realArg.getKind() != clang::TemplateArgument::Type) - continue; - auto SwiftType = Impl.importTypeIgnoreIUO( - realArg.getAsType(), ImportTypeKind::Abstract, - [](Diagnostic &&diag) {}, false, Bridgeability::None, - ImportTypeAttrs()); - if (SwiftType && SwiftType->isUnsafe()) { - auto attr = new (Impl.SwiftContext) UnsafeAttr(/*implicit=*/true); - result->getAttrs().add(attr); - break; - } - } - } - } - bool isNonEscapable = false; if (evaluateOrDefault( Impl.SwiftContext.evaluator, diff --git a/test/Interop/Cxx/templates/sfinae-template-type-arguments.swift b/test/Interop/Cxx/templates/sfinae-template-type-arguments.swift new file mode 100644 index 0000000000000..e24b8bfe842ef --- /dev/null +++ b/test/Interop/Cxx/templates/sfinae-template-type-arguments.swift @@ -0,0 +1,53 @@ +// RUN: split-file %s %t +// RUN: %target-clang -c -o /dev/null -Xclang -verify -I %t/Inputs %t/cxx.cpp +// RUN: %target-swift-frontend -typecheck -verify -cxx-interoperability-mode=default -I %t%{fs-sep}Inputs -verify-additional-file %t%{fs-sep}Inputs%{fs-sep}CxxHeader.h %t%{fs-sep}main.swift +// RUN: %target-swift-ide-test -print-module -module-to-print=CxxModule -I %t/Inputs -source-filename=x -cxx-interoperability-mode=default | %FileCheck %t/Inputs/CxxHeader.h + +//--- Inputs/module.modulemap +module CxxModule { + requires cplusplus + header "CxxHeader.h" +} + +//--- Inputs/CxxHeader.h +#pragma once + +struct Empty {}; +template struct MissingMember { typename T::Missing member; }; +using SUB = MissingMember; + +struct Incomplete; +template struct IncompleteField { T member; }; +using INC = IncompleteField; + +template struct DefaultedTemplateArgs {}; +using DefaultedTemplateArgsInst = DefaultedTemplateArgs<>; + +// CHECK: struct DefaultedTemplateArgs, IncompleteField> { +// CHECK: } +// CHECK: typealias DefaultedTemplateArgsInst = DefaultedTemplateArgs, IncompleteField> + +template struct ThrowsAwayTemplateArgs {}; +using ThrowsAwayTemplateArgsInst = ThrowsAwayTemplateArgs; + +// CHECK: struct ThrowsAwayTemplateArgs, IncompleteField> { +// CHECK: } +// CHECK: typealias ThrowsAwayTemplateArgsInst = ThrowsAwayTemplateArgs, IncompleteField> + +//--- cxx.cpp +// expected-no-diagnostics +#include +void make(void) { + DefaultedTemplateArgs<> dta{}; + DefaultedTemplateArgsInst dtai{}; + + ThrowsAwayTemplateArgs tata{}; + ThrowsAwayTemplateArgsInst tatai{}; +} + +//--- main.swift +import CxxModule +func make() { + let _: DefaultedTemplateArgsInst = .init() + let _: ThrowsAwayTemplateArgsInst = .init() +} From 6c997ae5612b5e2da5b44fbdd94e50bb412bc83b Mon Sep 17 00:00:00 2001 From: John Hui Date: Fri, 7 Nov 2025 15:02:19 -0800 Subject: [PATCH 3/6] [cxx-interop] Make ClangDeclExplicitSafety request non-recursive Doing so reduces opportunities for caching, but it's not obvious to me that we benefit from such fine-grained caching. The benefit here is that we also avoid the pitfalls of incremental caching, as illustrated by the added test case. Finally, we eliminate the use of hasActiveRequest(), which is an anti-pattern. --- lib/ClangImporter/ClangImporter.cpp | 223 +++++++++--------- .../Interop/Cxx/class/safe-interop-mode.swift | 16 ++ 2 files changed, 126 insertions(+), 113 deletions(-) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index e42622fdfc37d..78b38c3e522b8 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -93,6 +93,7 @@ #include "clang/Serialization/ObjectFilePCHContainerReader.h" #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" #include "clang/Tooling/DependencyScanning/ScanAndUpdateArgs.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" @@ -8769,132 +8770,128 @@ CustomRefCountingOperationResult CustomRefCountingOperation::evaluate( return {CustomRefCountingOperationResult::tooManyFound, nullptr, name}; } -/// Check whether the given Clang type involves an unsafe type. -static bool hasUnsafeType(Evaluator &evaluator, clang::QualType clangType) { - // Handle pointers. - auto pointeeType = clangType->getPointeeType(); - if (!pointeeType.isNull()) { - // Function pointers are okay. - if (pointeeType->isFunctionType()) - return false; - - // Pointers to record types are okay if they come in as foreign reference - // types. - if (auto *recordDecl = pointeeType->getAsRecordDecl()) { - if (hasImportAsRefAttr(recordDecl)) - return false; - } - - // All other pointers are considered unsafe. - return true; - } - - // Handle records recursively. - if (auto recordDecl = clangType->getAsTagDecl()) { - // If we reached this point the types is not imported as a shared reference, - // so we don't need to check the bases whether they are shared references. - auto req = ClangDeclExplicitSafety({recordDecl, false}); - if (evaluator.hasActiveRequest(req)) - // Normally, using hasActiveRequest() to avoid cycles is an anti-pattern - // because cycles should be treated as errors. However, cycles are allowed - // in C++ template, e.g.: - // - // template class Foo { ... }; // throws away template arg - // template class Bar : Foo> { ... }; - // - // A common use case of cyclic templates is the CRTP pattern. - // - // We need to avoid request cycles, so if there is already an active - // request for this type, just assume it is not explicitly unsafe for now - // (i.e., as if it were unspecified). - return false; - return evaluateOrDefault(evaluator, req, ExplicitSafety::Unspecified) == - ExplicitSafety::Unsafe; - } - - // Everything else is safe. - return false; -} - ExplicitSafety ClangDeclExplicitSafety::evaluate(Evaluator &evaluator, CxxDeclExplicitSafetyDescriptor desc) const { // FIXME: Also similar to hasPointerInSubobjects // FIXME: should probably also subsume IsSafeUseOfCxxDecl - - // Explicitly unsafe. - auto decl = desc.decl; - if (hasSwiftAttribute(decl, "unsafe")) - return ExplicitSafety::Unsafe; - - // Explicitly safe. - if (hasSwiftAttribute(decl, "safe")) - return ExplicitSafety::Safe; - - // Shared references are considered safe. + if (desc.isClass) - return ExplicitSafety::Safe; - - // Enums are always safe. - if (isa(decl)) - return ExplicitSafety::Safe; - - // If it's not a record, leave it unspecified. - auto recordDecl = dyn_cast(decl); - if (!recordDecl) - return ExplicitSafety::Unspecified; - - // Escapable and non-escapable annotations imply that the declaration is - // safe. - if (evaluateOrDefault( - evaluator, - ClangTypeEscapability({recordDecl->getTypeForDecl(), nullptr}), - CxxEscapability::Unknown) != CxxEscapability::Unknown) - return ExplicitSafety::Safe; - - // A template class is unsafe if any of its type arguments are unsafe. - // Note that this does not rely on the record being defined. - if (const auto *ctsd = - dyn_cast(recordDecl)) { - for (auto arg : ctsd->getTemplateArgs().asArray()) { - switch (arg.getKind()) { - case clang::TemplateArgument::Type: - if (hasUnsafeType(evaluator, arg.getAsType())) - return ExplicitSafety::Unsafe; - break; - case clang::TemplateArgument::Pack: - for (auto pkArg : arg.getPackAsArray()) { - if (pkArg.getKind() == clang::TemplateArgument::Type && - hasUnsafeType(evaluator, pkArg.getAsType())) + // Safety for class types is handled a bit differently than other types. + // If it is not explicitly marked unsafe, it is always explicitly safe. + return hasSwiftAttribute(desc.decl, "unsafe") ? ExplicitSafety::Unsafe + : ExplicitSafety::Safe; + + // Clang record types are considered explicitly unsafe if any of their fields, + // base classes, and template type parameters are unsafe. We use a stack for + // this recursive traversal. + // + // Invariant: if any Decl in the stack is unsafe, then desc.decl is unsafe. + llvm::SmallVector stack; + + // Keep track of which Decls we've seen to avoid cycles. + llvm::SmallDenseSet seen; + + // Check whether a type is unsafe. This function may also push to the stack. + auto isUnsafe = [&](clang::QualType type) -> bool { + auto pointeeType = type->getPointeeType(); + if (!pointeeType.isNull()) { + if (pointeeType->isFunctionType()) + return false; // Function pointers are not unsafe + auto *recordDecl = pointeeType->getAsRecordDecl(); + if (recordDecl && hasImportAsRefAttr(recordDecl)) + return false; // Pointers are ok if imported as foreign reference types + return true; // All other pointers are considered unsafe. + } + if (auto *decl = type->getAsTagDecl()) { + // We need to check the safety of the TagDecl corresponding to this type + if (seen.insert(decl).second) + // Only visit decl if we have not seen it before, to avoid cycles + stack.push_back(decl); + } + return false; // This type does not look unsafe on its own + }; + + stack.push_back(desc.decl); + seen.insert(desc.decl); + while (!stack.empty()) { + const clang::Decl *decl = stack.back(); + stack.pop_back(); + + // Found unsafe; whether decl == desc.decl or not, desc.decl is unsafe + // (see invariant, above) + if (hasSwiftAttribute(decl, "unsafe")) + return ExplicitSafety::Unsafe; + + if (hasSwiftAttribute(decl, "safe")) + continue; + + // Enums are always safe + if (isa(decl)) + continue; + + auto *recordDecl = dyn_cast(decl); + if (!recordDecl) { + if (decl == desc.decl) + // If desc.decl is not a RecordDecl or EnumDecl, safety is unspecified. + return ExplicitSafety::Unspecified; + // If we encountered non-Record non-Enum decl during recursive traversal, + // we need to continue checking safety of other decls. + continue; + } + + // Escapability annotations imply that the declaration is safe + if (evaluateOrDefault( + evaluator, + ClangTypeEscapability({recordDecl->getTypeForDecl(), nullptr}), + CxxEscapability::Unknown) != CxxEscapability::Unknown) + continue; + + // A template class is unsafe if any of its type arguments are unsafe. + // Note that this does not rely on the record being defined. + if (auto *specDecl = + dyn_cast(recordDecl)) { + for (auto arg : specDecl->getTemplateArgs().asArray()) { + switch (arg.getKind()) { + case clang::TemplateArgument::Type: + if (isUnsafe(arg.getAsType())) return ExplicitSafety::Unsafe; + break; + case clang::TemplateArgument::Pack: + for (auto pkArg : arg.getPackAsArray()) { + if (pkArg.getKind() == clang::TemplateArgument::Type && + isUnsafe(pkArg.getAsType())) + return ExplicitSafety::Unsafe; + } + break; + default: + continue; } - break; - default: - continue; } } - } - - // If we don't have a definition, leave it unspecified. - recordDecl = recordDecl->getDefinition(); - if (!recordDecl) - return ExplicitSafety::Unspecified; - - // If this is a C++ class, check its bases. - if (auto cxxRecordDecl = dyn_cast(recordDecl)) { - for (auto base : cxxRecordDecl->bases()) { - if (hasUnsafeType(evaluator, base.getType())) + + recordDecl = recordDecl->getDefinition(); + if (!recordDecl) { + if (decl == desc.decl) + // If desc.decl doesn't have a definition, safety is unspecified. + return ExplicitSafety::Unspecified; + // If we encountered decl without definition during recursive traversal, + // we need to continue checking safety of other decls. + continue; + } + + if (auto *cxxRecordDecl = dyn_cast(recordDecl)) { + for (auto base : cxxRecordDecl->bases()) { + if (isUnsafe(base.getType())) + return ExplicitSafety::Unsafe; + } + } + + for (auto *field : recordDecl->fields()) { + if (isUnsafe(field->getType())) return ExplicitSafety::Unsafe; } } - - // Check the fields. - for (auto field : recordDecl->fields()) { - if (hasUnsafeType(evaluator, field->getType())) - return ExplicitSafety::Unsafe; - } - - // Okay, call it safe. return ExplicitSafety::Safe; } diff --git a/test/Interop/Cxx/class/safe-interop-mode.swift b/test/Interop/Cxx/class/safe-interop-mode.swift index 11eac1ce830f4..ab664d16bb6a0 100644 --- a/test/Interop/Cxx/class/safe-interop-mode.swift +++ b/test/Interop/Cxx/class/safe-interop-mode.swift @@ -101,6 +101,12 @@ struct HoldsShared { SWIFT_RETURNS_UNRETAINED; }; +template struct TTake2 {}; +template struct PassThru {}; +struct IsUnsafe { int *p; }; +struct HasUnsafe : TTake2, IsUnsafe> {}; +using AlsoUnsafe = PassThru; + //--- test.swift import Test @@ -213,3 +219,13 @@ func useTTakeUnsafeTuple(x: TTakeUnsafeTuple) { // expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}} _ = x // expected-note{{reference to parameter 'x' involves unsafe type}} } + +func useTTakeUnsafeTuple(x: HasUnsafe) { + // expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}} + _ = x // expected-note{{reference to parameter 'x' involves unsafe type}} +} + +func useTTakeUnsafeTuple(x: AlsoUnsafe) { + // expected-warning@+1{{expression uses unsafe constructs but is not marked with 'unsafe'}} + _ = x // expected-note{{reference to parameter 'x' involves unsafe type}} +} From cbae2fc9b9dcf0badf616679a19ac88cd02839cb Mon Sep 17 00:00:00 2001 From: John Hui Date: Fri, 7 Nov 2025 15:12:52 -0800 Subject: [PATCH 4/6] [evaluator] hasActiveRequest() considered harmful --- include/swift/AST/Evaluator.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/swift/AST/Evaluator.h b/include/swift/AST/Evaluator.h index 5d7e47f29e65c..8741b02083a66 100644 --- a/include/swift/AST/Evaluator.h +++ b/include/swift/AST/Evaluator.h @@ -304,6 +304,10 @@ class Evaluator { void clearCache() { cache.clear(); } /// Is the given request, or an equivalent, currently being evaluated? + /// + /// WARN: do not rely on this function to avoid request cycles. Doing so can + /// lead to bugs that are very difficult to debug, especially when request + /// caching is involved. template bool hasActiveRequest(const Request &request) const { return activeRequests.count(ActiveRequest(request)); From 2b9b507923f835f7b7b62097b1316188f8ba6741 Mon Sep 17 00:00:00 2001 From: John Hui Date: Fri, 7 Nov 2025 15:22:03 -0800 Subject: [PATCH 5/6] [cxx-interop] Add a comment about ClangDeclExplicitSafety return Safe by default --- lib/ClangImporter/ClangImporter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 78b38c3e522b8..66fc12caab0af 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -8892,6 +8892,11 @@ ClangDeclExplicitSafety::evaluate(Evaluator &evaluator, return ExplicitSafety::Unsafe; } } + + // desc.decl isn't explicitly marked unsafe, and none of the types/decls + // reachable from desc.decl are considered unsafe either. Cases where we would + // consider desc.decl's safety unspecified should have returned early from the + // loop. Thus, we can conclude that desc.decl is safe. return ExplicitSafety::Safe; } From 6b3f8c75cb4498452a2431f78f45749e022e6080 Mon Sep 17 00:00:00 2001 From: John Hui Date: Fri, 7 Nov 2025 15:24:03 -0800 Subject: [PATCH 6/6] [cxx-interop] Rename CxxDeclExplicitSafetyDescriptor -> ClangDeclExplicitSafetyDescriptor Keep the naming convention consistent; this isn't specific to Cxx --- .../ClangImporter/ClangImporterRequests.h | 22 +++++++++---------- .../ClangImporter/ClangImporterTypeIDZone.def | 2 +- lib/ClangImporter/ClangImporter.cpp | 9 ++++---- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/include/swift/ClangImporter/ClangImporterRequests.h b/include/swift/ClangImporter/ClangImporterRequests.h index fe83d0fae0405..d435571c12272 100644 --- a/include/swift/ClangImporter/ClangImporterRequests.h +++ b/include/swift/ClangImporter/ClangImporterRequests.h @@ -624,37 +624,37 @@ class CxxValueSemantics void simple_display(llvm::raw_ostream &out, CxxValueSemanticsDescriptor desc); SourceLoc extractNearestSourceLoc(CxxValueSemanticsDescriptor desc); -struct CxxDeclExplicitSafetyDescriptor final { +struct ClangDeclExplicitSafetyDescriptor final { const clang::Decl *decl; bool isClass; - CxxDeclExplicitSafetyDescriptor(const clang::Decl *decl, bool isClass) + ClangDeclExplicitSafetyDescriptor(const clang::Decl *decl, bool isClass) : decl(decl), isClass(isClass) {} friend llvm::hash_code - hash_value(const CxxDeclExplicitSafetyDescriptor &desc) { + hash_value(const ClangDeclExplicitSafetyDescriptor &desc) { return llvm::hash_combine(desc.decl, desc.isClass); } - friend bool operator==(const CxxDeclExplicitSafetyDescriptor &lhs, - const CxxDeclExplicitSafetyDescriptor &rhs) { + friend bool operator==(const ClangDeclExplicitSafetyDescriptor &lhs, + const ClangDeclExplicitSafetyDescriptor &rhs) { return lhs.decl == rhs.decl && lhs.isClass == rhs.isClass; } - friend bool operator!=(const CxxDeclExplicitSafetyDescriptor &lhs, - const CxxDeclExplicitSafetyDescriptor &rhs) { + friend bool operator!=(const ClangDeclExplicitSafetyDescriptor &lhs, + const ClangDeclExplicitSafetyDescriptor &rhs) { return !(lhs == rhs); } }; void simple_display(llvm::raw_ostream &out, - CxxDeclExplicitSafetyDescriptor desc); -SourceLoc extractNearestSourceLoc(CxxDeclExplicitSafetyDescriptor desc); + ClangDeclExplicitSafetyDescriptor desc); +SourceLoc extractNearestSourceLoc(ClangDeclExplicitSafetyDescriptor desc); /// Determine the safety of the given Clang declaration. class ClangDeclExplicitSafety : public SimpleRequest { public: using SimpleRequest::SimpleRequest; @@ -668,7 +668,7 @@ class ClangDeclExplicitSafety // Evaluation. ExplicitSafety evaluate(Evaluator &evaluator, - CxxDeclExplicitSafetyDescriptor desc) const; + ClangDeclExplicitSafetyDescriptor desc) const; }; #define SWIFT_TYPEID_ZONE ClangImporter diff --git a/include/swift/ClangImporter/ClangImporterTypeIDZone.def b/include/swift/ClangImporter/ClangImporterTypeIDZone.def index 0d562311a9c72..206819d8fe245 100644 --- a/include/swift/ClangImporter/ClangImporterTypeIDZone.def +++ b/include/swift/ClangImporter/ClangImporterTypeIDZone.def @@ -49,5 +49,5 @@ SWIFT_REQUEST(ClangImporter, CxxValueSemantics, CxxValueSemanticsKind(CxxValueSemanticsDescriptor), Cached, NoLocationInfo) SWIFT_REQUEST(ClangImporter, ClangDeclExplicitSafety, - ExplicitSafety(CxxDeclExplicitSafetyDescriptor), Cached, + ExplicitSafety(ClangDeclExplicitSafetyDescriptor), Cached, NoLocationInfo) diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 66fc12caab0af..3c284594e592c 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -8702,7 +8702,7 @@ SourceLoc swift::extractNearestSourceLoc(SafeUseOfCxxDeclDescriptor desc) { } void swift::simple_display(llvm::raw_ostream &out, - CxxDeclExplicitSafetyDescriptor desc) { + ClangDeclExplicitSafetyDescriptor desc) { out << "Checking if '"; if (auto namedDecl = dyn_cast(desc.decl)) out << namedDecl->getNameAsString(); @@ -8711,7 +8711,7 @@ void swift::simple_display(llvm::raw_ostream &out, out << "' is explicitly safe.\n"; } -SourceLoc swift::extractNearestSourceLoc(CxxDeclExplicitSafetyDescriptor desc) { +SourceLoc swift::extractNearestSourceLoc(ClangDeclExplicitSafetyDescriptor desc) { return SourceLoc(); } @@ -8770,9 +8770,8 @@ CustomRefCountingOperationResult CustomRefCountingOperation::evaluate( return {CustomRefCountingOperationResult::tooManyFound, nullptr, name}; } -ExplicitSafety -ClangDeclExplicitSafety::evaluate(Evaluator &evaluator, - CxxDeclExplicitSafetyDescriptor desc) const { +ExplicitSafety ClangDeclExplicitSafety::evaluate( + Evaluator &evaluator, ClangDeclExplicitSafetyDescriptor desc) const { // FIXME: Also similar to hasPointerInSubobjects // FIXME: should probably also subsume IsSafeUseOfCxxDecl