vsapsai created this revision.
vsapsai added reviewers: egorzhdan, akyrtzi.
Herald added a subscriber: ributzka.
Herald added a project: All.
vsapsai requested review of this revision.
Herald added a project: clang.

Incorrect `isOverriding` flag triggers the assertion
`!Overridden.empty()` in `ObjCMethodDecl::getOverriddenMethods` when a
method is marked as overriding but we cannot find any overrides.

When a method is declared in a category and defined in implementation,
we don't treat it as an override because it is the same method with
a separate declaration and a definition. But with modules we can find
a method declaration both in a modular category and a non-modular category
with different memory addresses. Thus we erroneously conclude the method
is overriding. Fix by comparing canonical declarations that are the same
for equal entities coming from different modules.

rdar://92845511


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D138630

Files:
  clang/lib/Sema/SemaDeclObjC.cpp
  clang/test/Modules/override.m

Index: clang/test/Modules/override.m
===================================================================
--- /dev/null
+++ clang/test/Modules/override.m
@@ -0,0 +1,69 @@
+// UNSUPPORTED: -aix
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -fsyntax-only -I%t/include %t/test.m \
+// RUN:            -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache -fmodule-name=CheckOverride
+
+// Test that if we have the same method in a different module, it's not an
+// override as it is the same method and it has the same DeclContext but a
+// different object in the memory.
+
+
+//--- include/CheckOverride.h
+@interface NSObject
+@end
+
+@interface CheckOverrideInterfaceOnly: NSObject
+- (void)potentialOverrideInterfaceOnly;
+@end
+
+@interface CheckOverrideCategoryOnly: NSObject
+@end
+@interface CheckOverrideCategoryOnly(CategoryOnly)
+- (void)potentialOverrideCategoryOnly;
+@end
+
+@interface CheckOverrideImplementationOfInterface: NSObject
+- (void)potentialOverrideImplementationOfInterface;
+@end
+
+@interface CheckOverrideImplementationOfCategory: NSObject
+@end
+@interface CheckOverrideImplementationOfCategory(CategoryImpl)
+- (void)potentialOverrideImplementationOfCategory;
+@end
+
+//--- include/Redirect.h
+// Ensure CheckOverride is imported as the module despite all `-fmodule-name` flags.
+#import <CheckOverride.h>
+
+//--- include/module.modulemap
+module CheckOverride {
+  header "CheckOverride.h"
+}
+module Redirect {
+  header "Redirect.h"
+  export *
+}
+
+//--- test.m
+#import <CheckOverride.h>
+#import <Redirect.h>
+
+@implementation CheckOverrideImplementationOfInterface
+- (void)potentialOverrideImplementationOfInterface {}
+@end
+
+@implementation CheckOverrideImplementationOfCategory
+- (void)potentialOverrideImplementationOfCategory {}
+@end
+
+void triggerOverrideCheck(CheckOverrideInterfaceOnly *intfOnly,
+                          CheckOverrideCategoryOnly *catOnly,
+                          CheckOverrideImplementationOfInterface *intfImpl,
+                          CheckOverrideImplementationOfCategory *catImpl) {
+  [intfOnly potentialOverrideInterfaceOnly];
+  [catOnly potentialOverrideCategoryOnly];
+  [intfImpl potentialOverrideImplementationOfInterface];
+  [catImpl potentialOverrideImplementationOfCategory];
+}
Index: clang/lib/Sema/SemaDeclObjC.cpp
===================================================================
--- clang/lib/Sema/SemaDeclObjC.cpp
+++ clang/lib/Sema/SemaDeclObjC.cpp
@@ -4438,6 +4438,11 @@
                                     ResultTypeCompatibilityKind RTC) {
   if (!ObjCMethod)
     return;
+  auto IsMethodInCurrentClass = [CurrentClass](const ObjCMethodDecl *M) {
+    // Checking canonical decl works across modules.
+    return M->getClassInterface()->getCanonicalDecl() ==
+           CurrentClass->getCanonicalDecl();
+  };
   // Search for overridden methods and merge information down from them.
   OverrideSearch overrides(*this, ObjCMethod);
   // Keep track if the method overrides any method in the class's base classes,
@@ -4449,8 +4454,7 @@
   for (ObjCMethodDecl *overridden : overrides) {
     if (!hasOverriddenMethodsInBaseOrProtocol) {
       if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) ||
-          CurrentClass != overridden->getClassInterface() ||
-          overridden->isOverriding()) {
+          !IsMethodInCurrentClass(overridden) || overridden->isOverriding()) {
         CheckObjCMethodDirectOverrides(ObjCMethod, overridden);
         hasOverriddenMethodsInBaseOrProtocol = true;
       } else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) {
@@ -4475,7 +4479,7 @@
               OverrideSearch overrides(*this, overridden);
               for (ObjCMethodDecl *SuperOverridden : overrides) {
                 if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) ||
-                    CurrentClass != SuperOverridden->getClassInterface()) {
+                    !IsMethodInCurrentClass(SuperOverridden)) {
                   CheckObjCMethodDirectOverrides(ObjCMethod, SuperOverridden);
                   hasOverriddenMethodsInBaseOrProtocol = true;
                   overridden->setOverriding(true);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to