Skip to content

Commit b6517d2

Browse files
committed
[cxx-interop] Emit diagnostic to mark C++ type as non-copyable
1 parent f5ff400 commit b6517d2

File tree

4 files changed

+33
-18
lines changed

4 files changed

+33
-18
lines changed

include/swift/AST/DiagnosticsIRGen.def

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ ERROR(unable_to_load_pass_plugin,none,
8181
"unable to load plugin '%0': '%1'", (StringRef, StringRef))
8282

8383
ERROR(failed_emit_copy, none,
84-
"failed to copy %0; did you want to import %0 as ~Copyable?",
84+
"failed to copy %0; did you mean to import %0 as ~Copyable?",
8585
(const clang::NamedDecl *))
8686

8787
NOTE(use_requires_expression, none,
@@ -101,8 +101,16 @@ NOTE(annotate_non_copyable, none,
101101
())
102102

103103
NOTE(maybe_missing_annotation, none,
104-
"maybe one of the types that %0 depends on needs a %1",
105-
(const clang::NamedDecl *, StringRef))
104+
"one of the types that %0 depends on may need a 'requires' clause (since "
105+
"C++20) in the copy constructor, a 'SWIFT_COPYABLE_IF' annotation or a "
106+
"'SWIFT_NONCOPYABLE' annotation'",
107+
(const clang::NamedDecl *))
108+
109+
NOTE(maybe_missing_parameter, none,
110+
"the %select{'requires' clause on the copy constructor "
111+
"of|'SWIFT_COPYABLE_IF' annotation on}0 %1 may be missing a "
112+
"%select{constraint|parameter}0",
113+
(bool, const clang::NamedDecl *))
106114

107115
#define UNDEFINE_DIAGNOSTIC_MACROS
108116
#include "DefineDiagnosticMacros.h"

lib/IRGen/GenStruct.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -656,17 +656,22 @@ namespace {
656656
return false;
657657
});
658658

659-
if (copyConstructor->getTrailingRequiresClause()) {
660-
ctx.Diags.diagnose(copyConstructorLoc, diag::maybe_missing_annotation,
661-
recordDecl, "'requires' clause");
662-
} else if (hasCopyableIfAttr) {
659+
bool hasRequiresClause =
660+
copyConstructor->getTrailingRequiresClause() != nullptr;
661+
662+
if (hasRequiresClause || hasCopyableIfAttr) {
663663
ctx.Diags.diagnose(copyConstructorLoc, diag::maybe_missing_annotation,
664-
recordDecl, "'SWIFT_COPYABLE_IF' annotation");
664+
recordDecl);
665+
ctx.Diags.diagnose(copyConstructorLoc, diag::maybe_missing_parameter,
666+
hasCopyableIfAttr, recordDecl);
665667
} else {
666668
ctx.Diags.diagnose(copyConstructorLoc, diag::use_requires_expression);
667669
ctx.Diags.diagnose(copyConstructorLoc, diag::annotate_copyable_if);
668670
}
669-
ctx.Diags.diagnose(copyConstructorLoc, diag::annotate_non_copyable);
671+
672+
if (!copyConstructor->isUserProvided()) {
673+
ctx.Diags.diagnose(copyConstructorLoc, diag::annotate_non_copyable);
674+
}
670675
}
671676

672677
auto callee = cast<llvm::Function>(clangFnAddr->stripPointerCasts());

test/Interop/Cxx/class/noncopyable-irgen.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,16 @@ struct OwnsT {
2828
OwnsT(const OwnsT &other) : element(other.element) {}
2929
// expected-error@-1 *{{call to deleted constructor of 'NonCopyable'}}
3030
// expected-note@-2 *{{in instantiation of member function 'OwnsT<NonCopyable>::OwnsT' requested here}}
31-
// expected-TEST1-error@-3 {{failed to copy 'OwnsT<NonCopyable>'; did you want to import 'OwnsT<NonCopyable>' as ~Copyable?}}
31+
// expected-TEST1-error@-3 {{failed to copy 'OwnsT<NonCopyable>'; did you mean to import 'OwnsT<NonCopyable>' as ~Copyable?}}
3232
// expected-TEST1-note@-4 {{use 'requires' (since C++20) to specify the constraints under which the copy constructor is available}}
3333
// expected-TEST1-note@-5 {{annotate a type with 'SWIFT_COPYABLE_IF(<T>)' in C++ to specify that the type is Copyable if <T> is Copyable}}
34-
// expected-TEST1-note@-6 {{annotate a type with 'SWIFT_NONCOPYABLE' in C++ to import it as ~Copyable}}
3534
OwnsT(OwnsT&& other) {}
3635
};
3736

3837
using OwnsNonCopyable = OwnsT<NonCopyable>;
3938

