Skip to content

Commit 2893d55

Browse files
committed
[Serialization] Don't warn when a deserialized category is equivalent to an existing one.
A single class allows multiple categories to be defined for it. But if two of such categories have the same name, we emit a warning. It's not a hard error but a good indication of a potential mistake. With modules, we can end up with the same category in different modules. Diagnosing such a situation has little value as the categories in different modules are equivalent and don't reflect the usage of the same name for different purposes. When we deserialize a duplicate category, compare it to an existing one and warn only when the new one is different. rdar://104582081 Differential Revision: https://reviews.llvm.org/D144149
1 parent af4c4f4 commit 2893d55

File tree

4 files changed

+69
-19
lines changed

4 files changed

+69
-19
lines changed

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "ASTCommon.h"
1515
#include "ASTReaderInternals.h"
1616
#include "clang/AST/ASTContext.h"
17+
#include "clang/AST/ASTStructuralEquivalence.h"
1718
#include "clang/AST/Attr.h"
1819
#include "clang/AST/AttrIterator.h"
1920
#include "clang/AST/Decl.h"
@@ -4181,23 +4182,22 @@ namespace {
41814182
// Check for duplicate categories.
41824183
if (Cat->getDeclName()) {
41834184
ObjCCategoryDecl *&Existing = NameCategoryMap[Cat->getDeclName()];
4184-
if (Existing &&
4185-
Reader.getOwningModuleFile(Existing)
4186-
!= Reader.getOwningModuleFile(Cat)) {
4187-
// FIXME: We should not warn for duplicates in diamond:
4188-
//
4189-
// MT //
4190-
// / \ //
4191-
// ML MR //
4192-
// \ / //
4193-
// MB //
4194-
//
4195-
// If there are duplicates in ML/MR, there will be warning when
4196-
// creating MB *and* when importing MB. We should not warn when
4197-
// importing.
4198-
Reader.Diag(Cat->getLocation(), diag::warn_dup_category_def)
4199-
<< Interface->getDeclName() << Cat->getDeclName();
4200-
Reader.Diag(Existing->getLocation(), diag::note_previous_definition);
4185+
if (Existing && Reader.getOwningModuleFile(Existing) !=
4186+
Reader.getOwningModuleFile(Cat)) {
4187+
llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
4188+
StructuralEquivalenceContext Ctx(
4189+
Cat->getASTContext(), Existing->getASTContext(),
4190+
NonEquivalentDecls, StructuralEquivalenceKind::Default,
4191+
/*StrictTypeSpelling =*/false,
4192+
/*Complain =*/false,
4193+
/*ErrorOnTagTypeMismatch =*/true);
4194+
if (!Ctx.IsEquivalent(Cat, Existing)) {
4195+
// Warn only if the categories with the same name are different.
4196+
Reader.Diag(Cat->getLocation(), diag::warn_dup_category_def)
4197+
<< Interface->getDeclName() << Cat->getDeclName();
4198+
Reader.Diag(Existing->getLocation(),
4199+
diag::note_previous_definition);
4200+
}
42014201
} else if (!Existing) {
42024202
// Record this category.
42034203
Existing = Cat;

clang/test/Modules/compare-objc-interface.m

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,3 +444,54 @@ @interface CompareLastImplAttribute: NSObject
444444
// [email protected]:* {{'CompareLastImplAttribute' has different definitions in different modules; first difference is definition in module 'First.Hidden' found property 'lastImplAttribute' with 'direct' attribute}}
445445
// [email protected]:* {{but in {{'Second'|definition here}} found property 'lastImplAttribute' with different 'direct' attribute}}
446446
#endif
447+
448+
#if defined(FIRST)
449+
@interface CompareMatchingCategories: NSObject @end
450+
@interface CompareMatchingCategories(Matching)
451+
- (int)testMethod;
452+
@end
453+
454+
@interface CompareMismatchingCategories1: NSObject @end
455+
@interface CompareMismatchingCategories1(Category1)
456+
- (void)presentMethod;
457+
@end
458+
@interface CompareMismatchingCategories2: NSObject @end
459+
@interface CompareMismatchingCategories2(Category2)
460+
@end
461+
462+
@interface CompareDifferentCategoryNames: NSObject @end
463+
@interface CompareDifferentCategoryNames(CategoryFirst)
464+
- (void)firstMethod:(int)x;
465+
@end
466+
#elif defined(SECOND)
467+
@interface CompareMatchingCategories: NSObject @end
468+
@interface CompareMatchingCategories(Matching)
469+
- (int)testMethod;
470+
@end
471+
472+
@interface CompareMismatchingCategories1: NSObject @end
473+
@interface CompareMismatchingCategories1(Category1)
474+
@end
475+
@interface CompareMismatchingCategories2: NSObject @end
476+
@interface CompareMismatchingCategories2(Category2)
477+
- (void)presentMethod;
478+
@end
479+
480+
@interface CompareDifferentCategoryNames: NSObject @end
481+
@interface CompareDifferentCategoryNames(CategorySecond)
482+
- (void)secondMethod;
483+
@end
484+
#else
485+
CompareMatchingCategories *compareMatchingCategories; // no diagnostic
486+
CompareMismatchingCategories1 *compareMismatchingCategories1;
487+
#ifdef TEST_MODULAR
488+
// [email protected]:* {{duplicate definition of category 'Category1' on interface 'CompareMismatchingCategories1'}}
489+
// [email protected]:* {{previous definition is here}}
490+
#endif
491+
CompareMismatchingCategories2 *compareMismatchingCategories2;
492+
#ifdef TEST_MODULAR
493+
// [email protected]:* {{duplicate definition of category 'Category2' on interface 'CompareMismatchingCategories2'}}
494+
// [email protected]:* {{previous definition is here}}
495+
#endif
496+
CompareDifferentCategoryNames *compareDifferentCategoryNames; // no diagnostic
497+
#endif

clang/test/Modules/hidden-duplicates.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ @protocol ForwardDeclaredProtocolWithoutDefinition;
3232

3333
@interface NSObject @end
3434
@class ForwardDeclaredInterfaceWithoutDefinition;
35+
@interface NSObject(CategoryForTesting) @end
3536

3637
NSObject *interfaceDefinition(NSObject *o);
3738
NSObject *forwardDeclaredInterface(NSObject *o);

clang/test/Modules/objc-categories.m

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
@import category_bottom;
1010

11-
// expected-note@Inputs/category_left.h:14 {{previous definition}}
12-
// expected-warning@Inputs/category_right.h:12 {{duplicate definition of category}}
1311
// expected-note@Inputs/category_top.h:1 {{receiver is instance of class declared here}}
1412

1513
@interface Foo(Source)

0 commit comments

Comments
 (0)