Skip to content

Commit 665d3e1

Browse files
committed
[cxx-interop] Add diagnostics for explicit protocol conformance on the C++ side.
1 parent 5eb7c7a commit 665d3e1

File tree

4 files changed

+62
-7
lines changed

4 files changed

+62
-7
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,16 @@ ERROR(foreign_reference_types_invalid_release,none,
199199
"specified release function '%0' is invalid. Release must have exactly "
200200
"one argument of type '%1'", (StringRef, StringRef))
201201

202+
ERROR(cannot_find_conforms_to,none,
203+
"specified protocol conformance could not be found '%0'.", (StringRef))
204+
205+
ERROR(conforms_to_ambiguous,none,
206+
"specified protocol conformance is ambiguous. "
207+
"Found multiple protocols named '%0'.", (StringRef))
208+
209+
ERROR(conforms_to_not_protocol,none,
210+
"specified protocol conformance '%0' is not a protocol.", (StringRef))
211+
202212
NOTE(unsupported_builtin_type, none, "built-in type '%0' not supported", (StringRef))
203213
NOTE(record_field_not_imported, none, "field %0 not imported", (const clang::NamedDecl*))
204214
NOTE(invoked_func_not_imported, none, "function %0 not imported", (const clang::NamedDecl*))

lib/AST/ProtocolConformance.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,7 +1053,6 @@ void NominalTypeDecl::prepareConformanceTable() const {
10531053
SmallPtrSet<ProtocolDecl *, 2> protocols;
10541054

10551055
auto addSynthesized = [&](ProtocolDecl *proto) {
1056-
llvm::dbgs() << "S\n";
10571056
if (protocols.count(proto) == 0) {
10581057
ConformanceTable->addSynthesizedConformance(
10591058
mutableThis, proto, mutableThis);

lib/ClangImporter/ImportDecl.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2634,7 +2634,10 @@ namespace {
26342634
void addExplicitProtocolConformances(NominalTypeDecl *decl) {
26352635
auto clangDecl = decl->getClangDecl();
26362636

2637-
SmallVector<ValueDecl *, 2> results;
2637+
if (!clangDecl->hasAttrs())
2638+
return;
2639+
2640+
SmallVector<ValueDecl *, 1> results;
26382641
auto conformsToAttr =
26392642
llvm::find_if(clangDecl->getAttrs(), [](auto *attr) {
26402643
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
@@ -2653,11 +2656,24 @@ namespace {
26532656
module.second->lookupValue(Impl.SwiftContext.getIdentifier(name),
26542657
NLKind::UnqualifiedLookup, results);
26552658
}
2656-
for (auto proto : results) {
2657-
if (auto protocol = dyn_cast<ProtocolDecl>(proto)) {
2658-
decl->getAttrs().add(
2659-
new (Impl.SwiftContext) SynthesizedProtocolAttr(protocol, &Impl, false));
2660-
}
2659+
2660+
if (results.empty()) {
2661+
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
2662+
Impl.diagnose(attrLoc, diag::cannot_find_conforms_to, name);
2663+
return;
2664+
} else if (results.size() != 1) {
2665+
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
2666+
Impl.diagnose(attrLoc, diag::conforms_to_ambiguous, name);
2667+
return;
2668+
}
2669+
2670+
auto result = results.front();
2671+
if (auto protocol = dyn_cast<ProtocolDecl>(result)) {
2672+
decl->getAttrs().add(
2673+
new (Impl.SwiftContext) SynthesizedProtocolAttr(protocol, &Impl, false));
2674+
} else {
2675+
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
2676+
Impl.diagnose(attrLoc, diag::conforms_to_not_protocol, name);
26612677
}
26622678
}
26632679

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: not %target-swift-frontend -typecheck -I %t/Inputs %t/test.swift -enable-experimental-cxx-interop 2>&1 | %FileCheck %s
4+
5+
//--- Inputs/module.modulemap
6+
module Test {
7+
header "test.h"
8+
requires cplusplus
9+
}
10+
11+
//--- Inputs/test.h
12+
13+
struct __attribute__((swift_attr("conforms_to:X"))) CX {};
14+
struct __attribute__((swift_attr("conforms_to:A"))) CA {};
15+
struct __attribute__((swift_attr("conforms_to:B"))) CB {};
16+
17+
//--- test.swift
18+
19+
import Test
20+
21+
struct B {}
22+
23+
protocol A {}
24+
protocol A {}
25+
26+
// CHECK: error: specified protocol conformance could not be found 'X'.
27+
// CHECK: error: specified protocol conformance is ambiguous. Found multiple protocols named 'A'.
28+
// CHECK: error: specified protocol conformance 'B' is not a protocol.
29+
30+
func test(_ x: CX, _ a: CA, _ b: CB) {}

0 commit comments

Comments
 (0)