Skip to content

Commit d7f5dc4

Browse files
committed
ABIChecker: diagnose mangled name changes
Moving generic constraint from extension to its member or vice versa may change the mangled name of the member without changing the generic signature, thus introducing ABI breakages. This change teaches the ABI checker to diagnose USR (mangled name) changes to cover such cases. rdar://78276290
1 parent 2460639 commit d7f5dc4

File tree

7 files changed

+59
-0
lines changed

7 files changed

+59
-0
lines changed

include/swift/AST/DiagnosticsModuleDiffer.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ ERROR(not_inheriting_convenience_inits,APIDigesterBreakage,"%0 no longer inherit
8888

8989
ERROR(enum_case_added,APIDigesterBreakage,"%0 has been added as a new enum case", (StringRef))
9090

91+
ERROR(demangled_name_changed,APIDigesterBreakage,"%0 has mangled name changing from '%1' to '%2'", (StringRef, StringRef, StringRef))
92+
9193
WARNING(cannot_read_allowlist,none,"cannot read breakage allowlist at '%0'", (StringRef))
9294

9395
#define UNDEFINE_DIAGNOSTIC_MACROS

include/swift/AST/USRGeneration.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ bool printExtensionUSR(const ExtensionDecl *ED, raw_ostream &OS);
6161
/// \returns true if it failed, false on success.
6262
bool printDeclUSR(const Decl *D, raw_ostream &OS);
6363

64+
/// Demangle a mangle-name-based USR to a human readable name.
65+
std::string demangleUSR(StringRef mangled);
66+
6467
} // namespace ide
6568
} // namespace swift
6669

lib/APIDigester/ModuleAnalyzerNodes.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,8 @@ static bool isSDKNodeEqual(SDKContext &Ctx, const SDKNode &L, const SDKNode &R)
944944
if (Left->getFixedBinaryOrder() != Right->getFixedBinaryOrder())
945945
return false;
946946
}
947+
if (Left->getUsr() != Right->getUsr())
948+
return false;
947949
LLVM_FALLTHROUGH;
948950
}
949951
case SDKNodeKind::Conformance:
@@ -2551,6 +2553,13 @@ void swift::ide::api::SDKNodeDecl::diagnose(SDKNode *Right) {
25512553
emitDiag(Loc, diag::decl_reorder, getFixedBinaryOrder(),
25522554
RD->getFixedBinaryOrder());
25532555
}
2556+
if (getUsr() != RD->getUsr()) {
2557+
auto left = demangleUSR(getUsr());
2558+
auto right = demangleUSR(RD->getUsr());
2559+
if (left != right) {
2560+
emitDiag(Loc, diag::demangled_name_changed, left, right);
2561+
}
2562+
}
25542563
}
25552564
}
25562565

