diff options
author | Volodymyr Sapsai <vsapsai@apple.com> | 2022-07-08 13:10:31 -0700 |
---|---|---|
committer | Volodymyr Sapsai <vsapsai@apple.com> | 2022-11-17 18:31:32 -0800 |
commit | a65d5309d5b73527efcbdec49a3ba9bba0fd873d (patch) | |
tree | 5cb02a9ebdeeb2b6a4b06ecf53feb8a8a05e59b4 /clang/lib | |
parent | 7059a6c32cfad8f272fad47265e3890cd7a1a7e1 (diff) | |
download | llvm-a65d5309d5b73527efcbdec49a3ba9bba0fd873d.zip llvm-a65d5309d5b73527efcbdec49a3ba9bba0fd873d.tar.gz llvm-a65d5309d5b73527efcbdec49a3ba9bba0fd873d.tar.bz2 |
[ODRHash] Detect duplicate `ObjCProtocolDecl` ODR mismatches during parsing.
When during parsing we encountered a duplicate `ObjCProtocolDecl`, we
were always emitting an error. With this change we accept
* when a previous `ObjCProtocolDecl` is in a hidden [sub]module;
* parsed `ObjCProtocolDecl` is the same as the previous one.
And in case of mismatches we provide more detailed error messages.
rdar://93069080
Differential Revision: https://reviews.llvm.org/D130327
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/DeclObjC.cpp | 11 | ||||
-rw-r--r-- | clang/lib/AST/ODRDiagsEmitter.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Parse/ParseObjc.cpp | 17 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 20 |
4 files changed, 53 insertions, 17 deletions
diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 64e9f3c..2ba8daa 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -1997,6 +1997,17 @@ void ObjCProtocolDecl::startDefinition() { RD->Data = this->Data; } +void ObjCProtocolDecl::startDuplicateDefinitionForComparison() { + Data.setPointer(nullptr); + allocateDefinitionData(); + // Don't propagate data to other redeclarations. +} + +void ObjCProtocolDecl::mergeDuplicateDefinitionWithCommon( + const ObjCProtocolDecl *Definition) { + Data = Definition->Data; +} + void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM) const { if (const ObjCProtocolDecl *PDecl = getDefinition()) { for (auto *Prop : PDecl->properties()) { diff --git a/clang/lib/AST/ODRDiagsEmitter.cpp b/clang/lib/AST/ODRDiagsEmitter.cpp index dfc2157..6e0f122 100644 --- a/clang/lib/AST/ODRDiagsEmitter.cpp +++ b/clang/lib/AST/ODRDiagsEmitter.cpp @@ -90,8 +90,9 @@ static bool diagnoseSubMismatchMethodParameters(DiagnosticsEngine &Diags, DiagMethodType SecondMethodType = GetDiagMethodType(SecondMethod); return Diags.Report(SecondMethod->getLocation(), diag::note_module_odr_violation_method_params) - << SecondModule << SecondMethod->getSourceRange() << DiffType - << SecondMethodType << SecondName; + << SecondModule.empty() << SecondModule + << SecondMethod->getSourceRange() << DiffType << SecondMethodType + << SecondName; }; const unsigned FirstNumParameters = FirstMethod->param_size(); @@ -378,7 +379,7 @@ bool ODRDiagsEmitter::diagnoseSubMismatchProtocols( this](SourceLocation Loc, SourceRange Range, ODRReferencedProtocolDifference DiffType) { return Diag(Loc, diag::note_module_odr_violation_referenced_protocols) - << SecondModule << Range << DiffType; + << SecondModule.empty() << SecondModule << Range << DiffType; }; auto GetProtoListSourceRange = [](const ObjCProtocolList &PL) { if (PL.empty()) @@ -440,7 +441,8 @@ bool ODRDiagsEmitter::diagnoseSubMismatchObjCMethod( this](ODRMethodDifference DiffType) { return Diag(SecondMethod->getLocation(), diag::note_module_odr_violation_objc_method) - << SecondModule << SecondMethod->getSourceRange() << DiffType; + << SecondModule.empty() << SecondModule + << SecondMethod->getSourceRange() << DiffType; }; if (computeODRHash(FirstMethod->getReturnType()) != @@ -517,7 +519,8 @@ bool ODRDiagsEmitter::diagnoseSubMismatchObjCProperty( auto DiagNote = [SecondModule, SecondProp, this](SourceLocation Loc, ODRPropertyDifference DiffType) { return Diag(Loc, diag::note_module_odr_violation_objc_property) - << SecondModule << SecondProp->getSourceRange() << DiffType; + << SecondModule.empty() << SecondModule + << SecondProp->getSourceRange() << DiffType; }; IdentifierInfo *FirstII = FirstProp->getIdentifier(); @@ -690,7 +693,8 @@ void ODRDiagsEmitter::diagnoseSubMismatchDifferentDeclKinds( auto SecondDiagInfo = GetMismatchedDeclLoc(SecondRecord, DR.SecondDiffType, DR.SecondDecl); Diag(SecondDiagInfo.first, diag::note_module_odr_violation_mismatch_decl) - << SecondModule << SecondDiagInfo.second << DR.SecondDiffType; + << SecondModule.empty() << SecondModule << SecondDiagInfo.second + << DR.SecondDiffType; } bool ODRDiagsEmitter::diagnoseMismatch( @@ -1538,7 +1542,8 @@ bool ODRDiagsEmitter::diagnoseMismatch( << FirstDecl->getSourceRange(); Diag(SecondDecl->getLocation(), diag::note_module_odr_violation_mismatch_decl_unknown) - << SecondModule << FirstDiffType << SecondDecl->getSourceRange(); + << SecondModule.empty() << SecondModule << FirstDiffType + << SecondDecl->getSourceRange(); return true; } @@ -1908,6 +1913,7 @@ bool ODRDiagsEmitter::diagnoseMismatch( << FirstDecl->getSourceRange(); Diag(SecondDecl->getLocation(), diag::note_module_odr_violation_mismatch_decl_unknown) - << SecondModule << FirstDiffType << SecondDecl->getSourceRange(); + << SecondModule.empty() << SecondModule << FirstDiffType + << SecondDecl->getSourceRange(); return true; } diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 734c66f..7404eba 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" +#include "clang/AST/ODRDiagsEmitter.h" #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/TargetInfo.h" @@ -2088,11 +2089,23 @@ Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc, /*consumeLastToken=*/true)) return nullptr; - Decl *ProtoType = Actions.ActOnStartProtocolInterface( + Sema::SkipBodyInfo SkipBody; + ObjCProtocolDecl *ProtoType = Actions.ActOnStartProtocolInterface( AtLoc, protocolName, nameLoc, ProtocolRefs.data(), ProtocolRefs.size(), - ProtocolLocs.data(), EndProtoLoc, attrs); + ProtocolLocs.data(), EndProtoLoc, attrs, &SkipBody); ParseObjCInterfaceDeclList(tok::objc_protocol, ProtoType); + if (SkipBody.CheckSameAsPrevious) { + auto *PreviousDef = cast<ObjCProtocolDecl>(SkipBody.Previous); + if (Actions.ActOnDuplicateODRHashDefinition(ProtoType, PreviousDef)) { + ProtoType->mergeDuplicateDefinitionWithCommon( + PreviousDef->getDefinition()); + } else { + ODRDiagsEmitter DiagsEmitter(Diags, Actions.getASTContext(), + getPreprocessor().getLangOpts()); + DiagsEmitter.diagnoseMismatch(PreviousDef, ProtoType); + } + } return Actions.ConvertDeclToDeclGroup(ProtoType); } diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index c55cb78..97dff49 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1213,7 +1213,7 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface( SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, - const ParsedAttributesView &AttrList) { + const ParsedAttributesView &AttrList, SkipBodyInfo *SkipBody) { bool err = false; // FIXME: Deal with AttrList. assert(ProtocolName && "Missing protocol identifier"); @@ -1221,23 +1221,29 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface( forRedeclarationInCurContext()); ObjCProtocolDecl *PDecl = nullptr; if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : nullptr) { - // If we already have a definition, complain. - Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName; - Diag(Def->getLocation(), diag::note_previous_definition); - // Create a new protocol that is completely distinct from previous // declarations, and do not make this protocol available for name lookup. // That way, we'll end up completely ignoring the duplicate. // FIXME: Can we turn this into an error? PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName, ProtocolLoc, AtProtoInterfaceLoc, - /*PrevDecl=*/nullptr); + /*PrevDecl=*/Def); + + if (SkipBody && !hasVisibleDefinition(Def)) { + SkipBody->CheckSameAsPrevious = true; + SkipBody->New = PDecl; + SkipBody->Previous = Def; + } else { + // If we already have a definition, complain. + Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName; + Diag(Def->getLocation(), diag::note_previous_definition); + } // If we are using modules, add the decl to the context in order to // serialize something meaningful. if (getLangOpts().Modules) PushOnScopeChains(PDecl, TUScope); - PDecl->startDefinition(); + PDecl->startDuplicateDefinitionForComparison(); } else { if (PrevDecl) { // Check for circular dependencies among protocol declarations. This can |