Skip to content

Commit 0661293

Browse files
committed
C++ Interop: support mutating attribute for C++ methods
This change teaches ClangImporter to import C++ methods marked with `__attribute__((__swift_attr__("mutating")))` as mutating in Swift. This is useful, for example, when a method mutates `this` despite being `const` in C++ (e.g. via `const_cast`).
1 parent 83a79a5 commit 0661293

File tree

5 files changed

+44
-1
lines changed

5 files changed

+44
-1
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4351,7 +4351,14 @@ ClangImporter::instantiateCXXClassTemplate(
43514351

43524352
bool ClangImporter::isCXXMethodMutating(const clang::CXXMethodDecl *method) {
43534353
return isa<clang::CXXConstructorDecl>(method) || !method->isConst() ||
4354-
method->getParent()->hasMutableFields();
4354+
method->getParent()->hasMutableFields() ||
4355+
(method->hasAttrs() &&
4356+
llvm::any_of(method->getAttrs(), [](clang::Attr *a) {
4357+
if (auto swiftAttr = dyn_cast<clang::SwiftAttrAttr>(a)) {
4358+
return swiftAttr->getAttribute() == "mutating";
4359+
}
4360+
return false;
4361+
}));
43554362
}
43564363

43574364
SwiftLookupTable *

test/Interop/Cxx/class/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ module MutableMembers {
5353
requires cplusplus
5454
}
5555

56+
module MutabilityAnnotations {
57+
header "mutability-annotations.h"
58+
requires cplusplus
59+
}
60+
5661
module ProtocolConformance {
5762
header "protocol-conformance.h"
5863
requires cplusplus
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef TEST_INTEROP_CXX_CLASS_INPUTS_MUTABILITY_ANNOTATIONS_H
2+
#define TEST_INTEROP_CXX_CLASS_INPUTS_MUTABILITY_ANNOTATIONS_H
3+
4+
struct HasConstMethodAnnotatedAsMutating {
5+
int a;
6+
7+
int annotatedMutating() const __attribute__((__swift_attr__("mutating"))) {
8+
const_cast<HasConstMethodAnnotatedAsMutating *>(this)->a++;
9+
return a;
10+
}
11+
12+
int annotatedMutatingWithOtherAttrs() const __attribute__((__swift_attr__("public"))) __attribute__((__swift_attr__("mutating"))) {
13+
const_cast<HasConstMethodAnnotatedAsMutating *>(this)->a++;
14+
return a;
15+
}
16+
};
17+
18+
#endif // TEST_INTEROP_CXX_CLASS_INPUTS_MUTABILITY_ANNOTATIONS_H
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=MutabilityAnnotations -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s
2+
3+
// CHECK: struct HasConstMethodAnnotatedAsMutating {
4+
// CHECK: mutating func annotatedMutating() -> Int32
5+
// CHECK: mutating func annotatedMutatingWithOtherAttrs() -> Int32
6+
// CHECK: var a: Int32
7+
// CHECK: }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// RUN: %target-typecheck-verify-swift -I %S/Inputs -enable-cxx-interop
2+
3+
import MutabilityAnnotations
4+
5+
let obj = HasConstMethodAnnotatedAsMutating(a: 42) // expected-note {{change 'let' to 'var' to make it mutable}}
6+
let i = obj.annotatedMutating() // expected-error {{cannot use mutating member on immutable value: 'obj' is a 'let' constant}}

0 commit comments

Comments
 (0)