From 131aedee144b75feba1d620541fe39054acce7aa Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Mon, 20 Apr 2020 12:12:44 +0200 Subject: [PATCH] Devirtualizer: fix a miscompile due to handling of cast instructions. getInstanceWithExactDynamicType returns a new instance and for this the class decl has to be updated. https://bugs.swift.org/browse/SR-12538 rdar://problem/61911112 --- lib/SILOptimizer/Utils/Devirtualize.cpp | 18 +++++++-- .../devirtualize_class_method.swift | 37 +++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 test/SILOptimizer/devirtualize_class_method.swift diff --git a/lib/SILOptimizer/Utils/Devirtualize.cpp b/lib/SILOptimizer/Utils/Devirtualize.cpp index 32d5c20e1fd52..cb5226de09012 100644 --- a/lib/SILOptimizer/Utils/Devirtualize.cpp +++ b/lib/SILOptimizer/Utils/Devirtualize.cpp @@ -1147,8 +1147,15 @@ swift::tryDevirtualizeApply(ApplySite applySite, ClassHierarchyAnalysis *cha, // Try to check if the exact dynamic type of the instance is statically // known. - if (auto instance = getInstanceWithExactDynamicType(cmi->getOperand(), cha)) - return tryDevirtualizeClassMethod(fas, instance, cd, ore); + if (auto instance = getInstanceWithExactDynamicType(cmi->getOperand(), cha)) { + // Update the classDecl, because we are stripping casts more aggressively + // in getInstanceWithExactDynamicType than in stripUpCasts. + CanType classType = getSelfInstanceType(instance->getType().getASTType()); + // This should never be null - make the check just to be on the safe side. + if (ClassDecl *cd = classType.getClassOrBoundGenericClass()) + return tryDevirtualizeClassMethod(fas, instance, cd, ore); + return {ApplySite(), false}; + } if (auto exactTy = getExactDynamicType(cmi->getOperand(), cha)) { if (exactTy == cmi->getOperand()->getType()) @@ -1207,8 +1214,11 @@ bool swift::canDevirtualizeApply(FullApplySite applySite, // Try to check if the exact dynamic type of the instance is statically // known. - if (auto instance = getInstanceWithExactDynamicType(cmi->getOperand(), cha)) - return canDevirtualizeClassMethod(applySite, cd); + if (auto instance = getInstanceWithExactDynamicType(cmi->getOperand(), cha)) { + CanType classType = getSelfInstanceType(instance->getType().getASTType()); + ClassDecl *cd = classType.getClassOrBoundGenericClass(); + return cd && canDevirtualizeClassMethod(applySite, cd); + } if (auto exactTy = getExactDynamicType(cmi->getOperand(), cha)) { if (exactTy == cmi->getOperand()->getType()) diff --git a/test/SILOptimizer/devirtualize_class_method.swift b/test/SILOptimizer/devirtualize_class_method.swift new file mode 100644 index 0000000000000..97a819da0bc66 --- /dev/null +++ b/test/SILOptimizer/devirtualize_class_method.swift @@ -0,0 +1,37 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -O -module-name=test %s -o %t/a.out +// RUN: %target-run %t/a.out | %FileCheck %s +// REQUIRES: executable_test + +class Base { + required init() { } + + class func instance() -> Base { + return self.init() + } +} + +class Middle: Base { + override class func instance() -> Middle { + return self.init() + } +} + +class Derived: Middle { + required init() { + super.init() + print("init Derived") + } +} + +struct Maker { + @inline(never) + static func create() -> Base { + return C.instance() + } +} + +// CHECK: init Derived +// CHECK: test.Derived +print(Maker.create()) +