Skip to content

Commit 91bc753

Browse files
committed
[cxx-interop] Add diagnostics for nonmutating attr that has no effect
1 parent 23b2fa9 commit 91bc753

File tree

5 files changed

+45
-0
lines changed

5 files changed

+45
-0
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ WARNING(import_multiple_mainactor_attr,none,
109109
WARNING(contradicting_mutation_attrs,none,
110110
"attribute 'nonmutating' is ignored when combined with attribute 'mutating'", ())
111111

112+
WARNING(nonmutating_without_const,none,
113+
"attribute 'nonmutating' has no effect on non-const method", ())
114+
115+
WARNING(nonmutating_without_mutable_fields,none,
116+
"attribute 'nonmutating' has no effect without any mutable fields", ())
117+
112118
ERROR(module_map_not_found, none, "module map file '%0' not found", (StringRef))
113119

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

lib/ClangImporter/ImportDecl.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8826,6 +8826,22 @@ ClangImporter::Implementation::importSwiftAttrAttributes(Decl *MappedDecl) {
88268826
}
88278827

88288828
if (isMutabilityAttr(swiftAttr)) {
8829+
8830+
// Check if 'nonmutating' attr is applicable
8831+
if (swiftAttr->getAttribute() == "nonmutating") {
8832+
if (auto *method = dyn_cast<clang::CXXMethodDecl>(ClangDecl)) {
8833+
if (!method->isConst()) {
8834+
diagnose(HeaderLoc(swiftAttr->getLocation()),
8835+
diag::nonmutating_without_const);
8836+
}
8837+
if (!method->getParent()->hasMutableFields()) {
8838+
diagnose(HeaderLoc(swiftAttr->getLocation()),
8839+
diag::nonmutating_without_mutable_fields);
8840+
}
8841+
}
8842+
}
8843+
8844+
// Check for contradicting mutability attr
88298845
if (seenMutabilityAttr) {
88308846
StringRef seenAttribute =
88318847
seenMutabilityAttr.getValue()->getAttribute();

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,17 @@ struct HasMutableProperty {
3535
}
3636
};
3737

38+
struct NoMutableProperty {
39+
int a;
40+
41+
// expected-warning@+1 {{attribute 'nonmutating' has no effect without any mutable fields}}
42+
int isConst() const __attribute__((__swift_attr__("nonmutating"))) {
43+
return a;
44+
}
45+
46+
// expected-warning@+2 {{attribute 'nonmutating' has no effect without any mutable fields}}
47+
// expected-warning@+1 {{attribute 'nonmutating' has no effect on non-const method}}
48+
int nonConst() __attribute__((__swift_attr__("nonmutating"))) { return a; }
49+
};
50+
3851
#endif // TEST_INTEROP_CXX_CLASS_INPUTS_MUTABILITY_ANNOTATIONS_H

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,9 @@
1414
// CHECK: var a: Int32
1515
// CHECK: var b: Int32
1616
// CHECK: }
17+
18+
// CHECK: struct NoMutableProperty {
19+
// CHECK: func isConst() -> Int32
20+
// CHECK: mutating func nonConst() -> Int32
21+
// CHECK: var a: Int32
22+
// CHECK: }

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ let _ = objWMutableProperty.annotatedNonMutating()
1313
let _ = objWMutableProperty.noAnnotation() // expected-error {{cannot use mutating member on immutable value: 'objWMutableProperty' is a 'let' constant}}
1414
let _ = objWMutableProperty.contradictingAnnotations() // expected-error {{cannot use mutating member on immutable value: 'objWMutableProperty' is a 'let' constant}}
1515
let _ = objWMutableProperty.duplicateAnnotations()
16+
17+
let objWithoutMutableProperty = NoMutableProperty(a: 42) // expected-note {{change 'let' to 'var' to make it mutable}}
18+
let _ = objWithoutMutableProperty.isConst()
19+
let _ = objWithoutMutableProperty.nonConst() // expected-error {{cannot use mutating member on immutable value: 'objWithoutMutableProperty' is a 'let' constant}}

0 commit comments

Comments
 (0)