4039
template <typename T> struct Derived : OwnsT<T> {
41-
// expected-TEST2-error@-1 {{failed to copy 'Derived<NonCopyable>'; did you want to import 'Derived<NonCopyable>' as ~Copyable?}}
40+
// expected-TEST2-error@-1 {{failed to copy 'Derived<NonCopyable>'; did you mean to import 'Derived<NonCopyable>' as ~Copyable?}}
4241
// expected-TEST2-note@-2 {{use 'requires' (since C++20) to specify the constraints under which the copy constructor is available}}
4342
// expected-TEST2-note@-3 {{annotate a type with 'SWIFT_COPYABLE_IF(<T>)' in C++ to specify that the type is Copyable if <T> is Copyable}}
4443
// expected-TEST2-note@-4 {{annotate a type with 'SWIFT_NONCOPYABLE' in C++ to import it as ~Copyable}}
@@ -50,9 +49,9 @@ template <typename T> struct SWIFT_COPYABLE_IF(T) Annotated {
5049
T element;
5150
Annotated() : element() {}
5251
Annotated(const Annotated &other) : element(other.element) {}
53-
// expected-TEST3-error@-1 {{failed to copy 'Annotated<OwnsT<NonCopyable>>'; did you want to import 'Annotated<OwnsT<NonCopyable>>' as ~Copyable?}}
54-
// expected-TEST3-note@-2 {{maybe one of the types that 'Annotated<OwnsT<NonCopyable>>' depends on needs a 'SWIFT_COPYABLE_IF' annotation}}
55-
// expected-TEST3-note@-3 {{annotate a type with 'SWIFT_NONCOPYABLE' in C++ to import it as ~Copyable}}
52+
// expected-TEST3-error@-1 {{failed to copy 'Annotated<OwnsT<NonCopyable>>'; did you mean to import 'Annotated<OwnsT<NonCopyable>>' as ~Copyable?}}
53+
// expected-TEST3-note@-2 {{one of the types that 'Annotated<OwnsT<NonCopyable>>' depends on may need a 'requires' clause (since C++20) in the copy constructor, a 'SWIFT_COPYABLE_IF' annotation or a 'SWIFT_NONCOPYABLE' annotation'}}
54+
// expected-TEST3-note@-3 {{the 'SWIFT_COPYABLE_IF' annotation on 'Annotated<OwnsT<NonCopyable>>' may be missing a parameter}}
5655

5756
Annotated(Annotated &&) = default;
5857
};
@@ -64,9 +63,9 @@ template <typename T> struct Requires {
6463
T element;
6564
Requires() : element() {}
6665
Requires(const Requires &other) requires std::is_copy_constructible_v<T> : element(other.element) {}
67-
// expected-TEST4-error@-1 {{failed to copy 'Requires<OwnsT<NonCopyable>>'; did you want to import 'Requires<OwnsT<NonCopyable>>' as ~Copyable?}}
68-
// expected-TEST4-note@-2 {{maybe one of the types that 'Requires<OwnsT<NonCopyable>>' depends on needs a 'requires' clause}}
69-
// expected-TEST4-note@-3 {{annotate a type with 'SWIFT_NONCOPYABLE' in C++ to import it as ~Copyable}}
66+
// expected-TEST4-error@-1 {{failed to copy 'Requires<OwnsT<NonCopyable>>'; did you mean to import 'Requires<OwnsT<NonCopyable>>' as ~Copyable?}}
67+
// expected-TEST4-note@-2 {{one of the types that 'Requires<OwnsT<NonCopyable>>' depends on may need a 'requires' clause (since C++20) in the copy constructor, a 'SWIFT_COPYABLE_IF' annotation or a 'SWIFT_NONCOPYABLE' annotation'}}
68+
// expected-TEST4-note@-3 {{the 'requires' clause on the copy constructor of 'Requires<OwnsT<NonCopyable>>' may be missing a constraint}}
7069

7170
Requires(Requires &&) = default;
7271
};

test/Interop/Cxx/class/noncopyable-typechecker.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
// RUN: %target-swift-frontend -cxx-interoperability-mode=default -typecheck -verify -I %swift_src_root/lib/ClangImporter/SwiftBridging -I %t/Inputs %t/test.swift
44
// RUN: %target-swift-frontend -cxx-interoperability-mode=default -Xcc -std=c++20 -verify-additional-prefix cpp20- -D CPP20 -typecheck -verify -I %swift_src_root/lib/ClangImporter/SwiftBridging -I %t/Inputs %t/test.swift
55

6+
// This test uses -verify-additional-file, which do not work well on Windows.
7+
// UNSUPPORTED: OS=windows-msvc
8+
69
//--- Inputs/module.modulemap
710
module Test {
811
header "noncopyable.h"

0 commit comments

Comments
 (0)