lib/APIDigester/ModuleDiagsConsumer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ static StringRef getCategoryName(uint32_t ID) {
5454
case LocalDiagID::raw_type_change:
5555
return "/* RawRepresentable Changes */";
5656
case LocalDiagID::generic_sig_change:
57+
case LocalDiagID::demangled_name_changed:
5758
return "/* Generic Signature Changes */";
5859
case LocalDiagID::enum_case_added:
5960
case LocalDiagID::decl_added:

lib/AST/USRGeneration.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/SwiftNameTranslation.h"
2020
#include "swift/AST/TypeCheckRequests.h"
2121
#include "swift/AST/USRGeneration.h"
22+
#include "swift/Demangling/Demangler.h"
2223
#include "llvm/ADT/SmallString.h"
2324
#include "llvm/ADT/StringRef.h"
2425
#include "llvm/Support/raw_ostream.h"
@@ -255,6 +256,18 @@ swift::USRGenerationRequest::evaluate(Evaluator &evaluator,
255256
return NewMangler.mangleDeclAsUSR(D, getUSRSpacePrefix());
256257
}
257258

259+
std::string ide::demangleUSR(StringRef mangled) {
260+
if (mangled.startswith(getUSRSpacePrefix())) {
261+
mangled = mangled.substr(getUSRSpacePrefix().size());
262+
}
263+
SmallString<128> buffer;
264+
buffer += "$s";
265+
buffer += mangled;
266+
mangled = buffer.str();
267+
Demangler Dem;
268+
return nodeToString(Dem.demangleSymbol(mangled));
269+
}
270+
258271
std::string
259272
swift::MangleLocalTypeDeclRequest::evaluate(Evaluator &evaluator,
260273
const TypeDecl *D) const {

test/api-digester/Outputs/Cake-abi.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11

22
/* Generic Signature Changes */
3+
cake: Constructor S1.init(_:) has mangled name changing from 'cake.S1.init(Swift.Int) -> cake.S1' to 'cake.S1.init(Swift.Double) -> cake.S1'
4+
cake: Func C1.foo1() has mangled name changing from 'static cake.C1.foo1() -> ()' to 'cake.C1.foo1() -> ()'
5+
cake: Func C1.foo2(_:) has mangled name changing from 'cake.C1.foo2(Swift.Int) -> ()' to 'cake.C1.foo2(() -> ()) -> ()'
36
cake: Func P1.P1Constraint() has generic signature change from <Self where Self : cake.P1, Self : cake.P2> to <Self where Self : cake.P1>
7+
cake: Func P1.P1Constraint() has mangled name changing from '(extension in cake):cake.P1< where A: cake.P2>.P1Constraint() -> ()' to '(extension in cake):cake.P1.P1Constraint() -> ()'
8+
cake: Func S1.foo3() has mangled name changing from 'cake.S1.foo3() -> ()' to 'static cake.S1.foo3() -> ()'
9+
cake: Func S1.foo5(x:y:) has mangled name changing from 'cake.S1.foo5(x: Swift.Int, y: Swift.Int) -> ()' to 'cake.S1.foo5(x: Swift.Int, y: Swift.Int, z: Swift.Int) -> ()'
10+
cake: Func Somestruct2.foo1(_:) has mangled name changing from 'static cake.Somestruct2.foo1(cake.C3) -> ()' to 'static cake.NSSomestruct2.foo1(cake.C1) -> ()'
11+
cake: Func ownershipChange(_:_:) has mangled name changing from 'cake.ownershipChange(inout Swift.Int, __shared Swift.Int) -> ()' to 'cake.ownershipChange(Swift.Int, __owned Swift.Int) -> ()'
12+
cake: Func returnFunctionTypeOwnershipChange() has mangled name changing from 'cake.returnFunctionTypeOwnershipChange() -> (cake.C1) -> ()' to 'cake.returnFunctionTypeOwnershipChange() -> (__owned cake.C1) -> ()'
413
cake: Protocol P3 has generic signature change from <Self : cake.P1, Self : cake.P2> to <Self : cake.P1, Self : cake.P4>
14+
cake: Struct Somestruct2 has mangled name changing from 'cake.Somestruct2' to 'cake.NSSomestruct2'
515

616
/* RawRepresentable Changes */
717

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: echo "public func foo() {}" > %t/Foo.swift
3+
4+
// RUN: echo "public protocol P { associatedtype A }" > %t/Foo-1.swift
5+
// RUN: echo "public extension P { public func f() where A == Int {} }" >> %t/Foo-1.swift
6+
7+
// RUN: echo "public protocol P { associatedtype A }" > %t/Foo-2.swift
8+
// RUN: echo "public extension P where A == Int { public func f() {} }" >> %t/Foo-2.swift
9+
10+
// RUN: %target-swift-frontend -emit-module %t/Foo-1.swift -module-name Foo -emit-module-interface-path %t/Foo1.swiftinterface
11+
// RUN: %target-swift-frontend -emit-module %t/Foo-2.swift -module-name Foo -emit-module-interface-path %t/Foo2.swiftinterface
12+
13+
// RUN: %target-swift-frontend -compile-module-from-interface %t/Foo1.swiftinterface -o %t/Foo1.swiftmodule -module-name Foo -emit-abi-descriptor-path %t/Foo1.json
14+
15+
// RUN: %target-swift-frontend -compile-module-from-interface %t/Foo2.swiftinterface -o %t/Foo2.swiftmodule -module-name Foo -emit-abi-descriptor-path %t/Foo2.json
16+
17+
// RUN: %api-digester -diagnose-sdk -print-module --input-paths %t/Foo1.json -input-paths %t/Foo2.json -abi -o %t/result.txt
18+
19+
// RUN: %FileCheck %s < %t/result.txt
20+
21+
// CHECK: Foo: Func P.f() has mangled name changing from '(extension in Foo):Foo.P.f< where A.A == Swift.Int>() -> ()' to '(extension in Foo):Foo.P< where A.A == Swift.Int>.f() -> ()'

0 commit comments

Comments
 (0)