Skip to content

Commit 23b2fa9

Browse files
committed
[cxx-interop] Add diagnostic for contradicting mutability annotations
1 parent 60fe6aa commit 23b2fa9

File tree

6 files changed

+51
-9
lines changed

6 files changed

+51
-9
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ WARNING(import_multiple_mainactor_attr,none,
106106
"this attribute for global actor '%0' is invalid; the declaration already has attribute for global actor '%1'",
107107
(StringRef, StringRef))
108108

109+
WARNING(contradicting_mutation_attrs,none,
110+
"attribute 'nonmutating' is ignored when combined with attribute 'mutating'", ())
111+
109112
ERROR(module_map_not_found, none, "module map file '%0' not found", (StringRef))
110113

111114
NOTE(macro_not_imported_unsupported_operator, none, "operator not supported in macro arithmetic", ())

lib/ClangImporter/ImportDecl.cpp

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8768,12 +8768,13 @@ SourceFile &ClangImporter::Implementation::getClangSwiftAttrSourceFile(
87688768
}
87698769

87708770
bool swift::importer::isMainActorAttr(const clang::SwiftAttrAttr *swiftAttr) {
8771-
if (swiftAttr->getAttribute() == "@MainActor" ||
8772-
swiftAttr->getAttribute() == "@UIActor") {
8773-
return true;
8774-
}
8771+
return swiftAttr->getAttribute() == "@MainActor" ||
8772+
swiftAttr->getAttribute() == "@UIActor";
8773+
}
87758774

8776-
return false;
8775+
bool swift::importer::isMutabilityAttr(const clang::SwiftAttrAttr *swiftAttr) {
8776+
return swiftAttr->getAttribute() == "mutating" ||
8777+
swiftAttr->getAttribute() == "nonmutating";
87778778
}
87788779

87798780
void
@@ -8792,7 +8793,8 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
87928793
if (maybeDefinition.getValue())
87938794
ClangDecl = cast<clang::NamedDecl>(maybeDefinition.getValue());
87948795

8795-
Optional<const clang::SwiftAttrAttr *> SeenMainActorAttr;
8796+
Optional<const clang::SwiftAttrAttr *> seenMainActorAttr;
8797+
Optional<const clang::SwiftAttrAttr *> seenMutabilityAttr;
87968798
PatternBindingInitializer *initContext = nullptr;
87978799

87988800
auto importAttrsFromDecl = [&](const clang::NamedDecl *ClangDecl) {
@@ -8803,26 +8805,47 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
88038805
// FIXME: Hard-code @MainActor and @UIActor, because we don't have a
88048806
// point at which to do name lookup for imported entities.
88058807
if (isMainActorAttr(swiftAttr)) {
8806-
if (SeenMainActorAttr) {
8808+
if (seenMainActorAttr) {
88078809
// Cannot add main actor annotation twice. We'll keep the first
88088810
// one and raise a warning about the duplicate.
88098811
HeaderLoc attrLoc(swiftAttr->getLocation());
88108812
diagnose(attrLoc, diag::import_multiple_mainactor_attr,
88118813
swiftAttr->getAttribute(),
8812-
SeenMainActorAttr.getValue()->getAttribute());
8814+
seenMainActorAttr.getValue()->getAttribute());
88138815
continue;
88148816
}
88158817

88168818
if (Type mainActorType = SwiftContext.getMainActorType()) {
88178819
auto typeExpr = TypeExpr::createImplicit(mainActorType, SwiftContext);
88188820
auto attr = CustomAttr::create(SwiftContext, SourceLoc(), typeExpr);
88198821
MappedDecl->getAttrs().add(attr);
8820-
SeenMainActorAttr = swiftAttr;
8822+
seenMainActorAttr = swiftAttr;
88218823
}
88228824

88238825
continue;
88248826
}
88258827

8828+
if (isMutabilityAttr(swiftAttr)) {
8829+
if (seenMutabilityAttr) {
8830+
StringRef seenAttribute =
8831+
seenMutabilityAttr.getValue()->getAttribute();
8832+
if ((seenAttribute == "nonmutating" &&
8833+
swiftAttr->getAttribute() == "mutating") ||
8834+
(seenAttribute == "mutating" &&
8835+
swiftAttr->getAttribute() == "nonmutating")) {
8836+
const clang::SwiftAttrAttr *nonmutatingAttr =
8837+
seenAttribute == "nonmutating" ? seenMutabilityAttr.getValue()
8838+
: swiftAttr;
8839+
8840+
diagnose(HeaderLoc(nonmutatingAttr->getLocation()),
8841+
diag::contradicting_mutation_attrs);
8842+
continue;
8843+
}
8844+
}
8845+
8846+
seenMutabilityAttr = swiftAttr;
8847+
}
8848+
88268849
// Hard-code @actorIndependent, until Objective-C clients start
88278850
// using nonisolated.
88288851
if (swiftAttr->getAttribute() == "@actorIndependent") {

lib/ClangImporter/ImporterImpl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,6 +1849,9 @@ class SwiftNameLookupExtension : public clang::ModuleFileExtension {
18491849
/// actor.
18501850
bool isMainActorAttr(const clang::SwiftAttrAttr *swiftAttr);
18511851

1852+
/// Determines whether the given swift_attr controls mutability
1853+
bool isMutabilityAttr(const clang::SwiftAttrAttr *swiftAttr);
1854+
18521855
/// Apply an attribute to a function type.
18531856
static inline Type applyToFunctionType(
18541857
Type type, llvm::function_ref<ASTExtInfo(ASTExtInfo)> transform) {

test/Interop/Cxx/class/Inputs/mutability-annotations.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ struct HasMutableProperty {
2424
}
2525

2626
int noAnnotation() const { return b; }
27+
28+
// expected-warning@+1 {{attribute 'nonmutating' is ignored when combined with attribute 'mutating'}}
29+
int contradictingAnnotations() const __attribute__((__swift_attr__("nonmutating"))) __attribute__((__swift_attr__("mutating"))) {
30+
return b;
31+
}
32+
33+
int duplicateAnnotations() const __attribute__((__swift_attr__("nonmutating"))) __attribute__((__swift_attr__("nonmutating"))) {
34+
return b;
35+
}
2736
};
2837

2938
#endif // TEST_INTEROP_CXX_CLASS_INPUTS_MUTABILITY_ANNOTATIONS_H

test/Interop/Cxx/class/mutability-annotations-module-interface.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
// CHECK: struct HasMutableProperty {
1010
// CHECK: func annotatedNonMutating() -> Int32
1111
// CHECK: mutating func noAnnotation() -> Int32
12+
// CHECK: mutating func contradictingAnnotations() -> Int32
13+
// CHECK: func duplicateAnnotations() -> Int32
1214
// CHECK: var a: Int32
1315
// CHECK: var b: Int32
1416
// CHECK: }

test/Interop/Cxx/class/mutability-annotations-typechecker.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ let objWMutableProperty = HasMutableProperty(a: 42, b: 21) // expected-note {{ch
1111

1212
let _ = objWMutableProperty.annotatedNonMutating()
1313
let _ = objWMutableProperty.noAnnotation() // expected-error {{cannot use mutating member on immutable value: 'objWMutableProperty' is a 'let' constant}}
14+
let _ = objWMutableProperty.contradictingAnnotations() // expected-error {{cannot use mutating member on immutable value: 'objWMutableProperty' is a 'let' constant}}
15+
let _ = objWMutableProperty.duplicateAnnotations()

0 commit comments

Comments
 (0)