mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[c++ interop] Swift should allow multiple SWIFT_CONFORMS_TO_PROTOCOL attributes on a C++ class.
This commit is contained in:
@@ -294,6 +294,9 @@ ERROR(both_returns_retained_returns_unretained, none,
|
||||
"SWIFT_RETURNS_UNRETAINED",
|
||||
(const clang::NamedDecl *))
|
||||
|
||||
ERROR(redundant_conformance_protocol,none,
|
||||
"redundant conformance of %0 to protocol '%1'", (Type, StringRef))
|
||||
|
||||
ERROR(returns_retained_or_returns_unretained_for_non_cxx_frt_values, none,
|
||||
"%0 cannot be annotated with either SWIFT_RETURNS_RETAINED or "
|
||||
"SWIFT_RETURNS_UNRETAINED because it is not returning "
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallBitVector.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
@@ -3105,6 +3106,8 @@ namespace {
|
||||
return result;
|
||||
}
|
||||
|
||||
using ProtocolSet = llvm::SmallSet<ProtocolDecl *, 4>;
|
||||
|
||||
void
|
||||
addExplicitProtocolConformances(NominalTypeDecl *decl,
|
||||
const clang::CXXRecordDecl *clangDecl) {
|
||||
@@ -3119,25 +3122,26 @@ namespace {
|
||||
if (!clangDecl->hasAttrs())
|
||||
return;
|
||||
|
||||
SmallVector<ValueDecl *, 1> results;
|
||||
auto conformsToAttr =
|
||||
llvm::find_if(clangDecl->getAttrs(), [](auto *attr) {
|
||||
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
|
||||
return swiftAttr->getAttribute().starts_with("conforms_to:");
|
||||
return false;
|
||||
});
|
||||
if (conformsToAttr == clangDecl->getAttrs().end())
|
||||
return;
|
||||
ProtocolSet alreadyAdded;
|
||||
llvm::for_each(clangDecl->getAttrs(), [&](auto *attr) {
|
||||
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
|
||||
if (swiftAttr->getAttribute().starts_with("conforms_to:"))
|
||||
addExplicitProtocolConformance(decl, swiftAttr, alreadyAdded);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto conformsToValue = cast<clang::SwiftAttrAttr>(*conformsToAttr)
|
||||
->getAttribute()
|
||||
void addExplicitProtocolConformance(NominalTypeDecl *decl,
|
||||
clang::SwiftAttrAttr *conformsToAttr,
|
||||
ProtocolSet &alreadyAdded) {
|
||||
auto conformsToValue = conformsToAttr->getAttribute()
|
||||
.drop_front(StringRef("conforms_to:").size())
|
||||
.str();
|
||||
auto names = StringRef(conformsToValue).split('.');
|
||||
auto moduleName = names.first;
|
||||
auto protocolName = names.second;
|
||||
if (protocolName.empty()) {
|
||||
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
|
||||
HeaderLoc attrLoc(conformsToAttr->getLocation());
|
||||
Impl.diagnose(attrLoc, diag::conforms_to_missing_dot, conformsToValue);
|
||||
return;
|
||||
}
|
||||
@@ -3145,20 +3149,24 @@ namespace {
|
||||
auto *mod = Impl.SwiftContext.getModuleByIdentifier(
|
||||
Impl.SwiftContext.getIdentifier(moduleName));
|
||||
if (!mod) {
|
||||
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
|
||||
HeaderLoc attrLoc(conformsToAttr->getLocation());
|
||||
Impl.diagnose(attrLoc, diag::cannot_find_conforms_to_module,
|
||||
conformsToValue, moduleName);
|
||||
return;
|
||||
}
|
||||
|
||||
SmallVector<ValueDecl *, 1> results;
|
||||
mod->lookupValue(Impl.SwiftContext.getIdentifier(protocolName),
|
||||
NLKind::UnqualifiedLookup, results);
|
||||
if (results.empty()) {
|
||||
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
|
||||
HeaderLoc attrLoc(conformsToAttr->getLocation());
|
||||
Impl.diagnose(attrLoc, diag::cannot_find_conforms_to, protocolName,
|
||||
moduleName);
|
||||
return;
|
||||
} else if (results.size() != 1) {
|
||||
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
|
||||
}
|
||||
|
||||
if (results.size() != 1) {
|
||||
HeaderLoc attrLoc(conformsToAttr->getLocation());
|
||||
Impl.diagnose(attrLoc, diag::conforms_to_ambiguous, protocolName,
|
||||
moduleName);
|
||||
return;
|
||||
@@ -3166,10 +3174,17 @@ namespace {
|
||||
|
||||
auto result = results.front();
|
||||
if (auto protocol = dyn_cast<ProtocolDecl>(result)) {
|
||||
auto [_, inserted] = alreadyAdded.insert(protocol);
|
||||
if (!inserted) {
|
||||
HeaderLoc attrLoc(conformsToAttr->getLocation());
|
||||
Impl.diagnose(attrLoc, diag::redundant_conformance_protocol,
|
||||
decl->getDeclaredInterfaceType(), conformsToValue);
|
||||
}
|
||||
|
||||
decl->getAttrs().add(
|
||||
new (Impl.SwiftContext) SynthesizedProtocolAttr(protocol, &Impl, false));
|
||||
} else {
|
||||
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
|
||||
HeaderLoc attrLoc((conformsToAttr)->getLocation());
|
||||
Impl.diagnose(attrLoc, diag::conforms_to_not_protocol, result,
|
||||
conformsToValue);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,13 @@ struct
|
||||
void play() const;
|
||||
};
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.Testable")))
|
||||
__attribute__((swift_attr(
|
||||
"conforms_to:SwiftTest.Playable"))) MultipleConformanceHasTestAndPlay {
|
||||
void test() const;
|
||||
void play() const;
|
||||
};
|
||||
|
||||
struct
|
||||
__attribute__((swift_attr("conforms_to:ImportedModule.ProtocolFromImportedModule")))
|
||||
HasImportedConf {
|
||||
@@ -24,6 +31,8 @@ struct
|
||||
|
||||
struct DerivedFromHasTest : HasTest {};
|
||||
struct DerivedFromDerivedFromHasTest : HasTest {};
|
||||
struct DerivedFromMultipleConformanceHasTestAndPlay
|
||||
: MultipleConformanceHasTestAndPlay {};
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.Testable")))
|
||||
DerivedFromDerivedFromHasTestWithDuplicateArg : HasTest {};
|
||||
|
||||
@@ -16,6 +16,65 @@ struct __attribute__((swift_attr("conforms_to:SwiftTest.X"))) CX {};
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.A"))) CA {};
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.B"))) CB {};
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:X")))
|
||||
__attribute__((swift_attr("conforms_to:X"))) CXX {};
|
||||
struct __attribute__((swift_attr("conforms_to:X")))
|
||||
__attribute__((swift_attr("conforms_to:Mod.X"))) CXModX {};
|
||||
struct __attribute__((swift_attr("conforms_to:X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.X"))) CXTextX {};
|
||||
struct __attribute__((swift_attr("conforms_to:X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.A"))) CXA {};
|
||||
struct __attribute__((swift_attr("conforms_to:X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.B"))) CXB {};
|
||||
struct __attribute__((swift_attr("conforms_to:X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.C"))) CXC {};
|
||||
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:Mod.X")))
|
||||
__attribute__((swift_attr("conforms_to:Mod.X"))) CModXModX {};
|
||||
struct __attribute__((swift_attr("conforms_to:Mod.X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.X"))) CModXTestX {};
|
||||
struct __attribute__((swift_attr("conforms_to:Mod.X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.A"))) CModXA {};
|
||||
struct __attribute__((swift_attr("conforms_to:Mod.X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.B"))) CModXB {};
|
||||
struct __attribute__((swift_attr("conforms_to:Mod.X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.C"))) CModXC {};
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.X"))) CTestXTextX {};
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.A"))) CTextXA {};
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.B"))) CTextXB {};
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.X")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.C"))) CTextXC {};
|
||||
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.A")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.A"))) CAA {};
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.A")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.B"))) CAB {};
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.A")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.C"))) CAC {};
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.B")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.B"))) CBB {};
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.B")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.C"))) CBC {};
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.C")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.C"))) CCC {};
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.D"))) CD {};
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.D"))) CDD: CD {};
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.D"))) CD2 {};
|
||||
struct CCDCD2 : CD, CD2 {};
|
||||
|
||||
struct __attribute__((swift_attr("conforms_to:SwiftTest.D")))
|
||||
__attribute__((swift_attr("conforms_to:SwiftTest.E"))) CDE {};
|
||||
|
||||
//--- test.swift
|
||||
|
||||
import Test
|
||||
@@ -25,10 +84,78 @@ struct B {}
|
||||
protocol A {}
|
||||
protocol A {}
|
||||
|
||||
protocol C {}
|
||||
protocol D {}
|
||||
protocol E: D {}
|
||||
|
||||
// CHECK: error: expected module name and protocol name separated by '.' in protocol conformance; 'X' is invalid
|
||||
// CHECK: module 'Mod' in specified protocol conformance 'Mod.X' is not found; did you mean to import it first?
|
||||
// CHECK: error: protocol 'X' in specified protocol conformance is not found in module 'SwiftTest'
|
||||
// CHECK: error: ambiguous reference to protocol 'A' in specified protocol conformance; module 'SwiftTest' contains multiple protocols named 'A'
|
||||
// CHECK: error: struct 'B' referenced in protocol conformance 'SwiftTest.B' is not a protocol
|
||||
|
||||
func test(_ inv: CInv, _ invMod: CModInv, _ x: CX, _ a: CA, _ b: CB) {}
|
||||
|
||||
// CHECK: error: expected module name and protocol name separated by '.' in protocol conformance; 'X' is invalid
|
||||
// CHECK: error: expected module name and protocol name separated by '.' in protocol conformance; 'X' is invalid
|
||||
|
||||
// CHECK: error: expected module name and protocol name separated by '.' in protocol conformance; 'X' is invalid
|
||||
// CHECK: module 'Mod' in specified protocol conformance 'Mod.X' is not found; did you mean to import it first?
|
||||
|
||||
// CHECK: error: expected module name and protocol name separated by '.' in protocol conformance; 'X' is invalid
|
||||
// CHECK: error: protocol 'X' in specified protocol conformance is not found in module 'SwiftTest'
|
||||
|
||||
// CHECK: error: expected module name and protocol name separated by '.' in protocol conformance; 'X' is invalid
|
||||
// CHECK: error: ambiguous reference to protocol 'A' in specified protocol conformance; module 'SwiftTest' contains multiple protocols named 'A'
|
||||
|
||||
// CHECK: error: expected module name and protocol name separated by '.' in protocol conformance; 'X' is invalid
|
||||
// CHECK: error: struct 'B' referenced in protocol conformance 'SwiftTest.B' is not a protocol
|
||||
|
||||
// CHECK: error: expected module name and protocol name separated by '.' in protocol conformance; 'X' is invalid
|
||||
func test(_ xx: CXX, _ xModx: CXModX, _ xTextX: CXTextX, _ cxa: CXA, _ cxb: CXB, _ cxc: CXC) {}
|
||||
|
||||
// CHECK: module 'Mod' in specified protocol conformance 'Mod.X' is not found; did you mean to import it first?
|
||||
// CHECK: module 'Mod' in specified protocol conformance 'Mod.X' is not found; did you mean to import it first?
|
||||
|
||||
// CHECK: module 'Mod' in specified protocol conformance 'Mod.X' is not found; did you mean to import it first?
|
||||
// CHECK: error: protocol 'X' in specified protocol conformance is not found in module 'SwiftTest'
|
||||
|
||||
// CHECK: module 'Mod' in specified protocol conformance 'Mod.X' is not found; did you mean to import it first?
|
||||
// CHECK: error: ambiguous reference to protocol 'A' in specified protocol conformance; module 'SwiftTest' contains multiple protocols named 'A'
|
||||
|
||||
// CHECK: module 'Mod' in specified protocol conformance 'Mod.X' is not found; did you mean to import it first?
|
||||
// CHECK: error: struct 'B' referenced in protocol conformance 'SwiftTest.B' is not a protocol
|
||||
|
||||
// CHECK: module 'Mod' in specified protocol conformance 'Mod.X' is not found; did you mean to import it first?
|
||||
func test(_ modXModX: CModXModX, _ modXTestX: CModXTestX, _ modXA: CModXA, _ modXB: CModXB, _ modXC: CModXC) {}
|
||||
|
||||
// CHECK: error: protocol 'X' in specified protocol conformance is not found in module 'SwiftTest'
|
||||
// CHECK: error: protocol 'X' in specified protocol conformance is not found in module 'SwiftTest'
|
||||
|
||||
// CHECK: error: protocol 'X' in specified protocol conformance is not found in module 'SwiftTest'
|
||||
// CHECK: error: ambiguous reference to protocol 'A' in specified protocol conformance; module 'SwiftTest' contains multiple protocols named 'A'
|
||||
|
||||
// CHECK: error: protocol 'X' in specified protocol conformance is not found in module 'SwiftTest'
|
||||
// CHECK: error: struct 'B' referenced in protocol conformance 'SwiftTest.B' is not a protocol
|
||||
|
||||
// CHECK: error: protocol 'X' in specified protocol conformance is not found in module 'SwiftTest'
|
||||
func test(_ testXTextX: CTestXTextX, _ textXA: CTextXA, _ textXB: CTextXB, _ textXC: CTextXC) {}
|
||||
|
||||
// CHECK: error: ambiguous reference to protocol 'A' in specified protocol conformance; module 'SwiftTest' contains multiple protocols named 'A'
|
||||
// CHECK: error: ambiguous reference to protocol 'A' in specified protocol conformance; module 'SwiftTest' contains multiple protocols named 'A'
|
||||
|
||||
// CHECK: error: ambiguous reference to protocol 'A' in specified protocol conformance; module 'SwiftTest' contains multiple protocols named 'A'
|
||||
// CHECK: error: struct 'B' referenced in protocol conformance 'SwiftTest.B' is not a protocol
|
||||
|
||||
// CHECK: error: ambiguous reference to protocol 'A' in specified protocol conformance; module 'SwiftTest' contains multiple protocols named 'A'
|
||||
func test(_ aa: CAA, _ ab: CAB, _ ac: CAC) {}
|
||||
|
||||
// CHECK: error: struct 'B' referenced in protocol conformance 'SwiftTest.B' is not a protocol
|
||||
func test(_ bb: CBB, _ bc: CBC) {}
|
||||
|
||||
// CHECK: error: redundant conformance of 'CCC' to protocol 'SwiftTest.C'
|
||||
func test(_ cc: CCC) {}
|
||||
|
||||
// CHECK-NOT: error: redundant conformance of 'CDD' to protocol 'SwiftTest.D'
|
||||
// CHECK-NOT: error: redundant conformance of 'CCDCD2' to protocol 'SwiftTest.D'
|
||||
// CHECK-NOT: error: redundant conformance of 'CDE' to protocol 'SwiftTest.D'
|
||||
func test(_ dd: CDD, _ dd2: CCDCD2, de: CDE) {}
|
||||
@@ -35,13 +35,24 @@ func callee(_ _: Playable) {
|
||||
func caller(_ x: Playable) {
|
||||
callee(x)
|
||||
}
|
||||
|
||||
func caller(_ x: MultipleConformanceHasTestAndPlay) {
|
||||
callee(x as Testable)
|
||||
callee(x as Playable)
|
||||
}
|
||||
|
||||
func caller(_ x: DerivedFromHasPlay) { callee(x) }
|
||||
func caller(_ x: DerivedFromDerivedFromHasPlay) { callee(x) }
|
||||
func caller(_ x: DerivedFromMultipleConformanceHasTestAndPlay) {
|
||||
callee(x as Testable)
|
||||
callee(x as Playable)
|
||||
}
|
||||
|
||||
func caller(_ x: HasTestAndPlay) {
|
||||
callee(x as Testable)
|
||||
callee(x as Playable)
|
||||
}
|
||||
|
||||
func caller(_ x: DerivedFromHasTestAndPlay) {
|
||||
callee(x as Testable)
|
||||
callee(x as Playable)
|
||||
|
||||
Reference in New Issue
Block a user