1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206 |
- //===-- ODRDiagsEmitter.cpp - Diagnostics for ODR mismatches ----*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "clang/AST/ODRDiagsEmitter.h"
- #include "clang/AST/DeclFriend.h"
- #include "clang/AST/DeclTemplate.h"
- #include "clang/AST/ODRHash.h"
- #include "clang/Basic/DiagnosticAST.h"
- #include "clang/Basic/Module.h"
- using namespace clang;
- static unsigned computeODRHash(QualType Ty) {
- ODRHash Hasher;
- Hasher.AddQualType(Ty);
- return Hasher.CalculateHash();
- }
- static unsigned computeODRHash(const Stmt *S) {
- ODRHash Hasher;
- Hasher.AddStmt(S);
- return Hasher.CalculateHash();
- }
- static unsigned computeODRHash(const Decl *D) {
- assert(D);
- ODRHash Hasher;
- Hasher.AddSubDecl(D);
- return Hasher.CalculateHash();
- }
- static unsigned computeODRHash(const TemplateArgument &TA) {
- ODRHash Hasher;
- Hasher.AddTemplateArgument(TA);
- return Hasher.CalculateHash();
- }
- std::string ODRDiagsEmitter::getOwningModuleNameForDiagnostic(const Decl *D) {
- // If we know the owning module, use it.
- if (Module *M = D->getImportedOwningModule())
- return M->getFullModuleName();
- // Not from a module.
- return {};
- }
- template <typename MethodT>
- static bool diagnoseSubMismatchMethodParameters(DiagnosticsEngine &Diags,
- const NamedDecl *FirstContainer,
- StringRef FirstModule,
- StringRef SecondModule,
- const MethodT *FirstMethod,
- const MethodT *SecondMethod) {
- enum DiagMethodType {
- DiagMethod,
- DiagConstructor,
- DiagDestructor,
- };
- auto GetDiagMethodType = [](const NamedDecl *D) {
- if (isa<CXXConstructorDecl>(D))
- return DiagConstructor;
- if (isa<CXXDestructorDecl>(D))
- return DiagDestructor;
- return DiagMethod;
- };
- enum ODRMethodParametersDifference {
- NumberParameters,
- ParameterType,
- ParameterName,
- };
- auto DiagError = [&Diags, &GetDiagMethodType, FirstContainer, FirstModule,
- FirstMethod](ODRMethodParametersDifference DiffType) {
- DeclarationName FirstName = FirstMethod->getDeclName();
- DiagMethodType FirstMethodType = GetDiagMethodType(FirstMethod);
- return Diags.Report(FirstMethod->getLocation(),
- diag::err_module_odr_violation_method_params)
- << FirstContainer << FirstModule.empty() << FirstModule
- << FirstMethod->getSourceRange() << DiffType << FirstMethodType
- << FirstName;
- };
- auto DiagNote = [&Diags, &GetDiagMethodType, SecondModule,
- SecondMethod](ODRMethodParametersDifference DiffType) {
- DeclarationName SecondName = SecondMethod->getDeclName();
- DiagMethodType SecondMethodType = GetDiagMethodType(SecondMethod);
- return Diags.Report(SecondMethod->getLocation(),
- diag::note_module_odr_violation_method_params)
- << SecondModule.empty() << SecondModule
- << SecondMethod->getSourceRange() << DiffType << SecondMethodType
- << SecondName;
- };
- const unsigned FirstNumParameters = FirstMethod->param_size();
- const unsigned SecondNumParameters = SecondMethod->param_size();
- if (FirstNumParameters != SecondNumParameters) {
- DiagError(NumberParameters) << FirstNumParameters;
- DiagNote(NumberParameters) << SecondNumParameters;
- return true;
- }
- for (unsigned I = 0; I < FirstNumParameters; ++I) {
- const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
- const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
- QualType FirstParamType = FirstParam->getType();
- QualType SecondParamType = SecondParam->getType();
- if (FirstParamType != SecondParamType &&
- computeODRHash(FirstParamType) != computeODRHash(SecondParamType)) {
- if (const DecayedType *ParamDecayedType =
- FirstParamType->getAs<DecayedType>()) {
- DiagError(ParameterType) << (I + 1) << FirstParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- DiagError(ParameterType) << (I + 1) << FirstParamType << false;
- }
- if (const DecayedType *ParamDecayedType =
- SecondParamType->getAs<DecayedType>()) {
- DiagNote(ParameterType) << (I + 1) << SecondParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- DiagNote(ParameterType) << (I + 1) << SecondParamType << false;
- }
- return true;
- }
- DeclarationName FirstParamName = FirstParam->getDeclName();
- DeclarationName SecondParamName = SecondParam->getDeclName();
- if (FirstParamName != SecondParamName) {
- DiagError(ParameterName) << (I + 1) << FirstParamName;
- DiagNote(ParameterName) << (I + 1) << SecondParamName;
- return true;
- }
- }
- return false;
- }
- bool ODRDiagsEmitter::diagnoseSubMismatchField(
- const NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule,
- const FieldDecl *FirstField, const FieldDecl *SecondField) const {
- enum ODRFieldDifference {
- FieldName,
- FieldTypeName,
- FieldSingleBitField,
- FieldDifferentWidthBitField,
- FieldSingleMutable,
- FieldSingleInitializer,
- FieldDifferentInitializers,
- };
- auto DiagError = [FirstRecord, FirstField, FirstModule,
- this](ODRFieldDifference DiffType) {
- return Diag(FirstField->getLocation(), diag::err_module_odr_violation_field)
- << FirstRecord << FirstModule.empty() << FirstModule
- << FirstField->getSourceRange() << DiffType;
- };
- auto DiagNote = [SecondField, SecondModule,
- this](ODRFieldDifference DiffType) {
- return Diag(SecondField->getLocation(),
- diag::note_module_odr_violation_field)
- << SecondModule.empty() << SecondModule << SecondField->getSourceRange() << DiffType;
- };
- IdentifierInfo *FirstII = FirstField->getIdentifier();
- IdentifierInfo *SecondII = SecondField->getIdentifier();
- if (FirstII->getName() != SecondII->getName()) {
- DiagError(FieldName) << FirstII;
- DiagNote(FieldName) << SecondII;
- return true;
- }
- QualType FirstType = FirstField->getType();
- QualType SecondType = SecondField->getType();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagError(FieldTypeName) << FirstII << FirstType;
- DiagNote(FieldTypeName) << SecondII << SecondType;
- return true;
- }
- assert(Context.hasSameType(FirstField->getType(), SecondField->getType()));
- (void)Context;
- const bool IsFirstBitField = FirstField->isBitField();
- const bool IsSecondBitField = SecondField->isBitField();
- if (IsFirstBitField != IsSecondBitField) {
- DiagError(FieldSingleBitField) << FirstII << IsFirstBitField;
- DiagNote(FieldSingleBitField) << SecondII << IsSecondBitField;
- return true;
- }
- if (IsFirstBitField && IsSecondBitField) {
- unsigned FirstBitWidthHash = computeODRHash(FirstField->getBitWidth());
- unsigned SecondBitWidthHash = computeODRHash(SecondField->getBitWidth());
- if (FirstBitWidthHash != SecondBitWidthHash) {
- DiagError(FieldDifferentWidthBitField)
- << FirstII << FirstField->getBitWidth()->getSourceRange();
- DiagNote(FieldDifferentWidthBitField)
- << SecondII << SecondField->getBitWidth()->getSourceRange();
- return true;
- }
- }
- if (!LangOpts.CPlusPlus)
- return false;
- const bool IsFirstMutable = FirstField->isMutable();
- const bool IsSecondMutable = SecondField->isMutable();
- if (IsFirstMutable != IsSecondMutable) {
- DiagError(FieldSingleMutable) << FirstII << IsFirstMutable;
- DiagNote(FieldSingleMutable) << SecondII << IsSecondMutable;
- return true;
- }
- const Expr *FirstInitializer = FirstField->getInClassInitializer();
- const Expr *SecondInitializer = SecondField->getInClassInitializer();
- if ((!FirstInitializer && SecondInitializer) ||
- (FirstInitializer && !SecondInitializer)) {
- DiagError(FieldSingleInitializer)
- << FirstII << (FirstInitializer != nullptr);
- DiagNote(FieldSingleInitializer)
- << SecondII << (SecondInitializer != nullptr);
- return true;
- }
- if (FirstInitializer && SecondInitializer) {
- unsigned FirstInitHash = computeODRHash(FirstInitializer);
- unsigned SecondInitHash = computeODRHash(SecondInitializer);
- if (FirstInitHash != SecondInitHash) {
- DiagError(FieldDifferentInitializers)
- << FirstII << FirstInitializer->getSourceRange();
- DiagNote(FieldDifferentInitializers)
- << SecondII << SecondInitializer->getSourceRange();
- return true;
- }
- }
- return false;
- }
- bool ODRDiagsEmitter::diagnoseSubMismatchTypedef(
- const NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule,
- const TypedefNameDecl *FirstTD, const TypedefNameDecl *SecondTD,
- bool IsTypeAlias) const {
- enum ODRTypedefDifference {
- TypedefName,
- TypedefType,
- };
- auto DiagError = [FirstRecord, FirstTD, FirstModule,
- this](ODRTypedefDifference DiffType) {
- return Diag(FirstTD->getLocation(), diag::err_module_odr_violation_typedef)
- << FirstRecord << FirstModule.empty() << FirstModule
- << FirstTD->getSourceRange() << DiffType;
- };
- auto DiagNote = [SecondTD, SecondModule,
- this](ODRTypedefDifference DiffType) {
- return Diag(SecondTD->getLocation(),
- diag::note_module_odr_violation_typedef)
- << SecondModule << SecondTD->getSourceRange() << DiffType;
- };
- DeclarationName FirstName = FirstTD->getDeclName();
- DeclarationName SecondName = SecondTD->getDeclName();
- if (FirstName != SecondName) {
- DiagError(TypedefName) << IsTypeAlias << FirstName;
- DiagNote(TypedefName) << IsTypeAlias << SecondName;
- return true;
- }
- QualType FirstType = FirstTD->getUnderlyingType();
- QualType SecondType = SecondTD->getUnderlyingType();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagError(TypedefType) << IsTypeAlias << FirstName << FirstType;
- DiagNote(TypedefType) << IsTypeAlias << SecondName << SecondType;
- return true;
- }
- return false;
- }
- bool ODRDiagsEmitter::diagnoseSubMismatchVar(const NamedDecl *FirstRecord,
- StringRef FirstModule,
- StringRef SecondModule,
- const VarDecl *FirstVD,
- const VarDecl *SecondVD) const {
- enum ODRVarDifference {
- VarName,
- VarType,
- VarSingleInitializer,
- VarDifferentInitializer,
- VarConstexpr,
- };
- auto DiagError = [FirstRecord, FirstVD, FirstModule,
- this](ODRVarDifference DiffType) {
- return Diag(FirstVD->getLocation(), diag::err_module_odr_violation_variable)
- << FirstRecord << FirstModule.empty() << FirstModule
- << FirstVD->getSourceRange() << DiffType;
- };
- auto DiagNote = [SecondVD, SecondModule, this](ODRVarDifference DiffType) {
- return Diag(SecondVD->getLocation(),
- diag::note_module_odr_violation_variable)
- << SecondModule << SecondVD->getSourceRange() << DiffType;
- };
- DeclarationName FirstName = FirstVD->getDeclName();
- DeclarationName SecondName = SecondVD->getDeclName();
- if (FirstName != SecondName) {
- DiagError(VarName) << FirstName;
- DiagNote(VarName) << SecondName;
- return true;
- }
- QualType FirstType = FirstVD->getType();
- QualType SecondType = SecondVD->getType();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagError(VarType) << FirstName << FirstType;
- DiagNote(VarType) << SecondName << SecondType;
- return true;
- }
- if (!LangOpts.CPlusPlus)
- return false;
- const Expr *FirstInit = FirstVD->getInit();
- const Expr *SecondInit = SecondVD->getInit();
- if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
- DiagError(VarSingleInitializer)
- << FirstName << (FirstInit == nullptr)
- << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
- DiagNote(VarSingleInitializer)
- << SecondName << (SecondInit == nullptr)
- << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
- return true;
- }
- if (FirstInit && SecondInit &&
- computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
- DiagError(VarDifferentInitializer)
- << FirstName << FirstInit->getSourceRange();
- DiagNote(VarDifferentInitializer)
- << SecondName << SecondInit->getSourceRange();
- return true;
- }
- const bool FirstIsConstexpr = FirstVD->isConstexpr();
- const bool SecondIsConstexpr = SecondVD->isConstexpr();
- if (FirstIsConstexpr != SecondIsConstexpr) {
- DiagError(VarConstexpr) << FirstName << FirstIsConstexpr;
- DiagNote(VarConstexpr) << SecondName << SecondIsConstexpr;
- return true;
- }
- return false;
- }
- bool ODRDiagsEmitter::diagnoseSubMismatchProtocols(
- const ObjCProtocolList &FirstProtocols,
- const ObjCContainerDecl *FirstContainer, StringRef FirstModule,
- const ObjCProtocolList &SecondProtocols,
- const ObjCContainerDecl *SecondContainer, StringRef SecondModule) const {
- // Keep in sync with err_module_odr_violation_referenced_protocols.
- enum ODRReferencedProtocolDifference {
- NumProtocols,
- ProtocolType,
- };
- auto DiagRefProtocolError = [FirstContainer, FirstModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRReferencedProtocolDifference DiffType) {
- return Diag(Loc, diag::err_module_odr_violation_referenced_protocols)
- << FirstContainer << FirstModule.empty() << FirstModule << Range
- << DiffType;
- };
- auto DiagRefProtocolNote = [SecondModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRReferencedProtocolDifference DiffType) {
- return Diag(Loc, diag::note_module_odr_violation_referenced_protocols)
- << SecondModule.empty() << SecondModule << Range << DiffType;
- };
- auto GetProtoListSourceRange = [](const ObjCProtocolList &PL) {
- if (PL.empty())
- return SourceRange();
- return SourceRange(*PL.loc_begin(), *std::prev(PL.loc_end()));
- };
- if (FirstProtocols.size() != SecondProtocols.size()) {
- DiagRefProtocolError(FirstContainer->getLocation(),
- GetProtoListSourceRange(FirstProtocols), NumProtocols)
- << FirstProtocols.size();
- DiagRefProtocolNote(SecondContainer->getLocation(),
- GetProtoListSourceRange(SecondProtocols), NumProtocols)
- << SecondProtocols.size();
- return true;
- }
- for (unsigned I = 0, E = FirstProtocols.size(); I != E; ++I) {
- const ObjCProtocolDecl *FirstProtocol = FirstProtocols[I];
- const ObjCProtocolDecl *SecondProtocol = SecondProtocols[I];
- DeclarationName FirstProtocolName = FirstProtocol->getDeclName();
- DeclarationName SecondProtocolName = SecondProtocol->getDeclName();
- if (FirstProtocolName != SecondProtocolName) {
- SourceLocation FirstLoc = *(FirstProtocols.loc_begin() + I);
- SourceLocation SecondLoc = *(SecondProtocols.loc_begin() + I);
- SourceRange EmptyRange;
- DiagRefProtocolError(FirstLoc, EmptyRange, ProtocolType)
- << (I + 1) << FirstProtocolName;
- DiagRefProtocolNote(SecondLoc, EmptyRange, ProtocolType)
- << (I + 1) << SecondProtocolName;
- return true;
- }
- }
- return false;
- }
- bool ODRDiagsEmitter::diagnoseSubMismatchObjCMethod(
- const NamedDecl *FirstObjCContainer, StringRef FirstModule,
- StringRef SecondModule, const ObjCMethodDecl *FirstMethod,
- const ObjCMethodDecl *SecondMethod) const {
- enum ODRMethodDifference {
- ReturnType,
- InstanceOrClass,
- ControlLevel, // optional/required
- DesignatedInitializer,
- Directness,
- Name,
- };
- auto DiagError = [FirstObjCContainer, FirstModule, FirstMethod,
- this](ODRMethodDifference DiffType) {
- return Diag(FirstMethod->getLocation(),
- diag::err_module_odr_violation_objc_method)
- << FirstObjCContainer << FirstModule.empty() << FirstModule
- << FirstMethod->getSourceRange() << DiffType;
- };
- auto DiagNote = [SecondModule, SecondMethod,
- this](ODRMethodDifference DiffType) {
- return Diag(SecondMethod->getLocation(),
- diag::note_module_odr_violation_objc_method)
- << SecondModule.empty() << SecondModule
- << SecondMethod->getSourceRange() << DiffType;
- };
- if (computeODRHash(FirstMethod->getReturnType()) !=
- computeODRHash(SecondMethod->getReturnType())) {
- DiagError(ReturnType) << FirstMethod << FirstMethod->getReturnType();
- DiagNote(ReturnType) << SecondMethod << SecondMethod->getReturnType();
- return true;
- }
- if (FirstMethod->isInstanceMethod() != SecondMethod->isInstanceMethod()) {
- DiagError(InstanceOrClass)
- << FirstMethod << FirstMethod->isInstanceMethod();
- DiagNote(InstanceOrClass)
- << SecondMethod << SecondMethod->isInstanceMethod();
- return true;
- }
- if (FirstMethod->getImplementationControl() !=
- SecondMethod->getImplementationControl()) {
- DiagError(ControlLevel) << FirstMethod->getImplementationControl();
- DiagNote(ControlLevel) << SecondMethod->getImplementationControl();
- return true;
- }
- if (FirstMethod->isThisDeclarationADesignatedInitializer() !=
- SecondMethod->isThisDeclarationADesignatedInitializer()) {
- DiagError(DesignatedInitializer)
- << FirstMethod
- << FirstMethod->isThisDeclarationADesignatedInitializer();
- DiagNote(DesignatedInitializer)
- << SecondMethod
- << SecondMethod->isThisDeclarationADesignatedInitializer();
- return true;
- }
- if (FirstMethod->isDirectMethod() != SecondMethod->isDirectMethod()) {
- DiagError(Directness) << FirstMethod << FirstMethod->isDirectMethod();
- DiagNote(Directness) << SecondMethod << SecondMethod->isDirectMethod();
- return true;
- }
- if (diagnoseSubMismatchMethodParameters(Diags, FirstObjCContainer,
- FirstModule, SecondModule,
- FirstMethod, SecondMethod))
- return true;
- // Check method name *after* looking at the parameters otherwise we get a
- // less ideal diagnostics: a ObjCMethodName mismatch given that selectors
- // for different parameters are likely to be different.
- DeclarationName FirstName = FirstMethod->getDeclName();
- DeclarationName SecondName = SecondMethod->getDeclName();
- if (FirstName != SecondName) {
- DiagError(Name) << FirstName;
- DiagNote(Name) << SecondName;
- return true;
- }
- return false;
- }
- bool ODRDiagsEmitter::diagnoseSubMismatchObjCProperty(
- const NamedDecl *FirstObjCContainer, StringRef FirstModule,
- StringRef SecondModule, const ObjCPropertyDecl *FirstProp,
- const ObjCPropertyDecl *SecondProp) const {
- enum ODRPropertyDifference {
- Name,
- Type,
- ControlLevel, // optional/required
- Attribute,
- };
- auto DiagError = [FirstObjCContainer, FirstModule, FirstProp,
- this](SourceLocation Loc, ODRPropertyDifference DiffType) {
- return Diag(Loc, diag::err_module_odr_violation_objc_property)
- << FirstObjCContainer << FirstModule.empty() << FirstModule
- << FirstProp->getSourceRange() << DiffType;
- };
- auto DiagNote = [SecondModule, SecondProp,
- this](SourceLocation Loc, ODRPropertyDifference DiffType) {
- return Diag(Loc, diag::note_module_odr_violation_objc_property)
- << SecondModule.empty() << SecondModule
- << SecondProp->getSourceRange() << DiffType;
- };
- IdentifierInfo *FirstII = FirstProp->getIdentifier();
- IdentifierInfo *SecondII = SecondProp->getIdentifier();
- if (FirstII->getName() != SecondII->getName()) {
- DiagError(FirstProp->getLocation(), Name) << FirstII;
- DiagNote(SecondProp->getLocation(), Name) << SecondII;
- return true;
- }
- if (computeODRHash(FirstProp->getType()) !=
- computeODRHash(SecondProp->getType())) {
- DiagError(FirstProp->getLocation(), Type)
- << FirstII << FirstProp->getType();
- DiagNote(SecondProp->getLocation(), Type)
- << SecondII << SecondProp->getType();
- return true;
- }
- if (FirstProp->getPropertyImplementation() !=
- SecondProp->getPropertyImplementation()) {
- DiagError(FirstProp->getLocation(), ControlLevel)
- << FirstProp->getPropertyImplementation();
- DiagNote(SecondProp->getLocation(), ControlLevel)
- << SecondProp->getPropertyImplementation();
- return true;
- }
- // Go over the property attributes and stop at the first mismatch.
- unsigned FirstAttrs = (unsigned)FirstProp->getPropertyAttributes();
- unsigned SecondAttrs = (unsigned)SecondProp->getPropertyAttributes();
- if (FirstAttrs != SecondAttrs) {
- for (unsigned I = 0; I < NumObjCPropertyAttrsBits; ++I) {
- unsigned CheckedAttr = (1 << I);
- if ((FirstAttrs & CheckedAttr) == (SecondAttrs & CheckedAttr))
- continue;
- bool IsFirstWritten =
- (unsigned)FirstProp->getPropertyAttributesAsWritten() & CheckedAttr;
- bool IsSecondWritten =
- (unsigned)SecondProp->getPropertyAttributesAsWritten() & CheckedAttr;
- DiagError(IsFirstWritten ? FirstProp->getLParenLoc()
- : FirstProp->getLocation(),
- Attribute)
- << FirstII << (I + 1) << IsFirstWritten;
- DiagNote(IsSecondWritten ? SecondProp->getLParenLoc()
- : SecondProp->getLocation(),
- Attribute)
- << SecondII << (I + 1);
- return true;
- }
- }
- return false;
- }
- ODRDiagsEmitter::DiffResult
- ODRDiagsEmitter::FindTypeDiffs(DeclHashes &FirstHashes,
- DeclHashes &SecondHashes) {
- auto DifferenceSelector = [](const Decl *D) {
- assert(D && "valid Decl required");
- switch (D->getKind()) {
- default:
- return Other;
- case Decl::AccessSpec:
- switch (D->getAccess()) {
- case AS_public:
- return PublicSpecifer;
- case AS_private:
- return PrivateSpecifer;
- case AS_protected:
- return ProtectedSpecifer;
- case AS_none:
- break;
- }
- llvm_unreachable("Invalid access specifier");
- case Decl::StaticAssert:
- return StaticAssert;
- case Decl::Field:
- return Field;
- case Decl::CXXMethod:
- case Decl::CXXConstructor:
- case Decl::CXXDestructor:
- return CXXMethod;
- case Decl::TypeAlias:
- return TypeAlias;
- case Decl::Typedef:
- return TypeDef;
- case Decl::Var:
- return Var;
- case Decl::Friend:
- return Friend;
- case Decl::FunctionTemplate:
- return FunctionTemplate;
- case Decl::ObjCMethod:
- return ObjCMethod;
- case Decl::ObjCIvar:
- return ObjCIvar;
- case Decl::ObjCProperty:
- return ObjCProperty;
- }
- };
- DiffResult DR;
- auto FirstIt = FirstHashes.begin();
- auto SecondIt = SecondHashes.begin();
- while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) {
- if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() &&
- FirstIt->second == SecondIt->second) {
- ++FirstIt;
- ++SecondIt;
- continue;
- }
- DR.FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first;
- DR.SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first;
- DR.FirstDiffType =
- DR.FirstDecl ? DifferenceSelector(DR.FirstDecl) : EndOfClass;
- DR.SecondDiffType =
- DR.SecondDecl ? DifferenceSelector(DR.SecondDecl) : EndOfClass;
- return DR;
- }
- return DR;
- }
- void ODRDiagsEmitter::diagnoseSubMismatchUnexpected(
- DiffResult &DR, const NamedDecl *FirstRecord, StringRef FirstModule,
- const NamedDecl *SecondRecord, StringRef SecondModule) const {
- Diag(FirstRecord->getLocation(),
- diag::err_module_odr_violation_different_definitions)
- << FirstRecord << FirstModule.empty() << FirstModule;
- if (DR.FirstDecl) {
- Diag(DR.FirstDecl->getLocation(), diag::note_first_module_difference)
- << FirstRecord << DR.FirstDecl->getSourceRange();
- }
- Diag(SecondRecord->getLocation(),
- diag::note_module_odr_violation_different_definitions)
- << SecondModule;
- if (DR.SecondDecl) {
- Diag(DR.SecondDecl->getLocation(), diag::note_second_module_difference)
- << DR.SecondDecl->getSourceRange();
- }
- }
- void ODRDiagsEmitter::diagnoseSubMismatchDifferentDeclKinds(
- DiffResult &DR, const NamedDecl *FirstRecord, StringRef FirstModule,
- const NamedDecl *SecondRecord, StringRef SecondModule) const {
- auto GetMismatchedDeclLoc = [](const NamedDecl *Container,
- ODRMismatchDecl DiffType, const Decl *D) {
- SourceLocation Loc;
- SourceRange Range;
- if (DiffType == EndOfClass) {
- if (auto *Tag = dyn_cast<TagDecl>(Container))
- Loc = Tag->getBraceRange().getEnd();
- else if (auto *IF = dyn_cast<ObjCInterfaceDecl>(Container))
- Loc = IF->getAtEndRange().getBegin();
- else
- Loc = Container->getEndLoc();
- } else {
- Loc = D->getLocation();
- Range = D->getSourceRange();
- }
- return std::make_pair(Loc, Range);
- };
- auto FirstDiagInfo =
- GetMismatchedDeclLoc(FirstRecord, DR.FirstDiffType, DR.FirstDecl);
- Diag(FirstDiagInfo.first, diag::err_module_odr_violation_mismatch_decl)
- << FirstRecord << FirstModule.empty() << FirstModule
- << FirstDiagInfo.second << DR.FirstDiffType;
- auto SecondDiagInfo =
- GetMismatchedDeclLoc(SecondRecord, DR.SecondDiffType, DR.SecondDecl);
- Diag(SecondDiagInfo.first, diag::note_module_odr_violation_mismatch_decl)
- << SecondModule.empty() << SecondModule << SecondDiagInfo.second
- << DR.SecondDiffType;
- }
- bool ODRDiagsEmitter::diagnoseMismatch(
- const CXXRecordDecl *FirstRecord, const CXXRecordDecl *SecondRecord,
- const struct CXXRecordDecl::DefinitionData *SecondDD) const {
- // Multiple different declarations got merged together; tell the user
- // where they came from.
- if (FirstRecord == SecondRecord)
- return false;
- std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord);
- std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
- const struct CXXRecordDecl::DefinitionData *FirstDD =
- FirstRecord->DefinitionData;
- assert(FirstDD && SecondDD && "Definitions without DefinitionData");
- // Diagnostics from DefinitionData are emitted here.
- if (FirstDD != SecondDD) {
- // Keep in sync with err_module_odr_violation_definition_data.
- enum ODRDefinitionDataDifference {
- NumBases,
- NumVBases,
- BaseType,
- BaseVirtual,
- BaseAccess,
- };
- auto DiagBaseError = [FirstRecord, &FirstModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRDefinitionDataDifference DiffType) {
- return Diag(Loc, diag::err_module_odr_violation_definition_data)
- << FirstRecord << FirstModule.empty() << FirstModule << Range
- << DiffType;
- };
- auto DiagBaseNote = [&SecondModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRDefinitionDataDifference DiffType) {
- return Diag(Loc, diag::note_module_odr_violation_definition_data)
- << SecondModule << Range << DiffType;
- };
- auto GetSourceRange = [](const struct CXXRecordDecl::DefinitionData *DD) {
- unsigned NumBases = DD->NumBases;
- if (NumBases == 0)
- return SourceRange();
- ArrayRef<CXXBaseSpecifier> bases = DD->bases();
- return SourceRange(bases[0].getBeginLoc(),
- bases[NumBases - 1].getEndLoc());
- };
- unsigned FirstNumBases = FirstDD->NumBases;
- unsigned FirstNumVBases = FirstDD->NumVBases;
- unsigned SecondNumBases = SecondDD->NumBases;
- unsigned SecondNumVBases = SecondDD->NumVBases;
- if (FirstNumBases != SecondNumBases) {
- DiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
- NumBases)
- << FirstNumBases;
- DiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
- NumBases)
- << SecondNumBases;
- return true;
- }
- if (FirstNumVBases != SecondNumVBases) {
- DiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
- NumVBases)
- << FirstNumVBases;
- DiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
- NumVBases)
- << SecondNumVBases;
- return true;
- }
- ArrayRef<CXXBaseSpecifier> FirstBases = FirstDD->bases();
- ArrayRef<CXXBaseSpecifier> SecondBases = SecondDD->bases();
- for (unsigned I = 0; I < FirstNumBases; ++I) {
- const CXXBaseSpecifier FirstBase = FirstBases[I];
- const CXXBaseSpecifier SecondBase = SecondBases[I];
- if (computeODRHash(FirstBase.getType()) !=
- computeODRHash(SecondBase.getType())) {
- DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
- BaseType)
- << (I + 1) << FirstBase.getType();
- DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(),
- BaseType)
- << (I + 1) << SecondBase.getType();
- return true;
- }
- if (FirstBase.isVirtual() != SecondBase.isVirtual()) {
- DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
- BaseVirtual)
- << (I + 1) << FirstBase.isVirtual() << FirstBase.getType();
- DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(),
- BaseVirtual)
- << (I + 1) << SecondBase.isVirtual() << SecondBase.getType();
- return true;
- }
- if (FirstBase.getAccessSpecifierAsWritten() !=
- SecondBase.getAccessSpecifierAsWritten()) {
- DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
- BaseAccess)
- << (I + 1) << FirstBase.getType()
- << (int)FirstBase.getAccessSpecifierAsWritten();
- DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(),
- BaseAccess)
- << (I + 1) << SecondBase.getType()
- << (int)SecondBase.getAccessSpecifierAsWritten();
- return true;
- }
- }
- }
- const ClassTemplateDecl *FirstTemplate =
- FirstRecord->getDescribedClassTemplate();
- const ClassTemplateDecl *SecondTemplate =
- SecondRecord->getDescribedClassTemplate();
- assert(!FirstTemplate == !SecondTemplate &&
- "Both pointers should be null or non-null");
- if (FirstTemplate && SecondTemplate) {
- ArrayRef<const NamedDecl *> FirstTemplateParams =
- FirstTemplate->getTemplateParameters()->asArray();
- ArrayRef<const NamedDecl *> SecondTemplateParams =
- SecondTemplate->getTemplateParameters()->asArray();
- assert(FirstTemplateParams.size() == SecondTemplateParams.size() &&
- "Number of template parameters should be equal.");
- for (auto Pair : llvm::zip(FirstTemplateParams, SecondTemplateParams)) {
- const NamedDecl *FirstDecl = std::get<0>(Pair);
- const NamedDecl *SecondDecl = std::get<1>(Pair);
- if (computeODRHash(FirstDecl) == computeODRHash(SecondDecl))
- continue;
- assert(FirstDecl->getKind() == SecondDecl->getKind() &&
- "Parameter Decl's should be the same kind.");
- enum ODRTemplateDifference {
- ParamEmptyName,
- ParamName,
- ParamSingleDefaultArgument,
- ParamDifferentDefaultArgument,
- };
- auto hasDefaultArg = [](const NamedDecl *D) {
- if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
- return TTP->hasDefaultArgument() &&
- !TTP->defaultArgumentWasInherited();
- if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
- return NTTP->hasDefaultArgument() &&
- !NTTP->defaultArgumentWasInherited();
- auto *TTP = cast<TemplateTemplateParmDecl>(D);
- return TTP->hasDefaultArgument() && !TTP->defaultArgumentWasInherited();
- };
- bool hasFirstArg = hasDefaultArg(FirstDecl);
- bool hasSecondArg = hasDefaultArg(SecondDecl);
- ODRTemplateDifference ErrDiffType;
- ODRTemplateDifference NoteDiffType;
- DeclarationName FirstName = FirstDecl->getDeclName();
- DeclarationName SecondName = SecondDecl->getDeclName();
- if (FirstName != SecondName) {
- bool FirstNameEmpty =
- FirstName.isIdentifier() && !FirstName.getAsIdentifierInfo();
- bool SecondNameEmpty =
- SecondName.isIdentifier() && !SecondName.getAsIdentifierInfo();
- ErrDiffType = FirstNameEmpty ? ParamEmptyName : ParamName;
- NoteDiffType = SecondNameEmpty ? ParamEmptyName : ParamName;
- } else if (hasFirstArg == hasSecondArg)
- ErrDiffType = NoteDiffType = ParamDifferentDefaultArgument;
- else
- ErrDiffType = NoteDiffType = ParamSingleDefaultArgument;
- Diag(FirstDecl->getLocation(),
- diag::err_module_odr_violation_template_parameter)
- << FirstRecord << FirstModule.empty() << FirstModule
- << FirstDecl->getSourceRange() << ErrDiffType << hasFirstArg
- << FirstName;
- Diag(SecondDecl->getLocation(),
- diag::note_module_odr_violation_template_parameter)
- << SecondModule << SecondDecl->getSourceRange() << NoteDiffType
- << hasSecondArg << SecondName;
- return true;
- }
- }
- auto PopulateHashes = [](DeclHashes &Hashes, const RecordDecl *Record,
- const DeclContext *DC) {
- for (const Decl *D : Record->decls()) {
- if (!ODRHash::isSubDeclToBeProcessed(D, DC))
- continue;
- Hashes.emplace_back(D, computeODRHash(D));
- }
- };
- DeclHashes FirstHashes;
- DeclHashes SecondHashes;
- const DeclContext *DC = FirstRecord;
- PopulateHashes(FirstHashes, FirstRecord, DC);
- PopulateHashes(SecondHashes, SecondRecord, DC);
- DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
- ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
- ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
- const Decl *FirstDecl = DR.FirstDecl;
- const Decl *SecondDecl = DR.SecondDecl;
- if (FirstDiffType == Other || SecondDiffType == Other) {
- diagnoseSubMismatchUnexpected(DR, FirstRecord, FirstModule, SecondRecord,
- SecondModule);
- return true;
- }
- if (FirstDiffType != SecondDiffType) {
- diagnoseSubMismatchDifferentDeclKinds(DR, FirstRecord, FirstModule,
- SecondRecord, SecondModule);
- return true;
- }
- // Used with err_module_odr_violation_record and
- // note_module_odr_violation_record
- enum ODRCXXRecordDifference {
- StaticAssertCondition,
- StaticAssertMessage,
- StaticAssertOnlyMessage,
- MethodName,
- MethodDeleted,
- MethodDefaulted,
- MethodVirtual,
- MethodStatic,
- MethodVolatile,
- MethodConst,
- MethodInline,
- MethodParameterSingleDefaultArgument,
- MethodParameterDifferentDefaultArgument,
- MethodNoTemplateArguments,
- MethodDifferentNumberTemplateArguments,
- MethodDifferentTemplateArgument,
- MethodSingleBody,
- MethodDifferentBody,
- FriendTypeFunction,
- FriendType,
- FriendFunction,
- FunctionTemplateDifferentNumberParameters,
- FunctionTemplateParameterDifferentKind,
- FunctionTemplateParameterName,
- FunctionTemplateParameterSingleDefaultArgument,
- FunctionTemplateParameterDifferentDefaultArgument,
- FunctionTemplateParameterDifferentType,
- FunctionTemplatePackParameter,
- };
- auto DiagError = [FirstRecord, &FirstModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRCXXRecordDifference DiffType) {
- return Diag(Loc, diag::err_module_odr_violation_record)
- << FirstRecord << FirstModule.empty() << FirstModule << Range
- << DiffType;
- };
- auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range,
- ODRCXXRecordDifference DiffType) {
- return Diag(Loc, diag::note_module_odr_violation_record)
- << SecondModule << Range << DiffType;
- };
- assert(FirstDiffType == SecondDiffType);
- switch (FirstDiffType) {
- case Other:
- case EndOfClass:
- case PublicSpecifer:
- case PrivateSpecifer:
- case ProtectedSpecifer:
- case ObjCMethod:
- case ObjCIvar:
- case ObjCProperty:
- llvm_unreachable("Invalid diff type");
- case StaticAssert: {
- const StaticAssertDecl *FirstSA = cast<StaticAssertDecl>(FirstDecl);
- const StaticAssertDecl *SecondSA = cast<StaticAssertDecl>(SecondDecl);
- const Expr *FirstExpr = FirstSA->getAssertExpr();
- const Expr *SecondExpr = SecondSA->getAssertExpr();
- unsigned FirstODRHash = computeODRHash(FirstExpr);
- unsigned SecondODRHash = computeODRHash(SecondExpr);
- if (FirstODRHash != SecondODRHash) {
- DiagError(FirstExpr->getBeginLoc(), FirstExpr->getSourceRange(),
- StaticAssertCondition);
- DiagNote(SecondExpr->getBeginLoc(), SecondExpr->getSourceRange(),
- StaticAssertCondition);
- return true;
- }
- const StringLiteral *FirstStr = FirstSA->getMessage();
- const StringLiteral *SecondStr = SecondSA->getMessage();
- assert((FirstStr || SecondStr) && "Both messages cannot be empty");
- if ((FirstStr && !SecondStr) || (!FirstStr && SecondStr)) {
- SourceLocation FirstLoc, SecondLoc;
- SourceRange FirstRange, SecondRange;
- if (FirstStr) {
- FirstLoc = FirstStr->getBeginLoc();
- FirstRange = FirstStr->getSourceRange();
- } else {
- FirstLoc = FirstSA->getBeginLoc();
- FirstRange = FirstSA->getSourceRange();
- }
- if (SecondStr) {
- SecondLoc = SecondStr->getBeginLoc();
- SecondRange = SecondStr->getSourceRange();
- } else {
- SecondLoc = SecondSA->getBeginLoc();
- SecondRange = SecondSA->getSourceRange();
- }
- DiagError(FirstLoc, FirstRange, StaticAssertOnlyMessage)
- << (FirstStr == nullptr);
- DiagNote(SecondLoc, SecondRange, StaticAssertOnlyMessage)
- << (SecondStr == nullptr);
- return true;
- }
- if (FirstStr && SecondStr &&
- FirstStr->getString() != SecondStr->getString()) {
- DiagError(FirstStr->getBeginLoc(), FirstStr->getSourceRange(),
- StaticAssertMessage);
- DiagNote(SecondStr->getBeginLoc(), SecondStr->getSourceRange(),
- StaticAssertMessage);
- return true;
- }
- break;
- }
- case Field: {
- if (diagnoseSubMismatchField(FirstRecord, FirstModule, SecondModule,
- cast<FieldDecl>(FirstDecl),
- cast<FieldDecl>(SecondDecl)))
- return true;
- break;
- }
- case CXXMethod: {
- enum {
- DiagMethod,
- DiagConstructor,
- DiagDestructor,
- } FirstMethodType,
- SecondMethodType;
- auto GetMethodTypeForDiagnostics = [](const CXXMethodDecl *D) {
- if (isa<CXXConstructorDecl>(D))
- return DiagConstructor;
- if (isa<CXXDestructorDecl>(D))
- return DiagDestructor;
- return DiagMethod;
- };
- const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl);
- const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl);
- FirstMethodType = GetMethodTypeForDiagnostics(FirstMethod);
- SecondMethodType = GetMethodTypeForDiagnostics(SecondMethod);
- DeclarationName FirstName = FirstMethod->getDeclName();
- DeclarationName SecondName = SecondMethod->getDeclName();
- auto DiagMethodError = [&DiagError, FirstMethod, FirstMethodType,
- FirstName](ODRCXXRecordDifference DiffType) {
- return DiagError(FirstMethod->getLocation(),
- FirstMethod->getSourceRange(), DiffType)
- << FirstMethodType << FirstName;
- };
- auto DiagMethodNote = [&DiagNote, SecondMethod, SecondMethodType,
- SecondName](ODRCXXRecordDifference DiffType) {
- return DiagNote(SecondMethod->getLocation(),
- SecondMethod->getSourceRange(), DiffType)
- << SecondMethodType << SecondName;
- };
- if (FirstMethodType != SecondMethodType || FirstName != SecondName) {
- DiagMethodError(MethodName);
- DiagMethodNote(MethodName);
- return true;
- }
- const bool FirstDeleted = FirstMethod->isDeletedAsWritten();
- const bool SecondDeleted = SecondMethod->isDeletedAsWritten();
- if (FirstDeleted != SecondDeleted) {
- DiagMethodError(MethodDeleted) << FirstDeleted;
- DiagMethodNote(MethodDeleted) << SecondDeleted;
- return true;
- }
- const bool FirstDefaulted = FirstMethod->isExplicitlyDefaulted();
- const bool SecondDefaulted = SecondMethod->isExplicitlyDefaulted();
- if (FirstDefaulted != SecondDefaulted) {
- DiagMethodError(MethodDefaulted) << FirstDefaulted;
- DiagMethodNote(MethodDefaulted) << SecondDefaulted;
- return true;
- }
- const bool FirstVirtual = FirstMethod->isVirtualAsWritten();
- const bool SecondVirtual = SecondMethod->isVirtualAsWritten();
- const bool FirstPure = FirstMethod->isPure();
- const bool SecondPure = SecondMethod->isPure();
- if ((FirstVirtual || SecondVirtual) &&
- (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) {
- DiagMethodError(MethodVirtual) << FirstPure << FirstVirtual;
- DiagMethodNote(MethodVirtual) << SecondPure << SecondVirtual;
- return true;
- }
- // CXXMethodDecl::isStatic uses the canonical Decl. With Decl merging,
- // FirstDecl is the canonical Decl of SecondDecl, so the storage
- // class needs to be checked instead.
- StorageClass FirstStorage = FirstMethod->getStorageClass();
- StorageClass SecondStorage = SecondMethod->getStorageClass();
- const bool FirstStatic = FirstStorage == SC_Static;
- const bool SecondStatic = SecondStorage == SC_Static;
- if (FirstStatic != SecondStatic) {
- DiagMethodError(MethodStatic) << FirstStatic;
- DiagMethodNote(MethodStatic) << SecondStatic;
- return true;
- }
- const bool FirstVolatile = FirstMethod->isVolatile();
- const bool SecondVolatile = SecondMethod->isVolatile();
- if (FirstVolatile != SecondVolatile) {
- DiagMethodError(MethodVolatile) << FirstVolatile;
- DiagMethodNote(MethodVolatile) << SecondVolatile;
- return true;
- }
- const bool FirstConst = FirstMethod->isConst();
- const bool SecondConst = SecondMethod->isConst();
- if (FirstConst != SecondConst) {
- DiagMethodError(MethodConst) << FirstConst;
- DiagMethodNote(MethodConst) << SecondConst;
- return true;
- }
- const bool FirstInline = FirstMethod->isInlineSpecified();
- const bool SecondInline = SecondMethod->isInlineSpecified();
- if (FirstInline != SecondInline) {
- DiagMethodError(MethodInline) << FirstInline;
- DiagMethodNote(MethodInline) << SecondInline;
- return true;
- }
- if (diagnoseSubMismatchMethodParameters(Diags, FirstRecord,
- FirstModule, SecondModule,
- FirstMethod, SecondMethod))
- return true;
- for (unsigned I = 0, N = FirstMethod->param_size(); I < N; ++I) {
- const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
- const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
- const Expr *FirstInit = FirstParam->getInit();
- const Expr *SecondInit = SecondParam->getInit();
- if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
- DiagMethodError(MethodParameterSingleDefaultArgument)
- << (I + 1) << (FirstInit == nullptr)
- << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
- DiagMethodNote(MethodParameterSingleDefaultArgument)
- << (I + 1) << (SecondInit == nullptr)
- << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
- return true;
- }
- if (FirstInit && SecondInit &&
- computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
- DiagMethodError(MethodParameterDifferentDefaultArgument)
- << (I + 1) << FirstInit->getSourceRange();
- DiagMethodNote(MethodParameterDifferentDefaultArgument)
- << (I + 1) << SecondInit->getSourceRange();
- return true;
- }
- }
- const TemplateArgumentList *FirstTemplateArgs =
- FirstMethod->getTemplateSpecializationArgs();
- const TemplateArgumentList *SecondTemplateArgs =
- SecondMethod->getTemplateSpecializationArgs();
- if ((FirstTemplateArgs && !SecondTemplateArgs) ||
- (!FirstTemplateArgs && SecondTemplateArgs)) {
- DiagMethodError(MethodNoTemplateArguments)
- << (FirstTemplateArgs != nullptr);
- DiagMethodNote(MethodNoTemplateArguments)
- << (SecondTemplateArgs != nullptr);
- return true;
- }
- if (FirstTemplateArgs && SecondTemplateArgs) {
- // Remove pack expansions from argument list.
- auto ExpandTemplateArgumentList = [](const TemplateArgumentList *TAL) {
- llvm::SmallVector<const TemplateArgument *, 8> ExpandedList;
- for (const TemplateArgument &TA : TAL->asArray()) {
- if (TA.getKind() != TemplateArgument::Pack) {
- ExpandedList.push_back(&TA);
- continue;
- }
- llvm::append_range(ExpandedList,
- llvm::make_pointer_range(TA.getPackAsArray()));
- }
- return ExpandedList;
- };
- llvm::SmallVector<const TemplateArgument *, 8> FirstExpandedList =
- ExpandTemplateArgumentList(FirstTemplateArgs);
- llvm::SmallVector<const TemplateArgument *, 8> SecondExpandedList =
- ExpandTemplateArgumentList(SecondTemplateArgs);
- if (FirstExpandedList.size() != SecondExpandedList.size()) {
- DiagMethodError(MethodDifferentNumberTemplateArguments)
- << (unsigned)FirstExpandedList.size();
- DiagMethodNote(MethodDifferentNumberTemplateArguments)
- << (unsigned)SecondExpandedList.size();
- return true;
- }
- for (unsigned i = 0, e = FirstExpandedList.size(); i != e; ++i) {
- const TemplateArgument &FirstTA = *FirstExpandedList[i],
- &SecondTA = *SecondExpandedList[i];
- if (computeODRHash(FirstTA) == computeODRHash(SecondTA))
- continue;
- DiagMethodError(MethodDifferentTemplateArgument) << FirstTA << i + 1;
- DiagMethodNote(MethodDifferentTemplateArgument) << SecondTA << i + 1;
- return true;
- }
- }
- // Compute the hash of the method as if it has no body.
- auto ComputeCXXMethodODRHash = [](const CXXMethodDecl *D) {
- ODRHash Hasher;
- Hasher.AddFunctionDecl(D, true /*SkipBody*/);
- return Hasher.CalculateHash();
- };
- // Compare the hash generated to the hash stored. A difference means
- // that a body was present in the original source. Due to merging,
- // the standard way of detecting a body will not work.
- const bool HasFirstBody =
- ComputeCXXMethodODRHash(FirstMethod) != FirstMethod->getODRHash();
- const bool HasSecondBody =
- ComputeCXXMethodODRHash(SecondMethod) != SecondMethod->getODRHash();
- if (HasFirstBody != HasSecondBody) {
- DiagMethodError(MethodSingleBody) << HasFirstBody;
- DiagMethodNote(MethodSingleBody) << HasSecondBody;
- return true;
- }
- if (HasFirstBody && HasSecondBody) {
- DiagMethodError(MethodDifferentBody);
- DiagMethodNote(MethodDifferentBody);
- return true;
- }
- break;
- }
- case TypeAlias:
- case TypeDef: {
- if (diagnoseSubMismatchTypedef(FirstRecord, FirstModule, SecondModule,
- cast<TypedefNameDecl>(FirstDecl),
- cast<TypedefNameDecl>(SecondDecl),
- FirstDiffType == TypeAlias))
- return true;
- break;
- }
- case Var: {
- if (diagnoseSubMismatchVar(FirstRecord, FirstModule, SecondModule,
- cast<VarDecl>(FirstDecl),
- cast<VarDecl>(SecondDecl)))
- return true;
- break;
- }
- case Friend: {
- const FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl);
- const FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl);
- const NamedDecl *FirstND = FirstFriend->getFriendDecl();
- const NamedDecl *SecondND = SecondFriend->getFriendDecl();
- TypeSourceInfo *FirstTSI = FirstFriend->getFriendType();
- TypeSourceInfo *SecondTSI = SecondFriend->getFriendType();
- if (FirstND && SecondND) {
- DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
- FriendFunction)
- << FirstND;
- DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(),
- FriendFunction)
- << SecondND;
- return true;
- }
- if (FirstTSI && SecondTSI) {
- QualType FirstFriendType = FirstTSI->getType();
- QualType SecondFriendType = SecondTSI->getType();
- assert(computeODRHash(FirstFriendType) !=
- computeODRHash(SecondFriendType));
- DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
- FriendType)
- << FirstFriendType;
- DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(),
- FriendType)
- << SecondFriendType;
- return true;
- }
- DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
- FriendTypeFunction)
- << (FirstTSI == nullptr);
- DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(),
- FriendTypeFunction)
- << (SecondTSI == nullptr);
- return true;
- }
- case FunctionTemplate: {
- const FunctionTemplateDecl *FirstTemplate =
- cast<FunctionTemplateDecl>(FirstDecl);
- const FunctionTemplateDecl *SecondTemplate =
- cast<FunctionTemplateDecl>(SecondDecl);
- TemplateParameterList *FirstTPL = FirstTemplate->getTemplateParameters();
- TemplateParameterList *SecondTPL = SecondTemplate->getTemplateParameters();
- auto DiagTemplateError = [&DiagError,
- FirstTemplate](ODRCXXRecordDifference DiffType) {
- return DiagError(FirstTemplate->getLocation(),
- FirstTemplate->getSourceRange(), DiffType)
- << FirstTemplate;
- };
- auto DiagTemplateNote = [&DiagNote,
- SecondTemplate](ODRCXXRecordDifference DiffType) {
- return DiagNote(SecondTemplate->getLocation(),
- SecondTemplate->getSourceRange(), DiffType)
- << SecondTemplate;
- };
- if (FirstTPL->size() != SecondTPL->size()) {
- DiagTemplateError(FunctionTemplateDifferentNumberParameters)
- << FirstTPL->size();
- DiagTemplateNote(FunctionTemplateDifferentNumberParameters)
- << SecondTPL->size();
- return true;
- }
- for (unsigned i = 0, e = FirstTPL->size(); i != e; ++i) {
- NamedDecl *FirstParam = FirstTPL->getParam(i);
- NamedDecl *SecondParam = SecondTPL->getParam(i);
- if (FirstParam->getKind() != SecondParam->getKind()) {
- enum {
- TemplateTypeParameter,
- NonTypeTemplateParameter,
- TemplateTemplateParameter,
- };
- auto GetParamType = [](NamedDecl *D) {
- switch (D->getKind()) {
- default:
- llvm_unreachable("Unexpected template parameter type");
- case Decl::TemplateTypeParm:
- return TemplateTypeParameter;
- case Decl::NonTypeTemplateParm:
- return NonTypeTemplateParameter;
- case Decl::TemplateTemplateParm:
- return TemplateTemplateParameter;
- }
- };
- DiagTemplateError(FunctionTemplateParameterDifferentKind)
- << (i + 1) << GetParamType(FirstParam);
- DiagTemplateNote(FunctionTemplateParameterDifferentKind)
- << (i + 1) << GetParamType(SecondParam);
- return true;
- }
- if (FirstParam->getName() != SecondParam->getName()) {
- DiagTemplateError(FunctionTemplateParameterName)
- << (i + 1) << (bool)FirstParam->getIdentifier() << FirstParam;
- DiagTemplateNote(FunctionTemplateParameterName)
- << (i + 1) << (bool)SecondParam->getIdentifier() << SecondParam;
- return true;
- }
- if (isa<TemplateTypeParmDecl>(FirstParam) &&
- isa<TemplateTypeParmDecl>(SecondParam)) {
- TemplateTypeParmDecl *FirstTTPD =
- cast<TemplateTypeParmDecl>(FirstParam);
- TemplateTypeParmDecl *SecondTTPD =
- cast<TemplateTypeParmDecl>(SecondParam);
- bool HasFirstDefaultArgument =
- FirstTTPD->hasDefaultArgument() &&
- !FirstTTPD->defaultArgumentWasInherited();
- bool HasSecondDefaultArgument =
- SecondTTPD->hasDefaultArgument() &&
- !SecondTTPD->defaultArgumentWasInherited();
- if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
- DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasFirstDefaultArgument;
- DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasSecondDefaultArgument;
- return true;
- }
- if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
- QualType FirstType = FirstTTPD->getDefaultArgument();
- QualType SecondType = SecondTTPD->getDefaultArgument();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << FirstType;
- DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << SecondType;
- return true;
- }
- }
- if (FirstTTPD->isParameterPack() != SecondTTPD->isParameterPack()) {
- DiagTemplateError(FunctionTemplatePackParameter)
- << (i + 1) << FirstTTPD->isParameterPack();
- DiagTemplateNote(FunctionTemplatePackParameter)
- << (i + 1) << SecondTTPD->isParameterPack();
- return true;
- }
- }
- if (isa<TemplateTemplateParmDecl>(FirstParam) &&
- isa<TemplateTemplateParmDecl>(SecondParam)) {
- TemplateTemplateParmDecl *FirstTTPD =
- cast<TemplateTemplateParmDecl>(FirstParam);
- TemplateTemplateParmDecl *SecondTTPD =
- cast<TemplateTemplateParmDecl>(SecondParam);
- TemplateParameterList *FirstTPL = FirstTTPD->getTemplateParameters();
- TemplateParameterList *SecondTPL = SecondTTPD->getTemplateParameters();
- auto ComputeTemplateParameterListODRHash =
- [](const TemplateParameterList *TPL) {
- assert(TPL);
- ODRHash Hasher;
- Hasher.AddTemplateParameterList(TPL);
- return Hasher.CalculateHash();
- };
- if (ComputeTemplateParameterListODRHash(FirstTPL) !=
- ComputeTemplateParameterListODRHash(SecondTPL)) {
- DiagTemplateError(FunctionTemplateParameterDifferentType) << (i + 1);
- DiagTemplateNote(FunctionTemplateParameterDifferentType) << (i + 1);
- return true;
- }
- bool HasFirstDefaultArgument =
- FirstTTPD->hasDefaultArgument() &&
- !FirstTTPD->defaultArgumentWasInherited();
- bool HasSecondDefaultArgument =
- SecondTTPD->hasDefaultArgument() &&
- !SecondTTPD->defaultArgumentWasInherited();
- if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
- DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasFirstDefaultArgument;
- DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasSecondDefaultArgument;
- return true;
- }
- if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
- TemplateArgument FirstTA =
- FirstTTPD->getDefaultArgument().getArgument();
- TemplateArgument SecondTA =
- SecondTTPD->getDefaultArgument().getArgument();
- if (computeODRHash(FirstTA) != computeODRHash(SecondTA)) {
- DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << FirstTA;
- DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << SecondTA;
- return true;
- }
- }
- if (FirstTTPD->isParameterPack() != SecondTTPD->isParameterPack()) {
- DiagTemplateError(FunctionTemplatePackParameter)
- << (i + 1) << FirstTTPD->isParameterPack();
- DiagTemplateNote(FunctionTemplatePackParameter)
- << (i + 1) << SecondTTPD->isParameterPack();
- return true;
- }
- }
- if (isa<NonTypeTemplateParmDecl>(FirstParam) &&
- isa<NonTypeTemplateParmDecl>(SecondParam)) {
- NonTypeTemplateParmDecl *FirstNTTPD =
- cast<NonTypeTemplateParmDecl>(FirstParam);
- NonTypeTemplateParmDecl *SecondNTTPD =
- cast<NonTypeTemplateParmDecl>(SecondParam);
- QualType FirstType = FirstNTTPD->getType();
- QualType SecondType = SecondNTTPD->getType();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagTemplateError(FunctionTemplateParameterDifferentType) << (i + 1);
- DiagTemplateNote(FunctionTemplateParameterDifferentType) << (i + 1);
- return true;
- }
- bool HasFirstDefaultArgument =
- FirstNTTPD->hasDefaultArgument() &&
- !FirstNTTPD->defaultArgumentWasInherited();
- bool HasSecondDefaultArgument =
- SecondNTTPD->hasDefaultArgument() &&
- !SecondNTTPD->defaultArgumentWasInherited();
- if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
- DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasFirstDefaultArgument;
- DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
- << (i + 1) << HasSecondDefaultArgument;
- return true;
- }
- if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
- Expr *FirstDefaultArgument = FirstNTTPD->getDefaultArgument();
- Expr *SecondDefaultArgument = SecondNTTPD->getDefaultArgument();
- if (computeODRHash(FirstDefaultArgument) !=
- computeODRHash(SecondDefaultArgument)) {
- DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << FirstDefaultArgument;
- DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument)
- << (i + 1) << SecondDefaultArgument;
- return true;
- }
- }
- if (FirstNTTPD->isParameterPack() != SecondNTTPD->isParameterPack()) {
- DiagTemplateError(FunctionTemplatePackParameter)
- << (i + 1) << FirstNTTPD->isParameterPack();
- DiagTemplateNote(FunctionTemplatePackParameter)
- << (i + 1) << SecondNTTPD->isParameterPack();
- return true;
- }
- }
- }
- break;
- }
- }
- Diag(FirstDecl->getLocation(),
- diag::err_module_odr_violation_mismatch_decl_unknown)
- << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType
- << FirstDecl->getSourceRange();
- Diag(SecondDecl->getLocation(),
- diag::note_module_odr_violation_mismatch_decl_unknown)
- << SecondModule.empty() << SecondModule << FirstDiffType
- << SecondDecl->getSourceRange();
- return true;
- }
- bool ODRDiagsEmitter::diagnoseMismatch(const RecordDecl *FirstRecord,
- const RecordDecl *SecondRecord) const {
- if (FirstRecord == SecondRecord)
- return false;
- std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord);
- std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
- auto PopulateHashes = [](DeclHashes &Hashes, const RecordDecl *Record,
- const DeclContext *DC) {
- for (const Decl *D : Record->decls()) {
- if (!ODRHash::isSubDeclToBeProcessed(D, DC))
- continue;
- Hashes.emplace_back(D, computeODRHash(D));
- }
- };
- DeclHashes FirstHashes;
- DeclHashes SecondHashes;
- const DeclContext *DC = FirstRecord;
- PopulateHashes(FirstHashes, FirstRecord, DC);
- PopulateHashes(SecondHashes, SecondRecord, DC);
- DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
- ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
- ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
- const Decl *FirstDecl = DR.FirstDecl;
- const Decl *SecondDecl = DR.SecondDecl;
- if (FirstDiffType == Other || SecondDiffType == Other) {
- diagnoseSubMismatchUnexpected(DR, FirstRecord, FirstModule, SecondRecord,
- SecondModule);
- return true;
- }
- if (FirstDiffType != SecondDiffType) {
- diagnoseSubMismatchDifferentDeclKinds(DR, FirstRecord, FirstModule,
- SecondRecord, SecondModule);
- return true;
- }
- assert(FirstDiffType == SecondDiffType);
- switch (FirstDiffType) {
- // Already handled.
- case EndOfClass:
- case Other:
- // C++ only, invalid in this context.
- case PublicSpecifer:
- case PrivateSpecifer:
- case ProtectedSpecifer:
- case StaticAssert:
- case CXXMethod:
- case TypeAlias:
- case Friend:
- case FunctionTemplate:
- // Cannot be contained by RecordDecl, invalid in this context.
- case ObjCMethod:
- case ObjCIvar:
- case ObjCProperty:
- llvm_unreachable("Invalid diff type");
- case Field: {
- if (diagnoseSubMismatchField(FirstRecord, FirstModule, SecondModule,
- cast<FieldDecl>(FirstDecl),
- cast<FieldDecl>(SecondDecl)))
- return true;
- break;
- }
- case TypeDef: {
- if (diagnoseSubMismatchTypedef(FirstRecord, FirstModule, SecondModule,
- cast<TypedefNameDecl>(FirstDecl),
- cast<TypedefNameDecl>(SecondDecl),
- /*IsTypeAlias=*/false))
- return true;
- break;
- }
- case Var: {
- if (diagnoseSubMismatchVar(FirstRecord, FirstModule, SecondModule,
- cast<VarDecl>(FirstDecl),
- cast<VarDecl>(SecondDecl)))
- return true;
- break;
- }
- }
- Diag(FirstDecl->getLocation(),
- diag::err_module_odr_violation_mismatch_decl_unknown)
- << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType
- << FirstDecl->getSourceRange();
- Diag(SecondDecl->getLocation(),
- diag::note_module_odr_violation_mismatch_decl_unknown)
- << SecondModule.empty() << SecondModule << FirstDiffType
- << SecondDecl->getSourceRange();
- return true;
- }
- bool ODRDiagsEmitter::diagnoseMismatch(
- const FunctionDecl *FirstFunction,
- const FunctionDecl *SecondFunction) const {
- if (FirstFunction == SecondFunction)
- return false;
- // Keep in sync with select options in err_module_odr_violation_function.
- enum ODRFunctionDifference {
- ReturnType,
- ParameterName,
- ParameterType,
- ParameterSingleDefaultArgument,
- ParameterDifferentDefaultArgument,
- FunctionBody,
- };
- std::string FirstModule = getOwningModuleNameForDiagnostic(FirstFunction);
- std::string SecondModule = getOwningModuleNameForDiagnostic(SecondFunction);
- auto DiagError = [FirstFunction, &FirstModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRFunctionDifference DiffType) {
- return Diag(Loc, diag::err_module_odr_violation_function)
- << FirstFunction << FirstModule.empty() << FirstModule << Range
- << DiffType;
- };
- auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range,
- ODRFunctionDifference DiffType) {
- return Diag(Loc, diag::note_module_odr_violation_function)
- << SecondModule << Range << DiffType;
- };
- if (computeODRHash(FirstFunction->getReturnType()) !=
- computeODRHash(SecondFunction->getReturnType())) {
- DiagError(FirstFunction->getReturnTypeSourceRange().getBegin(),
- FirstFunction->getReturnTypeSourceRange(), ReturnType)
- << FirstFunction->getReturnType();
- DiagNote(SecondFunction->getReturnTypeSourceRange().getBegin(),
- SecondFunction->getReturnTypeSourceRange(), ReturnType)
- << SecondFunction->getReturnType();
- return true;
- }
- assert(FirstFunction->param_size() == SecondFunction->param_size() &&
- "Merged functions with different number of parameters");
- size_t ParamSize = FirstFunction->param_size();
- for (unsigned I = 0; I < ParamSize; ++I) {
- const ParmVarDecl *FirstParam = FirstFunction->getParamDecl(I);
- const ParmVarDecl *SecondParam = SecondFunction->getParamDecl(I);
- assert(Context.hasSameType(FirstParam->getType(), SecondParam->getType()) &&
- "Merged function has different parameter types.");
- if (FirstParam->getDeclName() != SecondParam->getDeclName()) {
- DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
- ParameterName)
- << I + 1 << FirstParam->getDeclName();
- DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
- ParameterName)
- << I + 1 << SecondParam->getDeclName();
- return true;
- };
- QualType FirstParamType = FirstParam->getType();
- QualType SecondParamType = SecondParam->getType();
- if (FirstParamType != SecondParamType &&
- computeODRHash(FirstParamType) != computeODRHash(SecondParamType)) {
- if (const DecayedType *ParamDecayedType =
- FirstParamType->getAs<DecayedType>()) {
- DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
- ParameterType)
- << (I + 1) << FirstParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
- ParameterType)
- << (I + 1) << FirstParamType << false;
- }
- if (const DecayedType *ParamDecayedType =
- SecondParamType->getAs<DecayedType>()) {
- DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
- ParameterType)
- << (I + 1) << SecondParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
- ParameterType)
- << (I + 1) << SecondParamType << false;
- }
- return true;
- }
- const Expr *FirstInit = FirstParam->getInit();
- const Expr *SecondInit = SecondParam->getInit();
- if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
- DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
- ParameterSingleDefaultArgument)
- << (I + 1) << (FirstInit == nullptr)
- << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
- DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
- ParameterSingleDefaultArgument)
- << (I + 1) << (SecondInit == nullptr)
- << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
- return true;
- }
- if (FirstInit && SecondInit &&
- computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
- DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
- ParameterDifferentDefaultArgument)
- << (I + 1) << FirstInit->getSourceRange();
- DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
- ParameterDifferentDefaultArgument)
- << (I + 1) << SecondInit->getSourceRange();
- return true;
- }
- assert(computeODRHash(FirstParam) == computeODRHash(SecondParam) &&
- "Undiagnosed parameter difference.");
- }
- // If no error has been generated before now, assume the problem is in
- // the body and generate a message.
- DiagError(FirstFunction->getLocation(), FirstFunction->getSourceRange(),
- FunctionBody);
- DiagNote(SecondFunction->getLocation(), SecondFunction->getSourceRange(),
- FunctionBody);
- return true;
- }
- bool ODRDiagsEmitter::diagnoseMismatch(const EnumDecl *FirstEnum,
- const EnumDecl *SecondEnum) const {
- if (FirstEnum == SecondEnum)
- return false;
- // Keep in sync with select options in err_module_odr_violation_enum.
- enum ODREnumDifference {
- SingleScopedEnum,
- EnumTagKeywordMismatch,
- SingleSpecifiedType,
- DifferentSpecifiedTypes,
- DifferentNumberEnumConstants,
- EnumConstantName,
- EnumConstantSingleInitializer,
- EnumConstantDifferentInitializer,
- };
- std::string FirstModule = getOwningModuleNameForDiagnostic(FirstEnum);
- std::string SecondModule = getOwningModuleNameForDiagnostic(SecondEnum);
- auto DiagError = [FirstEnum, &FirstModule, this](const auto *DiagAnchor,
- ODREnumDifference DiffType) {
- return Diag(DiagAnchor->getLocation(), diag::err_module_odr_violation_enum)
- << FirstEnum << FirstModule.empty() << FirstModule
- << DiagAnchor->getSourceRange() << DiffType;
- };
- auto DiagNote = [&SecondModule, this](const auto *DiagAnchor,
- ODREnumDifference DiffType) {
- return Diag(DiagAnchor->getLocation(), diag::note_module_odr_violation_enum)
- << SecondModule << DiagAnchor->getSourceRange() << DiffType;
- };
- if (FirstEnum->isScoped() != SecondEnum->isScoped()) {
- DiagError(FirstEnum, SingleScopedEnum) << FirstEnum->isScoped();
- DiagNote(SecondEnum, SingleScopedEnum) << SecondEnum->isScoped();
- return true;
- }
- if (FirstEnum->isScoped() && SecondEnum->isScoped()) {
- if (FirstEnum->isScopedUsingClassTag() !=
- SecondEnum->isScopedUsingClassTag()) {
- DiagError(FirstEnum, EnumTagKeywordMismatch)
- << FirstEnum->isScopedUsingClassTag();
- DiagNote(SecondEnum, EnumTagKeywordMismatch)
- << SecondEnum->isScopedUsingClassTag();
- return true;
- }
- }
- QualType FirstUnderlyingType =
- FirstEnum->getIntegerTypeSourceInfo()
- ? FirstEnum->getIntegerTypeSourceInfo()->getType()
- : QualType();
- QualType SecondUnderlyingType =
- SecondEnum->getIntegerTypeSourceInfo()
- ? SecondEnum->getIntegerTypeSourceInfo()->getType()
- : QualType();
- if (FirstUnderlyingType.isNull() != SecondUnderlyingType.isNull()) {
- DiagError(FirstEnum, SingleSpecifiedType) << !FirstUnderlyingType.isNull();
- DiagNote(SecondEnum, SingleSpecifiedType) << !SecondUnderlyingType.isNull();
- return true;
- }
- if (!FirstUnderlyingType.isNull() && !SecondUnderlyingType.isNull()) {
- if (computeODRHash(FirstUnderlyingType) !=
- computeODRHash(SecondUnderlyingType)) {
- DiagError(FirstEnum, DifferentSpecifiedTypes) << FirstUnderlyingType;
- DiagNote(SecondEnum, DifferentSpecifiedTypes) << SecondUnderlyingType;
- return true;
- }
- }
- // Compare enum constants.
- using DeclHashes =
- llvm::SmallVector<std::pair<const EnumConstantDecl *, unsigned>, 4>;
- auto PopulateHashes = [FirstEnum](DeclHashes &Hashes, const EnumDecl *Enum) {
- for (const Decl *D : Enum->decls()) {
- // Due to decl merging, the first EnumDecl is the parent of
- // Decls in both records.
- if (!ODRHash::isSubDeclToBeProcessed(D, FirstEnum))
- continue;
- assert(isa<EnumConstantDecl>(D) && "Unexpected Decl kind");
- Hashes.emplace_back(cast<EnumConstantDecl>(D), computeODRHash(D));
- }
- };
- DeclHashes FirstHashes;
- PopulateHashes(FirstHashes, FirstEnum);
- DeclHashes SecondHashes;
- PopulateHashes(SecondHashes, SecondEnum);
- if (FirstHashes.size() != SecondHashes.size()) {
- DiagError(FirstEnum, DifferentNumberEnumConstants)
- << (int)FirstHashes.size();
- DiagNote(SecondEnum, DifferentNumberEnumConstants)
- << (int)SecondHashes.size();
- return true;
- }
- for (unsigned I = 0, N = FirstHashes.size(); I < N; ++I) {
- if (FirstHashes[I].second == SecondHashes[I].second)
- continue;
- const EnumConstantDecl *FirstConstant = FirstHashes[I].first;
- const EnumConstantDecl *SecondConstant = SecondHashes[I].first;
- if (FirstConstant->getDeclName() != SecondConstant->getDeclName()) {
- DiagError(FirstConstant, EnumConstantName) << I + 1 << FirstConstant;
- DiagNote(SecondConstant, EnumConstantName) << I + 1 << SecondConstant;
- return true;
- }
- const Expr *FirstInit = FirstConstant->getInitExpr();
- const Expr *SecondInit = SecondConstant->getInitExpr();
- if (!FirstInit && !SecondInit)
- continue;
- if (!FirstInit || !SecondInit) {
- DiagError(FirstConstant, EnumConstantSingleInitializer)
- << I + 1 << FirstConstant << (FirstInit != nullptr);
- DiagNote(SecondConstant, EnumConstantSingleInitializer)
- << I + 1 << SecondConstant << (SecondInit != nullptr);
- return true;
- }
- if (computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
- DiagError(FirstConstant, EnumConstantDifferentInitializer)
- << I + 1 << FirstConstant;
- DiagNote(SecondConstant, EnumConstantDifferentInitializer)
- << I + 1 << SecondConstant;
- return true;
- }
- }
- return false;
- }
- bool ODRDiagsEmitter::diagnoseMismatch(
- const ObjCInterfaceDecl *FirstID, const ObjCInterfaceDecl *SecondID,
- const struct ObjCInterfaceDecl::DefinitionData *SecondDD) const {
- // Multiple different declarations got merged together; tell the user
- // where they came from.
- if (FirstID == SecondID)
- return false;
- std::string FirstModule = getOwningModuleNameForDiagnostic(FirstID);
- std::string SecondModule = getOwningModuleNameForDiagnostic(SecondID);
- // Keep in sync with err_module_odr_violation_objc_interface.
- enum ODRInterfaceDifference {
- SuperClassType,
- IVarAccess,
- };
- auto DiagError = [FirstID, &FirstModule,
- this](SourceLocation Loc, SourceRange Range,
- ODRInterfaceDifference DiffType) {
- return Diag(Loc, diag::err_module_odr_violation_objc_interface)
- << FirstID << FirstModule.empty() << FirstModule << Range
- << DiffType;
- };
- auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range,
- ODRInterfaceDifference DiffType) {
- return Diag(Loc, diag::note_module_odr_violation_objc_interface)
- << SecondModule.empty() << SecondModule << Range << DiffType;
- };
- const struct ObjCInterfaceDecl::DefinitionData *FirstDD = &FirstID->data();
- assert(FirstDD && SecondDD && "Definitions without DefinitionData");
- if (FirstDD != SecondDD) {
- // Check for matching super class.
- auto GetSuperClassSourceRange = [](const TypeSourceInfo *SuperInfo,
- const ObjCInterfaceDecl *ID) {
- if (!SuperInfo)
- return ID->getSourceRange();
- TypeLoc Loc = SuperInfo->getTypeLoc();
- return SourceRange(Loc.getBeginLoc(), Loc.getEndLoc());
- };
- ObjCInterfaceDecl *FirstSuperClass = FirstID->getSuperClass();
- ObjCInterfaceDecl *SecondSuperClass = nullptr;
- const TypeSourceInfo *FirstSuperInfo = FirstID->getSuperClassTInfo();
- const TypeSourceInfo *SecondSuperInfo = SecondDD->SuperClassTInfo;
- if (SecondSuperInfo)
- SecondSuperClass =
- SecondSuperInfo->getType()->castAs<ObjCObjectType>()->getInterface();
- if ((FirstSuperClass && SecondSuperClass &&
- FirstSuperClass->getODRHash() != SecondSuperClass->getODRHash()) ||
- (FirstSuperClass && !SecondSuperClass) ||
- (!FirstSuperClass && SecondSuperClass)) {
- QualType FirstType;
- if (FirstSuperInfo)
- FirstType = FirstSuperInfo->getType();
- DiagError(FirstID->getLocation(),
- GetSuperClassSourceRange(FirstSuperInfo, FirstID),
- SuperClassType)
- << (bool)FirstSuperInfo << FirstType;
- QualType SecondType;
- if (SecondSuperInfo)
- SecondType = SecondSuperInfo->getType();
- DiagNote(SecondID->getLocation(),
- GetSuperClassSourceRange(SecondSuperInfo, SecondID),
- SuperClassType)
- << (bool)SecondSuperInfo << SecondType;
- return true;
- }
- // Check both interfaces reference the same protocols.
- auto &FirstProtos = FirstID->getReferencedProtocols();
- auto &SecondProtos = SecondDD->ReferencedProtocols;
- if (diagnoseSubMismatchProtocols(FirstProtos, FirstID, FirstModule,
- SecondProtos, SecondID, SecondModule))
- return true;
- }
- auto PopulateHashes = [](DeclHashes &Hashes, const ObjCInterfaceDecl *ID,
- const DeclContext *DC) {
- for (auto *D : ID->decls()) {
- if (!ODRHash::isSubDeclToBeProcessed(D, DC))
- continue;
- Hashes.emplace_back(D, computeODRHash(D));
- }
- };
- DeclHashes FirstHashes;
- DeclHashes SecondHashes;
- // Use definition as DeclContext because definitions are merged when
- // DeclContexts are merged and separate when DeclContexts are separate.
- PopulateHashes(FirstHashes, FirstID, FirstID->getDefinition());
- PopulateHashes(SecondHashes, SecondID, SecondID->getDefinition());
- DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
- ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
- ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
- const Decl *FirstDecl = DR.FirstDecl;
- const Decl *SecondDecl = DR.SecondDecl;
- if (FirstDiffType == Other || SecondDiffType == Other) {
- diagnoseSubMismatchUnexpected(DR, FirstID, FirstModule, SecondID,
- SecondModule);
- return true;
- }
- if (FirstDiffType != SecondDiffType) {
- diagnoseSubMismatchDifferentDeclKinds(DR, FirstID, FirstModule, SecondID,
- SecondModule);
- return true;
- }
- assert(FirstDiffType == SecondDiffType);
- switch (FirstDiffType) {
- // Already handled.
- case EndOfClass:
- case Other:
- // Cannot be contained by ObjCInterfaceDecl, invalid in this context.
- case Field:
- case TypeDef:
- case Var:
- // C++ only, invalid in this context.
- case PublicSpecifer:
- case PrivateSpecifer:
- case ProtectedSpecifer:
- case StaticAssert:
- case CXXMethod:
- case TypeAlias:
- case Friend:
- case FunctionTemplate:
- llvm_unreachable("Invalid diff type");
- case ObjCMethod: {
- if (diagnoseSubMismatchObjCMethod(FirstID, FirstModule, SecondModule,
- cast<ObjCMethodDecl>(FirstDecl),
- cast<ObjCMethodDecl>(SecondDecl)))
- return true;
- break;
- }
- case ObjCIvar: {
- if (diagnoseSubMismatchField(FirstID, FirstModule, SecondModule,
- cast<FieldDecl>(FirstDecl),
- cast<FieldDecl>(SecondDecl)))
- return true;
- // Check if the access match.
- const ObjCIvarDecl *FirstIvar = cast<ObjCIvarDecl>(FirstDecl);
- const ObjCIvarDecl *SecondIvar = cast<ObjCIvarDecl>(SecondDecl);
- if (FirstIvar->getCanonicalAccessControl() !=
- SecondIvar->getCanonicalAccessControl()) {
- DiagError(FirstIvar->getLocation(), FirstIvar->getSourceRange(),
- IVarAccess)
- << FirstIvar->getName()
- << (int)FirstIvar->getCanonicalAccessControl();
- DiagNote(SecondIvar->getLocation(), SecondIvar->getSourceRange(),
- IVarAccess)
- << SecondIvar->getName()
- << (int)SecondIvar->getCanonicalAccessControl();
- return true;
- }
- break;
- }
- case ObjCProperty: {
- if (diagnoseSubMismatchObjCProperty(FirstID, FirstModule, SecondModule,
- cast<ObjCPropertyDecl>(FirstDecl),
- cast<ObjCPropertyDecl>(SecondDecl)))
- return true;
- break;
- }
- }
- Diag(FirstDecl->getLocation(),
- diag::err_module_odr_violation_mismatch_decl_unknown)
- << FirstID << FirstModule.empty() << FirstModule << FirstDiffType
- << FirstDecl->getSourceRange();
- Diag(SecondDecl->getLocation(),
- diag::note_module_odr_violation_mismatch_decl_unknown)
- << SecondModule << FirstDiffType << SecondDecl->getSourceRange();
- return true;
- }
- bool ODRDiagsEmitter::diagnoseMismatch(
- const ObjCProtocolDecl *FirstProtocol,
- const ObjCProtocolDecl *SecondProtocol,
- const struct ObjCProtocolDecl::DefinitionData *SecondDD) const {
- if (FirstProtocol == SecondProtocol)
- return false;
- std::string FirstModule = getOwningModuleNameForDiagnostic(FirstProtocol);
- std::string SecondModule = getOwningModuleNameForDiagnostic(SecondProtocol);
- const ObjCProtocolDecl::DefinitionData *FirstDD = &FirstProtocol->data();
- assert(FirstDD && SecondDD && "Definitions without DefinitionData");
- // Diagnostics from ObjCProtocol DefinitionData are emitted here.
- if (FirstDD != SecondDD) {
- // Check both protocols reference the same protocols.
- const ObjCProtocolList &FirstProtocols =
- FirstProtocol->getReferencedProtocols();
- const ObjCProtocolList &SecondProtocols = SecondDD->ReferencedProtocols;
- if (diagnoseSubMismatchProtocols(FirstProtocols, FirstProtocol, FirstModule,
- SecondProtocols, SecondProtocol,
- SecondModule))
- return true;
- }
- auto PopulateHashes = [](DeclHashes &Hashes, const ObjCProtocolDecl *ID,
- const DeclContext *DC) {
- for (const Decl *D : ID->decls()) {
- if (!ODRHash::isSubDeclToBeProcessed(D, DC))
- continue;
- Hashes.emplace_back(D, computeODRHash(D));
- }
- };
- DeclHashes FirstHashes;
- DeclHashes SecondHashes;
- // Use definition as DeclContext because definitions are merged when
- // DeclContexts are merged and separate when DeclContexts are separate.
- PopulateHashes(FirstHashes, FirstProtocol, FirstProtocol->getDefinition());
- PopulateHashes(SecondHashes, SecondProtocol, SecondProtocol->getDefinition());
- DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
- ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
- ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
- const Decl *FirstDecl = DR.FirstDecl;
- const Decl *SecondDecl = DR.SecondDecl;
- if (FirstDiffType == Other || SecondDiffType == Other) {
- diagnoseSubMismatchUnexpected(DR, FirstProtocol, FirstModule,
- SecondProtocol, SecondModule);
- return true;
- }
- if (FirstDiffType != SecondDiffType) {
- diagnoseSubMismatchDifferentDeclKinds(DR, FirstProtocol, FirstModule,
- SecondProtocol, SecondModule);
- return true;
- }
- assert(FirstDiffType == SecondDiffType);
- switch (FirstDiffType) {
- // Already handled.
- case EndOfClass:
- case Other:
- // Cannot be contained by ObjCProtocolDecl, invalid in this context.
- case Field:
- case TypeDef:
- case Var:
- case ObjCIvar:
- // C++ only, invalid in this context.
- case PublicSpecifer:
- case PrivateSpecifer:
- case ProtectedSpecifer:
- case StaticAssert:
- case CXXMethod:
- case TypeAlias:
- case Friend:
- case FunctionTemplate:
- llvm_unreachable("Invalid diff type");
- case ObjCMethod: {
- if (diagnoseSubMismatchObjCMethod(FirstProtocol, FirstModule, SecondModule,
- cast<ObjCMethodDecl>(FirstDecl),
- cast<ObjCMethodDecl>(SecondDecl)))
- return true;
- break;
- }
- case ObjCProperty: {
- if (diagnoseSubMismatchObjCProperty(FirstProtocol, FirstModule,
- SecondModule,
- cast<ObjCPropertyDecl>(FirstDecl),
- cast<ObjCPropertyDecl>(SecondDecl)))
- return true;
- break;
- }
- }
- Diag(FirstDecl->getLocation(),
- diag::err_module_odr_violation_mismatch_decl_unknown)
- << FirstProtocol << FirstModule.empty() << FirstModule << FirstDiffType
- << FirstDecl->getSourceRange();
- Diag(SecondDecl->getLocation(),
- diag::note_module_odr_violation_mismatch_decl_unknown)
- << SecondModule.empty() << SecondModule << FirstDiffType
- << SecondDecl->getSourceRange();
- return true;
- }
|