[cxx-interop] Adding swift_name attributes to virtual methods overrides

This commit is contained in:
susmonteiro
2025-07-17 16:23:32 +01:00
parent 21ded5c132
commit 585ca5e2da
11 changed files with 531 additions and 12 deletions

View File

@@ -73,6 +73,11 @@ GROUPED_WARNING(inconsistent_swift_name, ClangDeclarationImport, none,
(bool, StringRef, StringRef, DeclName, StringRef, DeclName,
StringRef))
WARNING(swift_name_attr_ignored, none,
"ignoring swift_name attribute %0; swift_name attributes have no "
"effect on method overrides",
(DeclName))
GROUPED_WARNING(swift_name_circular_context_import, ClangDeclarationImport, none,
"cycle detected while resolving '%0' in swift_name attribute for '%1'",
(StringRef, StringRef))

View File

@@ -6336,11 +6336,9 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
// Capture the arity of already found members in the
// current record, to avoid adding ambiguous members
// from base classes.
const auto getArity =
ClangImporter::Implementation::getImportedBaseMemberDeclArity;
llvm::SmallSet<size_t, 4> foundNameArities;
llvm::SmallSet<DeclName, 4> foundMethodNames;
for (const auto *valueDecl : result)
foundNameArities.insert(getArity(valueDecl));
foundMethodNames.insert(valueDecl->getName());
for (auto base : cxxRecord->bases()) {
if (skipIfNonPublic && base.getAccessSpecifier() != clang::AS_public)
@@ -6374,9 +6372,9 @@ TinyPtrVector<ValueDecl *> ClangRecordMemberLookup::evaluate(
{});
for (auto foundInBase : baseResults) {
// Do not add duplicate entry with the same arity,
// Do not add duplicate entry with the same DeclName,
// as that would cause an ambiguous lookup.
if (foundNameArities.count(getArity(foundInBase)))
if (foundMethodNames.count(foundInBase->getName()))
continue;
collector.add(foundInBase);
@@ -7671,6 +7669,7 @@ ValueDecl *ClangImporter::Implementation::importBaseMemberDecl(
auto known = clonedBaseMembers.find(key);
if (known == clonedBaseMembers.end()) {
ValueDecl *cloned = cloneBaseMemberDecl(decl, newContext, inheritance);
handleAmbiguousSwiftName(cloned);
known = clonedBaseMembers.insert({key, cloned}).first;
clonedMembers.insert(std::make_pair(cloned, decl));
}

View File

@@ -55,6 +55,7 @@
#include "swift/ClangImporter/ClangImporterRequests.h"
#include "swift/ClangImporter/ClangModule.h"
#include "swift/Parse/Lexer.h"
#include "swift/Parse/ParseDeclName.h"
#include "swift/Strings.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
@@ -4424,7 +4425,43 @@ namespace {
// Create a thunk that will perform dynamic dispatch.
// TODO: we don't have to import the actual `method` in this case,
// we can just synthesize a thunk and import that instead.
auto result = synthesizer.makeVirtualMethod(decl);
FuncDecl *result;
if (decl->size_overridden_methods() > 0) {
if (auto swiftNameAttr = decl->getAttr<clang::SwiftNameAttr>()) {
auto parsedDeclName = parseDeclName(swiftNameAttr->getName());
auto swiftDeclName =
parsedDeclName.formDeclName(method->getASTContext());
ImportedName importedName;
std::tie(importedName, std::ignore) = importFullName(decl);
result = synthesizer.makeVirtualMethod(decl);
if (swiftDeclName != importedName.getDeclName()) {
Impl.diagnose(HeaderLoc(swiftNameAttr->getLoc()),
diag::swift_name_attr_ignored, swiftDeclName);
Impl.markUnavailable(
result, (llvm::Twine("ignoring swift_name '") +
swiftNameAttr->getName() + "' in '" +
decl->getParent()->getName() +
"'; swift_name attributes have no effect "
"on method overrides")
.str());
}
} else {
// If there's no swift_name attribute, we don't import this method.
// This is because if the overridden method was renamed and
// this one is not, we want to use the overridden method's name.
// This is reasonable because `makeVirtualMethod` returns
// a thunk that will perform dynamic dispatch, and consequently
// the correct instance of the method will get executed.
return nullptr;
}
} else {
result = synthesizer.makeVirtualMethod(decl);
}
if (result) {
return result;
} else {
@@ -10367,6 +10404,22 @@ ValueDecl *ClangImporter::Implementation::createUnavailableDecl(
return var;
}
void ClangImporter::Implementation::handleAmbiguousSwiftName(ValueDecl *decl) {
if (!decl || decl->isUnavailable())
return;
auto *cxxRecordDecl = dyn_cast<clang::CXXRecordDecl>(
decl->getDeclContext()->getAsDecl()->getClangDecl());
if (!cxxRecordDecl)
return;
if (findUnavailableMethod(cxxRecordDecl, decl->getName())) {
markUnavailable(decl,
"overrides multiple C++ methods with different Swift names");
}
}
// Force the members of the entire inheritance hierarchy to be loaded and
// deserialized before loading the members of this class. This allows the
// decl members table to be warmed up and enables the correct identification of

View File

@@ -1706,6 +1706,12 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
}
}
// `swift_name` attribute is not supported in virtual methods overrides
if (auto method = dyn_cast<clang::CXXMethodDecl>(D)) {
if (method->isVirtual() && method->size_overridden_methods() > 0)
skipCustomName = true;
}
if (!skipCustomName) {
result.info.hasCustomName = true;
result.declName = parsedName.formDeclName(
@@ -2315,6 +2321,42 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
newName = baseName.substr(StringRef("__synthesizedVirtualCall_").size());
baseName = newName;
}
if (method->isVirtual()) {
// The name should be imported from the base method
if (method->size_overridden_methods() > 0) {
DeclName overriddenName;
bool foundDivergentMethod = false;
for (auto overriddenMethod : method->overridden_methods()) {
ImportedName importedName =
importName(overriddenMethod, version, givenName);
if (!overriddenName) {
overriddenName = importedName.getDeclName();
} else if (overriddenName.compare(importedName.getDeclName())) {
importerImpl->insertUnavailableMethod(method->getParent(),
importedName.getDeclName());
foundDivergentMethod = true;
}
}
if (foundDivergentMethod) {
// The method we want to mark as unavailable will be generated
// lazily, when we clone the methods from base classes to the derived
// class method->getParent().
// Since we don't have the actual method here, we store this
// information to be accessed when we generate the actual method.
importerImpl->insertUnavailableMethod(method->getParent(),
overriddenName);
return ImportedName();
}
baseName = overriddenName.getBaseIdentifier().str();
// Also inherit argument names from base method
argumentNames.clear();
llvm::for_each(overriddenName.getArgumentNames(), [&](Identifier arg) {
argumentNames.push_back(arg.str());
});
}
}
}
// swift_newtype-ed declarations may have common words with the type name

View File

@@ -694,6 +694,14 @@ private:
// Map all cloned methods back to the original member
llvm::DenseMap<ValueDecl *, ValueDecl *> clonedMembers;
// Keep track of methods that are unavailale in each class.
// We need this set because these methods will be imported lazily. We don't
// have the corresponding Swift method when the availability check is
// performed, so instead we store the information in this set and then, when
// the method is finally generated, we check if it's present here
llvm::DenseSet<std::pair<const clang::CXXRecordDecl *, DeclName>>
unavailableMethods;
public:
llvm::DenseMap<const clang::ParmVarDecl*, FuncDecl*> defaultArgGenerators;
@@ -722,6 +730,18 @@ public:
return getNameImporter().getEnumKind(decl);
}
bool findUnavailableMethod(const clang::CXXRecordDecl *classDecl,
DeclName name) {
return unavailableMethods.contains({classDecl, name});
}
void insertUnavailableMethod(const clang::CXXRecordDecl *classDecl,
DeclName name) {
unavailableMethods.insert({classDecl, name});
}
void handleAmbiguousSwiftName(ValueDecl *decl);
private:
/// A mapping from imported declarations to their "alternate" declarations,
/// for cases where a single Clang declaration is imported to two

View File

@@ -22,6 +22,7 @@
#include "swift/Basic/STLExtras.h"
#include "swift/Basic/Version.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "swift/Parse/ParseDeclName.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Lex/MacroInfo.h"
@@ -1945,6 +1946,15 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table,
named, importedName.getEffectiveContext());
}
if (auto swiftNameAttr = named->getAttr<clang::SwiftNameAttr>()) {
auto parsedDeclName = parseDeclName(swiftNameAttr->getName());
auto swiftDeclName =
parsedDeclName.formDeclName(nameImporter.getContext());
if (importedName.getDeclName() != swiftDeclName)
table.addEntry(swiftDeclName, named,
importedName.getEffectiveContext());
}
return true;
});
if (failed) {

View File

@@ -41,19 +41,19 @@ import ImportAsMember
// CHECK-NEXT: TU: __swift
// CHECK-NEXT: adding:
// CHECK-NEXT: SNSomeStruct: SNAdding
// CHECK-NEXT: blue:
// CHECK: blue:
// CHECK-NEXT: SNColorChoice: SNColorBlue
// CHECK-NEXT: defaultValue:
// CHECK-NEXT: SNSomeStruct: SNSomeStructGetDefault, SNSomeStructSetDefault
// CHECK-NEXT: defaultX:
// CHECK: defaultX:
// CHECK-NEXT: SNSomeStruct: DefaultXValue
// CHECK-NEXT: foo:
// CHECK: foo:
// CHECK-NEXT: SNSomeStruct: SNSomeStructGetFoo, SNSomeStructSetFoo
// CHECK-NEXT: green:
// CHECK: green:
// CHECK-NEXT: SNColorChoice: SNColorGreen
// CHECK-NEXT: init:
// CHECK-NEXT: SNSomeStruct: SNCreate
// CHECK-NEXT: makeSomeStruct:
// CHECK: makeSomeStruct:
// CHECK-NEXT: TU: SNMakeSomeStruct, SNMakeSomeStructForX
// CHECK-NEXT: x:
// CHECK-NEXT: SNSomeStruct: X

View File

@@ -139,3 +139,138 @@ inline const Immortal *_Nonnull castToImmortal(
const DerivedFromImmortal *_Nonnull immortal) {
return static_cast<const Immortal *>(immortal);
}
// A1
// / \
// B1 B2
// / \
// C1 C2
struct IMMORTAL_FRT A1 {
virtual int virtualMethod() const { return 111; }
__attribute__((swift_name("swiftFooRename()")))
virtual int fooRename() const { return 112; }
__attribute__((swift_name("swiftBarRename()")))
virtual int barRename() const { return 113; }
__attribute__((swift_name("swiftParamsRename(a1:)")))
virtual int paramsRename(int i) const { return i; }
static A1 *_Nonnull create() { return new A1(); }
};
struct B1 : A1 {
__attribute__((swift_name("swiftVirtualMethod()")))
virtual int virtualMethod() const override { return 211; }
virtual int fooRename() const override { return 212; }
__attribute__((swift_name("B1BarRename()")))
virtual int barRename() const override { return 213; }
__attribute__((swift_name("swiftParamsRename(b1:)")))
virtual int paramsRename(int i) const override { return i; }
static B1 *_Nonnull create() { return new B1(); }
};
struct B2 : A1 {
int virtualMethod() const { return 221; }
int fooRename() const { return 222; }
__attribute__((swift_name("B2BarRename()"))) int barRename() const {
return 223;
}
static B2 *_Nonnull create() { return new B2(); }
};
struct C1 : B1 {
__attribute__((swift_name("swiftFooRename()")))
virtual int fooRename() const override { return 312; }
__attribute__((swift_name("swiftBarRename()")))
virtual int barRename() const override { return 313; }
virtual int paramsRename(int i) const override { return i; }
static C1 *_Nonnull create() { return new C1(); }
};
struct C2 : B1 {
__attribute__((swift_name("swiftVirtualMethod()")))
virtual int virtualMethod() const override { return 321; }
__attribute__((swift_name("C2FooRename()")))
virtual int fooRename() const override { return 322; }
__attribute__((swift_name("B1BarRename()")))
virtual int barRename() const override { return 323; }
__attribute__((swift_name("swiftParamsRename(b1:)")))
virtual int paramsRename(int i) const override { return i; }
static C2 *_Nonnull create() { return new C2(); }
};
struct IMMORTAL_FRT A2 {
__attribute__((swift_name("swiftVirtualMethod()")))
virtual int virtualMethod() const { return 121; }
__attribute__((swift_name("swiftFooRename()")))
virtual int fooRename() const { return 122; }
__attribute__((swift_name("A2BarRename()")))
virtual int barRename() const { return 123; }
__attribute__((swift_name("swiftParamsRename(a2:)"))) virtual int
paramsRename(int i) const {
return i + 1;
}
static A2 *_Nonnull create() { return new A2(); }
};
// A1 A2
// \ /
// D1
struct D1 : A1, A2 {
static D1 *_Nonnull create() { return new D1(); }
};
// A1 A2
// \ /
// B1 /
// \ /
// D2
struct D2 : B1, A2 {
__attribute__((swift_name("swiftVirtualMethod()")))
virtual int virtualMethod() const override { return 411; }
virtual int fooRename() const override { return 412; }
virtual int barRename() const override { return 413; }
virtual int paramsRename(int i) const override { return i; }
};
// A1
// / \
// / \
// B1 B2
// |\ /|
// | \ / |
// | D3 |
// C1 |
// \ |
// \ /
// D4
struct D3 : B1, B2 {};
struct D4 : C1, B2 {};

View File

@@ -15,3 +15,123 @@
// CHECK-NEXT: final func virtualMethod(_: HasDestructor)
// CHECK-NEXT: final func swiftVirtualRename()
// CHECK: }
// CHECK: class A1 {
// CHECK: final func virtualMethod() -> Int32
// CHECK: final func swiftFooRename() -> Int32
// CHECK: final func swiftBarRename() -> Int32
// CHECK: final func swiftParamsRename(a1 i: Int32) -> Int32
// CHECK: }
// CHECK: class B1 {
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftVirtualMethod() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func B1BarRename() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftParamsRename(b1 i: Int32) -> Int32
// CHECK: final func virtualMethod() -> Int32
// CHECK: final func swiftFooRename() -> Int32
// CHECK: final func swiftBarRename() -> Int32
// CHECK: final func swiftParamsRename(a1 i: Int32) -> Int32
// CHECK: }
// CHECK: class B2 {
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func B2BarRename() -> Int32
// CHECK: final func virtualMethod() -> Int32
// CHECK: final func swiftFooRename() -> Int32
// CHECK: final func swiftBarRename() -> Int32
// CHECK: final func swiftParamsRename(a1 i: Int32) -> Int32
// CHECK: }
// CHECK: class C1 {
// CHECK: final func swiftFooRename() -> Int32
// CHECK: final func swiftBarRename() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftVirtualMethod() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func B1BarRename() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftParamsRename(b1 i: Int32) -> Int32
// CHECK: final func virtualMethod() -> Int32
// CHECK: final func swiftParamsRename(a1 i: Int32) -> Int32
// CHECK: }
// CHECK: class C2 {
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftVirtualMethod() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func C2FooRename() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func B1BarRename() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftParamsRename(b1 i: Int32) -> Int32
// CHECK: final func virtualMethod() -> Int32
// CHECK: final func swiftFooRename() -> Int32
// CHECK: final func swiftBarRename() -> Int32
// CHECK: final func swiftParamsRename(a1 i: Int32) -> Int32
// CHECK: }
// CHECK: class A2 {
// CHECK: final func swiftVirtualMethod() -> Int32
// CHECK: final func swiftFooRename() -> Int32
// CHECK: final func A2BarRename() -> Int32
// CHECK: final func swiftParamsRename(a2 i: Int32) -> Int32
// CHECK: }
// CHECK: class D1 {
// CHECK: final func virtualMethod() -> Int32
// CHECK: final func swiftFooRename() -> Int32
// CHECK: final func swiftBarRename() -> Int32
// CHECK: final func swiftParamsRename(a1 i: Int32) -> Int32
// CHECK: final func swiftVirtualMethod() -> Int32
// CHECK: final func A2BarRename() -> Int32
// CHECK: final func swiftParamsRename(a2 i: Int32) -> Int32
// CHECK: }
// CHECK: class D2 {
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftVirtualMethod() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func B1BarRename() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftParamsRename(b1 i: Int32) -> Int32
// CHECK: @available(*, unavailable, message: "overrides{{.*}}")
// CHECK: final func virtualMethod() -> Int32
// CHECK: final func swiftFooRename() -> Int32
// CHECK: @available(*, unavailable, message: "overrides{{.*}}")
// CHECK: final func swiftBarRename() -> Int32
// CHECK: @available(*, unavailable, message: "overrides{{.*}}")
// CHECK: final func swiftParamsRename(a1 i: Int32) -> Int32
// CHECK: @available(*, unavailable, message: "overrides{{.*}}")
// CHECK: final func A2BarRename() -> Int32
// CHECK: @available(*, unavailable, message: "overrides{{.*}}")
// CHECK: final func swiftParamsRename(a2 i: Int32) -> Int32
// CHECK: }
// CHECK: struct D3 {
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftVirtualMethod() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func B1BarRename() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftParamsRename(b1 i: Int32) -> Int32
// CHECK: final func virtualMethod() -> Int32
// CHECK: final func swiftFooRename() -> Int32
// CHECK: final func swiftBarRename() -> Int32
// CHECK: final func swiftParamsRename(a1 i: Int32) -> Int32
// CHECK: }
// CHECK: struct D4 {
// CHECK: final func swiftFooRename() -> Int32
// CHECK: final func swiftBarRename() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftVirtualMethod() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func B1BarRename() -> Int32
// CHECK: @available(*, unavailable, message: "ignoring{{.*}}")
// CHECK: final func swiftParamsRename(b1 i: Int32) -> Int32
// CHECK: final func virtualMethod() -> Int32
// CHECK: final func swiftParamsRename(a1 i: Int32) -> Int32
// CHECK: }

View File

@@ -32,3 +32,94 @@ func callsRenamedVirtualMethodsInFRT(_ i: Immortal2) {
i.virtualRename() // expected-error {{value of type 'Immortal2' has no member 'virtualRename'}}
i.swiftVirtualRename()
}
@available(SwiftStdlib 5.8, *)
func callsOverridesOfRenamedVirtualMethods(
_ a1: A1, _ a2: A2, _ b1: B1, _ b2: B2, _ c1: C1, _ c2: C2, _ d1: D1, _ d2: D2, _ d3: D3, _ d4: D4
) {
a1.virtualMethod()
a1.fooRename() // expected-error {{value of type 'A1' has no member 'fooRename'}}
a1.swiftFooRename()
a1.swiftParamsRename(a1: 42)
b1.virtualMethod()
b1.swiftVirtualMethod() // expected-error {{'swiftVirtualMethod()' is unavailable: ignoring swift_name 'swiftVirtualMethod()' in 'B1'; swift_name attributes have no effect on method overrides}}
b1.fooRename() // expected-error {{value of type 'B1' has no member 'fooRename'}}
b1.swiftFooRename()
b1.barRename() // expected-error {{value of type 'B1' has no member 'barRename'}}
b1.swiftBarRename()
b1.B1BarRename() // expected-error {{'B1BarRename()' is unavailable: ignoring swift_name 'B1BarRename()' in 'B1'; swift_name attributes have no effect on method overrides}}
b1.swiftParamsRename(a1: 42)
b1.swiftParamsRename(b1: 42) // expected-error {{'swiftParamsRename(b1:)' is unavailable: ignoring swift_name 'swiftParamsRename(b1:)' in 'B1'; swift_name attributes have no effect on method overrides}}
b2.virtualMethod()
b2.fooRename() // expected-error {{value of type 'B2' has no member 'fooRename'; did you mean 'swiftFooRename'?}}
b2.swiftFooRename()
b2.B2BarRename() // expected-error {{'B2BarRename()' is unavailable: ignoring swift_name 'B2BarRename()' in 'B2'; swift_name attributes have no effect on method overrides}}
b2.swiftParamsRename(a1: 42)
c1.virtualMethod()
c1.swiftVirtualMethod() // expected-error {{'swiftVirtualMethod()' is unavailable: ignoring swift_name 'swiftVirtualMethod()' in 'B1'; swift_name attributes have no effect on method overrides}}
c1.fooRename() // expected-error {{value of type 'C1' has no member 'fooRename'}}
c1.swiftFooRename()
c1.barRename() // expected-error {{value of type 'C1' has no member 'barRename'}}
c1.swiftBarRename()
c1.B1BarRename() // expected-error {{'B1BarRename()' is unavailable: ignoring swift_name 'B1BarRename()' in 'B1'; swift_name attributes have no effect on method overrides}}
c1.paramsRename(42) // expected-error {{value of type 'C1' has no member 'paramsRename'}}
c1.swiftParamsRename(42) // expected-error {{missing argument label 'a1:' in call}}
c1.swiftParamsRename(a1: 42)
c2.virtualMethod()
c2.swiftVirtualMethod() // expected-error {{'swiftVirtualMethod()' is unavailable: ignoring swift_name 'swiftVirtualMethod()' in 'C2'; swift_name attributes have no effect on method overrides}}
c2.fooRename() // expected-error {{value of type 'C2' has no member 'fooRename'}}
c2.swiftFooRename()
c2.C2FooRename() // expected-error {{'C2FooRename()' is unavailable: ignoring swift_name 'C2FooRename()' in 'C2'; swift_name attributes have no effect on method overrides}}
c2.barRename() // expected-error {{value of type 'C2' has no member 'barRename'}}
c2.swiftBarRename()
c2.B1BarRename() // expected-error {{'B1BarRename()' is unavailable: ignoring swift_name 'B1BarRename()' in 'C2'; swift_name attributes have no effect on method overrides}}
c2.paramsRename(42) // expected-error {{value of type 'C2' has no member 'paramsRename'}}
c2.swiftParamsRename(a1: 42)
c2.swiftParamsRename(b1: 42) // expected-error {{'swiftParamsRename(b1:)' is unavailable: ignoring swift_name 'swiftParamsRename(b1:)' in 'C2'; swift_name attributes have no effect on method overrides}}
d1.virtualMethod()
d1.swiftVirtualMethod()
d1.fooRename() // expected-error {{value of type 'D1' has no member 'fooRename'}}
d1.swiftFooRename() // expected-error {{ambiguous use of 'swiftFooRename()'}}
d1.barRename() // expected-error {{value of type 'D1' has no member 'barRename'}}
d1.swiftBarRename()
d1.A2BarRename()
d1.swiftParamsRename(a1: 42)
d1.swiftParamsRename(a2: 42)
d2.virtualMethod() // expected-error {{'virtualMethod()' is unavailable: overrides multiple C++ methods with different Swift names}}
d2.swiftVirtualMethod() // expected-error {{ambiguous use of 'swiftVirtualMethod()'}}
d2.fooRename() // expected-error {{value of type 'D2' has no member 'fooRename'}}
d2.swiftFooRename() // expected-error {{ambiguous use of 'swiftFooRename()'}}
d2.barRename() // expected-error {{value of type 'D2' has no member 'barRename'}}
d2.swiftBarRename() // expected-error {{'swiftBarRename()' is unavailable: overrides multiple C++ methods with different Swift names}}
d2.A2BarRename() // expected-error {{'A2BarRename()' is unavailable: overrides multiple C++ methods with different Swift names}}
d2.swiftParamsRename(a1: 42) // expected-error {{'swiftParamsRename(a1:)' is unavailable: overrides multiple C++ methods with different Swift names}}
d2.swiftParamsRename(a2: 42) // expected-error {{'swiftParamsRename(a2:)' is unavailable: overrides multiple C++ methods with different Swift names}}
d2.swiftParamsRename(b1: 42) // expected-error {{'swiftParamsRename(b1:)' is unavailable: ignoring swift_name 'swiftParamsRename(b1:)' in 'B1'; swift_name attributes have no effect on method overrides}}
d3.virtualMethod()
d3.swiftVirtualMethod() // expected-error {{'swiftVirtualMethod()' is unavailable: ignoring swift_name 'swiftVirtualMethod()' in 'B1'; swift_name attributes have no effect on method overrides}}
d3.fooRename() // expected-error {{value of type 'D3' has no member 'fooRename'}}
d3.swiftFooRename()
d3.barRename() // expected-error {{value of type 'D3' has no member 'barRename'}}
d3.swiftBarRename()
d3.B1BarRename() // expected-error {{'B1BarRename()' is unavailable: ignoring swift_name 'B1BarRename()' in 'B1'; swift_name attributes have no effect on method overrides}}
d3.swiftParamsRename(a1: 42)
d3.swiftParamsRename(b1: 42) // expected-error {{'swiftParamsRename(b1:)' is unavailable: ignoring swift_name 'swiftParamsRename(b1:)' in 'B1'; swift_name attributes have no effect on method overrides}}
d4.virtualMethod()
d4.swiftVirtualMethod() // expected-error {{'swiftVirtualMethod()' is unavailable: ignoring swift_name 'swiftVirtualMethod()' in 'B1'; swift_name attributes have no effect on method overrides}}
d4.fooRename() // expected-error {{value of type 'D4' has no member 'fooRename'}}
d4.swiftFooRename() // expected-error {{ambiguous use of 'swiftFooRename()'}}
d4.barRename() // expected-error {{value of type 'D4' has no member 'barRename'}}
d4.swiftBarRename() // expected-error {{ambiguous use of 'swiftBarRename()'}}
d4.B1BarRename() // expected-error {{'B1BarRename()' is unavailable: ignoring swift_name 'B1BarRename()' in 'B1'; swift_name attributes have no effect on method overrides}}
d4.paramsRename(42) // expected-error {{value of type 'D4' has no member 'paramsRename'}}
d4.swiftParamsRename(42) // expected-error {{missing argument label 'a1:' in call}}
d4.swiftParamsRename(a1: 42)
}

View File

@@ -111,6 +111,50 @@ if #available(SwiftStdlib 5.8, *) {
func f(immortalClass: Immortal2) {
immortalClass.swiftVirtualRename()
}
let a1 = A1.create()
expectEqual(a1.virtualMethod(), 111)
expectEqual(a1.swiftFooRename(), 112)
expectEqual(a1.swiftBarRename(), 113)
expectEqual(a1.swiftParamsRename(a1: 42), 42)
let b1 = B1.create()
expectEqual(b1.virtualMethod(), 211)
expectEqual(b1.swiftFooRename(), 212)
expectEqual(b1.swiftBarRename(), 213)
expectEqual(b1.swiftParamsRename(a1: 42), 42)
let b2 = B2.create()
expectEqual(b2.virtualMethod(), 221)
expectEqual(b2.swiftFooRename(), 222)
expectEqual(b2.swiftBarRename(), 223)
let c1 = C1.create()
expectEqual(c1.virtualMethod(), 211)
expectEqual(c1.swiftFooRename(), 312)
expectEqual(c1.swiftBarRename(), 313)
expectEqual(c1.swiftParamsRename(a1: 42), 42)
let c2 = C2.create()
expectEqual(c2.virtualMethod(), 321)
expectEqual(c2.swiftFooRename(), 322)
expectEqual(c2.swiftBarRename(), 323)
expectEqual(c2.swiftParamsRename(a1: 42), 42)
let a2 = A2.create()
expectEqual(a2.swiftVirtualMethod(), 121)
expectEqual(a2.swiftFooRename(), 122)
expectEqual(a2.A2BarRename(), 123)
expectEqual(a2.swiftParamsRename(a2: 42), 43)
let d1 = D1.create()
expectEqual(d1.virtualMethod(), 111)
expectEqual(d1.swiftBarRename(), 113)
expectEqual(d1.swiftParamsRename(a1: 42), 42)
// FIXME the method calls below return incorrect values
expectEqual(d1.swiftVirtualMethod(), 111) // should be 121
expectEqual(d1.A2BarRename(), 113) // should be 123
expectEqual(d1.swiftParamsRename(a2: 42), 42) // should be 43
}
}