Skip to content

Commit df4745b

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

File tree

3 files changed

+59
-6
lines changed

3 files changed

+59
-6
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/ClangImporter/ImportDecl.cpp

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

2637-
SmallVector<ValueDecl *, 2> results;
2637+
SmallVector<ValueDecl *, 1> results;
26382638
auto conformsToAttr =
26392639
llvm::find_if(clangDecl->getAttrs(), [](auto *attr) {
26402640
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr))
@@ -2653,11 +2653,24 @@ namespace {
26532653
module.second->lookupValue(Impl.SwiftContext.getIdentifier(name),
26542654
NLKind::UnqualifiedLookup, results);
26552655
}
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-
}
2656+
2657+
if (results.empty()) {
2658+
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
2659+
Impl.diagnose(attrLoc, diag::cannot_find_conforms_to, name);
2660+
return;
2661+
} else if (results.size() != 1) {
2662+
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
2663+
Impl.diagnose(attrLoc, diag::conforms_to_ambiguous, name);
2664+
return;
2665+
}
2666+
2667+
auto result = results.front();
2668+
if (auto protocol = dyn_cast<ProtocolDecl>(result)) {
2669+
decl->getAttrs().add(
2670+
new (Impl.SwiftContext) SynthesizedProtocolAttr(protocol, &Impl, false));
2671+
} else {
2672+
HeaderLoc attrLoc((*conformsToAttr)->getLocation());
2673+
Impl.diagnose(attrLoc, diag::conforms_to_not_protocol, name);
26612674
}
26622675
}
26632676

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)