1 | //===-- ODRDiagsEmitter.cpp - Diagnostics for ODR mismatches ----*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "clang/AST/ODRDiagsEmitter.h" |
10 | #include "clang/AST/DeclFriend.h" |
11 | #include "clang/AST/DeclTemplate.h" |
12 | #include "clang/AST/ODRHash.h" |
13 | #include "clang/Basic/DiagnosticAST.h" |
14 | #include "clang/Basic/Module.h" |
15 | |
16 | using namespace clang; |
17 | |
18 | static unsigned computeODRHash(QualType Ty) { |
19 | ODRHash Hasher; |
20 | Hasher.AddQualType(T: Ty); |
21 | return Hasher.CalculateHash(); |
22 | } |
23 | |
24 | static unsigned computeODRHash(const Stmt *S) { |
25 | ODRHash Hasher; |
26 | Hasher.AddStmt(S); |
27 | return Hasher.CalculateHash(); |
28 | } |
29 | |
30 | static unsigned computeODRHash(const Decl *D) { |
31 | assert(D); |
32 | ODRHash Hasher; |
33 | Hasher.AddSubDecl(D); |
34 | return Hasher.CalculateHash(); |
35 | } |
36 | |
37 | static unsigned computeODRHash(const TemplateArgument &TA) { |
38 | ODRHash Hasher; |
39 | Hasher.AddTemplateArgument(TA); |
40 | return Hasher.CalculateHash(); |
41 | } |
42 | |
43 | std::string ODRDiagsEmitter::getOwningModuleNameForDiagnostic(const Decl *D) { |
44 | // If we know the owning module, use it. |
45 | if (Module *M = D->getImportedOwningModule()) |
46 | return M->getFullModuleName(); |
47 | |
48 | // Not from a module. |
49 | return {}; |
50 | } |
51 | |
52 | template <typename MethodT> |
53 | static bool diagnoseSubMismatchMethodParameters(DiagnosticsEngine &Diags, |
54 | const NamedDecl *FirstContainer, |
55 | StringRef FirstModule, |
56 | StringRef SecondModule, |
57 | const MethodT *FirstMethod, |
58 | const MethodT *SecondMethod) { |
59 | enum DiagMethodType { |
60 | DiagMethod, |
61 | DiagConstructor, |
62 | DiagDestructor, |
63 | }; |
64 | auto GetDiagMethodType = [](const NamedDecl *D) { |
65 | if (isa<CXXConstructorDecl>(Val: D)) |
66 | return DiagConstructor; |
67 | if (isa<CXXDestructorDecl>(Val: D)) |
68 | return DiagDestructor; |
69 | return DiagMethod; |
70 | }; |
71 | |
72 | enum ODRMethodParametersDifference { |
73 | NumberParameters, |
74 | ParameterType, |
75 | ParameterName, |
76 | }; |
77 | auto DiagError = [&Diags, &GetDiagMethodType, FirstContainer, FirstModule, |
78 | FirstMethod](ODRMethodParametersDifference DiffType) { |
79 | DeclarationName FirstName = FirstMethod->getDeclName(); |
80 | DiagMethodType FirstMethodType = GetDiagMethodType(FirstMethod); |
81 | return Diags.Report(FirstMethod->getLocation(), |
82 | diag::err_module_odr_violation_method_params) |
83 | << FirstContainer << FirstModule.empty() << FirstModule |
84 | << FirstMethod->getSourceRange() << DiffType << FirstMethodType |
85 | << FirstName; |
86 | }; |
87 | auto DiagNote = [&Diags, &GetDiagMethodType, SecondModule, |
88 | SecondMethod](ODRMethodParametersDifference DiffType) { |
89 | DeclarationName SecondName = SecondMethod->getDeclName(); |
90 | DiagMethodType SecondMethodType = GetDiagMethodType(SecondMethod); |
91 | return Diags.Report(SecondMethod->getLocation(), |
92 | diag::note_module_odr_violation_method_params) |
93 | << SecondModule.empty() << SecondModule |
94 | << SecondMethod->getSourceRange() << DiffType << SecondMethodType |
95 | << SecondName; |
96 | }; |
97 | |
98 | const unsigned FirstNumParameters = FirstMethod->param_size(); |
99 | const unsigned SecondNumParameters = SecondMethod->param_size(); |
100 | if (FirstNumParameters != SecondNumParameters) { |
101 | DiagError(NumberParameters) << FirstNumParameters; |
102 | DiagNote(NumberParameters) << SecondNumParameters; |
103 | return true; |
104 | } |
105 | |
106 | for (unsigned I = 0; I < FirstNumParameters; ++I) { |
107 | const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I); |
108 | const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I); |
109 | |
110 | QualType FirstParamType = FirstParam->getType(); |
111 | QualType SecondParamType = SecondParam->getType(); |
112 | if (FirstParamType != SecondParamType && |
113 | computeODRHash(Ty: FirstParamType) != computeODRHash(Ty: SecondParamType)) { |
114 | if (const DecayedType *ParamDecayedType = |
115 | FirstParamType->getAs<DecayedType>()) { |
116 | DiagError(ParameterType) << (I + 1) << FirstParamType << true |
117 | << ParamDecayedType->getOriginalType(); |
118 | } else { |
119 | DiagError(ParameterType) << (I + 1) << FirstParamType << false; |
120 | } |
121 | |
122 | if (const DecayedType *ParamDecayedType = |
123 | SecondParamType->getAs<DecayedType>()) { |
124 | DiagNote(ParameterType) << (I + 1) << SecondParamType << true |
125 | << ParamDecayedType->getOriginalType(); |
126 | } else { |
127 | DiagNote(ParameterType) << (I + 1) << SecondParamType << false; |
128 | } |
129 | return true; |
130 | } |
131 | |
132 | DeclarationName FirstParamName = FirstParam->getDeclName(); |
133 | DeclarationName SecondParamName = SecondParam->getDeclName(); |
134 | if (FirstParamName != SecondParamName) { |
135 | DiagError(ParameterName) << (I + 1) << FirstParamName; |
136 | DiagNote(ParameterName) << (I + 1) << SecondParamName; |
137 | return true; |
138 | } |
139 | } |
140 | |
141 | return false; |
142 | } |
143 | |
144 | bool ODRDiagsEmitter::diagnoseSubMismatchField( |
145 | const NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule, |
146 | const FieldDecl *FirstField, const FieldDecl *SecondField) const { |
147 | enum ODRFieldDifference { |
148 | FieldName, |
149 | FieldTypeName, |
150 | FieldSingleBitField, |
151 | FieldDifferentWidthBitField, |
152 | FieldSingleMutable, |
153 | FieldSingleInitializer, |
154 | FieldDifferentInitializers, |
155 | }; |
156 | |
157 | auto DiagError = [FirstRecord, FirstField, FirstModule, |
158 | this](ODRFieldDifference DiffType) { |
159 | return Diag(Loc: FirstField->getLocation(), DiagID: diag::err_module_odr_violation_field) |
160 | << FirstRecord << FirstModule.empty() << FirstModule |
161 | << FirstField->getSourceRange() << DiffType; |
162 | }; |
163 | auto DiagNote = [SecondField, SecondModule, |
164 | this](ODRFieldDifference DiffType) { |
165 | return Diag(Loc: SecondField->getLocation(), |
166 | DiagID: diag::note_module_odr_violation_field) |
167 | << SecondModule.empty() << SecondModule << SecondField->getSourceRange() << DiffType; |
168 | }; |
169 | |
170 | IdentifierInfo *FirstII = FirstField->getIdentifier(); |
171 | IdentifierInfo *SecondII = SecondField->getIdentifier(); |
172 | if (FirstII->getName() != SecondII->getName()) { |
173 | DiagError(FieldName) << FirstII; |
174 | DiagNote(FieldName) << SecondII; |
175 | return true; |
176 | } |
177 | |
178 | QualType FirstType = FirstField->getType(); |
179 | QualType SecondType = SecondField->getType(); |
180 | if (computeODRHash(Ty: FirstType) != computeODRHash(Ty: SecondType)) { |
181 | DiagError(FieldTypeName) << FirstII << FirstType; |
182 | DiagNote(FieldTypeName) << SecondII << SecondType; |
183 | return true; |
184 | } |
185 | |
186 | assert(Context.hasSameType(FirstField->getType(), SecondField->getType())); |
187 | (void)Context; |
188 | |
189 | const bool IsFirstBitField = FirstField->isBitField(); |
190 | const bool IsSecondBitField = SecondField->isBitField(); |
191 | if (IsFirstBitField != IsSecondBitField) { |
192 | DiagError(FieldSingleBitField) << FirstII << IsFirstBitField; |
193 | DiagNote(FieldSingleBitField) << SecondII << IsSecondBitField; |
194 | return true; |
195 | } |
196 | |
197 | if (IsFirstBitField && IsSecondBitField) { |
198 | unsigned FirstBitWidthHash = computeODRHash(S: FirstField->getBitWidth()); |
199 | unsigned SecondBitWidthHash = computeODRHash(S: SecondField->getBitWidth()); |
200 | if (FirstBitWidthHash != SecondBitWidthHash) { |
201 | DiagError(FieldDifferentWidthBitField) |
202 | << FirstII << FirstField->getBitWidth()->getSourceRange(); |
203 | DiagNote(FieldDifferentWidthBitField) |
204 | << SecondII << SecondField->getBitWidth()->getSourceRange(); |
205 | return true; |
206 | } |
207 | } |
208 | |
209 | if (!LangOpts.CPlusPlus) |
210 | return false; |
211 | |
212 | const bool IsFirstMutable = FirstField->isMutable(); |
213 | const bool IsSecondMutable = SecondField->isMutable(); |
214 | if (IsFirstMutable != IsSecondMutable) { |
215 | DiagError(FieldSingleMutable) << FirstII << IsFirstMutable; |
216 | DiagNote(FieldSingleMutable) << SecondII << IsSecondMutable; |
217 | return true; |
218 | } |
219 | |
220 | const Expr *FirstInitializer = FirstField->getInClassInitializer(); |
221 | const Expr *SecondInitializer = SecondField->getInClassInitializer(); |
222 | if ((!FirstInitializer && SecondInitializer) || |
223 | (FirstInitializer && !SecondInitializer)) { |
224 | DiagError(FieldSingleInitializer) |
225 | << FirstII << (FirstInitializer != nullptr); |
226 | DiagNote(FieldSingleInitializer) |
227 | << SecondII << (SecondInitializer != nullptr); |
228 | return true; |
229 | } |
230 | |
231 | if (FirstInitializer && SecondInitializer) { |
232 | unsigned FirstInitHash = computeODRHash(S: FirstInitializer); |
233 | unsigned SecondInitHash = computeODRHash(S: SecondInitializer); |
234 | if (FirstInitHash != SecondInitHash) { |
235 | DiagError(FieldDifferentInitializers) |
236 | << FirstII << FirstInitializer->getSourceRange(); |
237 | DiagNote(FieldDifferentInitializers) |
238 | << SecondII << SecondInitializer->getSourceRange(); |
239 | return true; |
240 | } |
241 | } |
242 | |
243 | return false; |
244 | } |
245 | |
246 | bool ODRDiagsEmitter::diagnoseSubMismatchTypedef( |
247 | const NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule, |
248 | const TypedefNameDecl *FirstTD, const TypedefNameDecl *SecondTD, |
249 | bool IsTypeAlias) const { |
250 | enum ODRTypedefDifference { |
251 | TypedefName, |
252 | TypedefType, |
253 | }; |
254 | |
255 | auto DiagError = [FirstRecord, FirstTD, FirstModule, |
256 | this](ODRTypedefDifference DiffType) { |
257 | return Diag(Loc: FirstTD->getLocation(), DiagID: diag::err_module_odr_violation_typedef) |
258 | << FirstRecord << FirstModule.empty() << FirstModule |
259 | << FirstTD->getSourceRange() << DiffType; |
260 | }; |
261 | auto DiagNote = [SecondTD, SecondModule, |
262 | this](ODRTypedefDifference DiffType) { |
263 | return Diag(Loc: SecondTD->getLocation(), |
264 | DiagID: diag::note_module_odr_violation_typedef) |
265 | << SecondModule << SecondTD->getSourceRange() << DiffType; |
266 | }; |
267 | |
268 | DeclarationName FirstName = FirstTD->getDeclName(); |
269 | DeclarationName SecondName = SecondTD->getDeclName(); |
270 | if (FirstName != SecondName) { |
271 | DiagError(TypedefName) << IsTypeAlias << FirstName; |
272 | DiagNote(TypedefName) << IsTypeAlias << SecondName; |
273 | return true; |
274 | } |
275 | |
276 | QualType FirstType = FirstTD->getUnderlyingType(); |
277 | QualType SecondType = SecondTD->getUnderlyingType(); |
278 | if (computeODRHash(Ty: FirstType) != computeODRHash(Ty: SecondType)) { |
279 | DiagError(TypedefType) << IsTypeAlias << FirstName << FirstType; |
280 | DiagNote(TypedefType) << IsTypeAlias << SecondName << SecondType; |
281 | return true; |
282 | } |
283 | return false; |
284 | } |
285 | |
286 | bool ODRDiagsEmitter::diagnoseSubMismatchVar(const NamedDecl *FirstRecord, |
287 | StringRef FirstModule, |
288 | StringRef SecondModule, |
289 | const VarDecl *FirstVD, |
290 | const VarDecl *SecondVD) const { |
291 | enum ODRVarDifference { |
292 | VarName, |
293 | VarType, |
294 | VarSingleInitializer, |
295 | VarDifferentInitializer, |
296 | VarConstexpr, |
297 | }; |
298 | |
299 | auto DiagError = [FirstRecord, FirstVD, FirstModule, |
300 | this](ODRVarDifference DiffType) { |
301 | return Diag(Loc: FirstVD->getLocation(), DiagID: diag::err_module_odr_violation_variable) |
302 | << FirstRecord << FirstModule.empty() << FirstModule |
303 | << FirstVD->getSourceRange() << DiffType; |
304 | }; |
305 | auto DiagNote = [SecondVD, SecondModule, this](ODRVarDifference DiffType) { |
306 | return Diag(Loc: SecondVD->getLocation(), |
307 | DiagID: diag::note_module_odr_violation_variable) |
308 | << SecondModule << SecondVD->getSourceRange() << DiffType; |
309 | }; |
310 | |
311 | DeclarationName FirstName = FirstVD->getDeclName(); |
312 | DeclarationName SecondName = SecondVD->getDeclName(); |
313 | if (FirstName != SecondName) { |
314 | DiagError(VarName) << FirstName; |
315 | DiagNote(VarName) << SecondName; |
316 | return true; |
317 | } |
318 | |
319 | QualType FirstType = FirstVD->getType(); |
320 | QualType SecondType = SecondVD->getType(); |
321 | if (computeODRHash(Ty: FirstType) != computeODRHash(Ty: SecondType)) { |
322 | DiagError(VarType) << FirstName << FirstType; |
323 | DiagNote(VarType) << SecondName << SecondType; |
324 | return true; |
325 | } |
326 | |
327 | if (!LangOpts.CPlusPlus) |
328 | return false; |
329 | |
330 | const Expr *FirstInit = FirstVD->getInit(); |
331 | const Expr *SecondInit = SecondVD->getInit(); |
332 | if ((FirstInit == nullptr) != (SecondInit == nullptr)) { |
333 | DiagError(VarSingleInitializer) |
334 | << FirstName << (FirstInit == nullptr) |
335 | << (FirstInit ? FirstInit->getSourceRange() : SourceRange()); |
336 | DiagNote(VarSingleInitializer) |
337 | << SecondName << (SecondInit == nullptr) |
338 | << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); |
339 | return true; |
340 | } |
341 | |
342 | if (FirstInit && SecondInit && |
343 | computeODRHash(S: FirstInit) != computeODRHash(S: SecondInit)) { |
344 | DiagError(VarDifferentInitializer) |
345 | << FirstName << FirstInit->getSourceRange(); |
346 | DiagNote(VarDifferentInitializer) |
347 | << SecondName << SecondInit->getSourceRange(); |
348 | return true; |
349 | } |
350 | |
351 | const bool FirstIsConstexpr = FirstVD->isConstexpr(); |
352 | const bool SecondIsConstexpr = SecondVD->isConstexpr(); |
353 | if (FirstIsConstexpr != SecondIsConstexpr) { |
354 | DiagError(VarConstexpr) << FirstName << FirstIsConstexpr; |
355 | DiagNote(VarConstexpr) << SecondName << SecondIsConstexpr; |
356 | return true; |
357 | } |
358 | return false; |
359 | } |
360 | |
361 | bool ODRDiagsEmitter::diagnoseSubMismatchProtocols( |
362 | const ObjCProtocolList &FirstProtocols, |
363 | const ObjCContainerDecl *FirstContainer, StringRef FirstModule, |
364 | const ObjCProtocolList &SecondProtocols, |
365 | const ObjCContainerDecl *SecondContainer, StringRef SecondModule) const { |
366 | // Keep in sync with err_module_odr_violation_referenced_protocols. |
367 | enum ODRReferencedProtocolDifference { |
368 | NumProtocols, |
369 | ProtocolType, |
370 | }; |
371 | auto DiagRefProtocolError = [FirstContainer, FirstModule, |
372 | this](SourceLocation Loc, SourceRange Range, |
373 | ODRReferencedProtocolDifference DiffType) { |
374 | return Diag(Loc, DiagID: diag::err_module_odr_violation_referenced_protocols) |
375 | << FirstContainer << FirstModule.empty() << FirstModule << Range |
376 | << DiffType; |
377 | }; |
378 | auto DiagRefProtocolNote = [SecondModule, |
379 | this](SourceLocation Loc, SourceRange Range, |
380 | ODRReferencedProtocolDifference DiffType) { |
381 | return Diag(Loc, DiagID: diag::note_module_odr_violation_referenced_protocols) |
382 | << SecondModule.empty() << SecondModule << Range << DiffType; |
383 | }; |
384 | auto GetProtoListSourceRange = [](const ObjCProtocolList &PL) { |
385 | if (PL.empty()) |
386 | return SourceRange(); |
387 | return SourceRange(*PL.loc_begin(), *std::prev(x: PL.loc_end())); |
388 | }; |
389 | |
390 | if (FirstProtocols.size() != SecondProtocols.size()) { |
391 | DiagRefProtocolError(FirstContainer->getLocation(), |
392 | GetProtoListSourceRange(FirstProtocols), NumProtocols) |
393 | << FirstProtocols.size(); |
394 | DiagRefProtocolNote(SecondContainer->getLocation(), |
395 | GetProtoListSourceRange(SecondProtocols), NumProtocols) |
396 | << SecondProtocols.size(); |
397 | return true; |
398 | } |
399 | |
400 | for (unsigned I = 0, E = FirstProtocols.size(); I != E; ++I) { |
401 | const ObjCProtocolDecl *FirstProtocol = FirstProtocols[I]; |
402 | const ObjCProtocolDecl *SecondProtocol = SecondProtocols[I]; |
403 | DeclarationName FirstProtocolName = FirstProtocol->getDeclName(); |
404 | DeclarationName SecondProtocolName = SecondProtocol->getDeclName(); |
405 | if (FirstProtocolName != SecondProtocolName) { |
406 | SourceLocation FirstLoc = *(FirstProtocols.loc_begin() + I); |
407 | SourceLocation SecondLoc = *(SecondProtocols.loc_begin() + I); |
408 | SourceRange EmptyRange; |
409 | DiagRefProtocolError(FirstLoc, EmptyRange, ProtocolType) |
410 | << (I + 1) << FirstProtocolName; |
411 | DiagRefProtocolNote(SecondLoc, EmptyRange, ProtocolType) |
412 | << (I + 1) << SecondProtocolName; |
413 | return true; |
414 | } |
415 | } |
416 | |
417 | return false; |
418 | } |
419 | |
420 | bool ODRDiagsEmitter::diagnoseSubMismatchObjCMethod( |
421 | const NamedDecl *FirstObjCContainer, StringRef FirstModule, |
422 | StringRef SecondModule, const ObjCMethodDecl *FirstMethod, |
423 | const ObjCMethodDecl *SecondMethod) const { |
424 | enum ODRMethodDifference { |
425 | ReturnType, |
426 | InstanceOrClass, |
427 | ControlLevel, // optional/required |
428 | DesignatedInitializer, |
429 | Directness, |
430 | Name, |
431 | }; |
432 | |
433 | auto DiagError = [FirstObjCContainer, FirstModule, FirstMethod, |
434 | this](ODRMethodDifference DiffType) { |
435 | return Diag(Loc: FirstMethod->getLocation(), |
436 | DiagID: diag::err_module_odr_violation_objc_method) |
437 | << FirstObjCContainer << FirstModule.empty() << FirstModule |
438 | << FirstMethod->getSourceRange() << DiffType; |
439 | }; |
440 | auto DiagNote = [SecondModule, SecondMethod, |
441 | this](ODRMethodDifference DiffType) { |
442 | return Diag(Loc: SecondMethod->getLocation(), |
443 | DiagID: diag::note_module_odr_violation_objc_method) |
444 | << SecondModule.empty() << SecondModule |
445 | << SecondMethod->getSourceRange() << DiffType; |
446 | }; |
447 | |
448 | if (computeODRHash(Ty: FirstMethod->getReturnType()) != |
449 | computeODRHash(Ty: SecondMethod->getReturnType())) { |
450 | DiagError(ReturnType) << FirstMethod << FirstMethod->getReturnType(); |
451 | DiagNote(ReturnType) << SecondMethod << SecondMethod->getReturnType(); |
452 | return true; |
453 | } |
454 | |
455 | if (FirstMethod->isInstanceMethod() != SecondMethod->isInstanceMethod()) { |
456 | DiagError(InstanceOrClass) |
457 | << FirstMethod << FirstMethod->isInstanceMethod(); |
458 | DiagNote(InstanceOrClass) |
459 | << SecondMethod << SecondMethod->isInstanceMethod(); |
460 | return true; |
461 | } |
462 | if (FirstMethod->getImplementationControl() != |
463 | SecondMethod->getImplementationControl()) { |
464 | DiagError(ControlLevel) |
465 | << llvm::to_underlying(E: FirstMethod->getImplementationControl()); |
466 | DiagNote(ControlLevel) << llvm::to_underlying( |
467 | E: SecondMethod->getImplementationControl()); |
468 | return true; |
469 | } |
470 | if (FirstMethod->isThisDeclarationADesignatedInitializer() != |
471 | SecondMethod->isThisDeclarationADesignatedInitializer()) { |
472 | DiagError(DesignatedInitializer) |
473 | << FirstMethod |
474 | << FirstMethod->isThisDeclarationADesignatedInitializer(); |
475 | DiagNote(DesignatedInitializer) |
476 | << SecondMethod |
477 | << SecondMethod->isThisDeclarationADesignatedInitializer(); |
478 | return true; |
479 | } |
480 | if (FirstMethod->isDirectMethod() != SecondMethod->isDirectMethod()) { |
481 | DiagError(Directness) << FirstMethod << FirstMethod->isDirectMethod(); |
482 | DiagNote(Directness) << SecondMethod << SecondMethod->isDirectMethod(); |
483 | return true; |
484 | } |
485 | if (diagnoseSubMismatchMethodParameters(Diags, FirstContainer: FirstObjCContainer, |
486 | FirstModule, SecondModule, |
487 | FirstMethod, SecondMethod)) |
488 | return true; |
489 | |
490 | // Check method name *after* looking at the parameters otherwise we get a |
491 | // less ideal diagnostics: a ObjCMethodName mismatch given that selectors |
492 | // for different parameters are likely to be different. |
493 | DeclarationName FirstName = FirstMethod->getDeclName(); |
494 | DeclarationName SecondName = SecondMethod->getDeclName(); |
495 | if (FirstName != SecondName) { |
496 | DiagError(Name) << FirstName; |
497 | DiagNote(Name) << SecondName; |
498 | return true; |
499 | } |
500 | |
501 | return false; |
502 | } |
503 | |
504 | bool ODRDiagsEmitter::diagnoseSubMismatchObjCProperty( |
505 | const NamedDecl *FirstObjCContainer, StringRef FirstModule, |
506 | StringRef SecondModule, const ObjCPropertyDecl *FirstProp, |
507 | const ObjCPropertyDecl *SecondProp) const { |
508 | enum ODRPropertyDifference { |
509 | Name, |
510 | Type, |
511 | ControlLevel, // optional/required |
512 | Attribute, |
513 | }; |
514 | |
515 | auto DiagError = [FirstObjCContainer, FirstModule, FirstProp, |
516 | this](SourceLocation Loc, ODRPropertyDifference DiffType) { |
517 | return Diag(Loc, DiagID: diag::err_module_odr_violation_objc_property) |
518 | << FirstObjCContainer << FirstModule.empty() << FirstModule |
519 | << FirstProp->getSourceRange() << DiffType; |
520 | }; |
521 | auto DiagNote = [SecondModule, SecondProp, |
522 | this](SourceLocation Loc, ODRPropertyDifference DiffType) { |
523 | return Diag(Loc, DiagID: diag::note_module_odr_violation_objc_property) |
524 | << SecondModule.empty() << SecondModule |
525 | << SecondProp->getSourceRange() << DiffType; |
526 | }; |
527 | |
528 | IdentifierInfo *FirstII = FirstProp->getIdentifier(); |
529 | IdentifierInfo *SecondII = SecondProp->getIdentifier(); |
530 | if (FirstII->getName() != SecondII->getName()) { |
531 | DiagError(FirstProp->getLocation(), Name) << FirstII; |
532 | DiagNote(SecondProp->getLocation(), Name) << SecondII; |
533 | return true; |
534 | } |
535 | if (computeODRHash(Ty: FirstProp->getType()) != |
536 | computeODRHash(Ty: SecondProp->getType())) { |
537 | DiagError(FirstProp->getLocation(), Type) |
538 | << FirstII << FirstProp->getType(); |
539 | DiagNote(SecondProp->getLocation(), Type) |
540 | << SecondII << SecondProp->getType(); |
541 | return true; |
542 | } |
543 | if (FirstProp->getPropertyImplementation() != |
544 | SecondProp->getPropertyImplementation()) { |
545 | DiagError(FirstProp->getLocation(), ControlLevel) |
546 | << FirstProp->getPropertyImplementation(); |
547 | DiagNote(SecondProp->getLocation(), ControlLevel) |
548 | << SecondProp->getPropertyImplementation(); |
549 | return true; |
550 | } |
551 | |
552 | // Go over the property attributes and stop at the first mismatch. |
553 | unsigned FirstAttrs = (unsigned)FirstProp->getPropertyAttributes(); |
554 | unsigned SecondAttrs = (unsigned)SecondProp->getPropertyAttributes(); |
555 | if (FirstAttrs != SecondAttrs) { |
556 | for (unsigned I = 0; I < NumObjCPropertyAttrsBits; ++I) { |
557 | unsigned CheckedAttr = (1 << I); |
558 | if ((FirstAttrs & CheckedAttr) == (SecondAttrs & CheckedAttr)) |
559 | continue; |
560 | |
561 | bool IsFirstWritten = |
562 | (unsigned)FirstProp->getPropertyAttributesAsWritten() & CheckedAttr; |
563 | bool IsSecondWritten = |
564 | (unsigned)SecondProp->getPropertyAttributesAsWritten() & CheckedAttr; |
565 | DiagError(IsFirstWritten ? FirstProp->getLParenLoc() |
566 | : FirstProp->getLocation(), |
567 | Attribute) |
568 | << FirstII << (I + 1) << IsFirstWritten; |
569 | DiagNote(IsSecondWritten ? SecondProp->getLParenLoc() |
570 | : SecondProp->getLocation(), |
571 | Attribute) |
572 | << SecondII << (I + 1); |
573 | return true; |
574 | } |
575 | } |
576 | |
577 | return false; |
578 | } |
579 | |
580 | ODRDiagsEmitter::DiffResult |
581 | ODRDiagsEmitter::FindTypeDiffs(DeclHashes &FirstHashes, |
582 | DeclHashes &SecondHashes) { |
583 | auto DifferenceSelector = [](const Decl *D) { |
584 | assert(D && "valid Decl required" ); |
585 | switch (D->getKind()) { |
586 | default: |
587 | return Other; |
588 | case Decl::AccessSpec: |
589 | switch (D->getAccess()) { |
590 | case AS_public: |
591 | return PublicSpecifer; |
592 | case AS_private: |
593 | return PrivateSpecifer; |
594 | case AS_protected: |
595 | return ProtectedSpecifer; |
596 | case AS_none: |
597 | break; |
598 | } |
599 | llvm_unreachable("Invalid access specifier" ); |
600 | case Decl::StaticAssert: |
601 | return StaticAssert; |
602 | case Decl::Field: |
603 | return Field; |
604 | case Decl::CXXMethod: |
605 | case Decl::CXXConstructor: |
606 | case Decl::CXXDestructor: |
607 | return CXXMethod; |
608 | case Decl::TypeAlias: |
609 | return TypeAlias; |
610 | case Decl::Typedef: |
611 | return TypeDef; |
612 | case Decl::Var: |
613 | return Var; |
614 | case Decl::Friend: |
615 | return Friend; |
616 | case Decl::FunctionTemplate: |
617 | return FunctionTemplate; |
618 | case Decl::ObjCMethod: |
619 | return ObjCMethod; |
620 | case Decl::ObjCIvar: |
621 | return ObjCIvar; |
622 | case Decl::ObjCProperty: |
623 | return ObjCProperty; |
624 | } |
625 | }; |
626 | |
627 | DiffResult DR; |
628 | auto FirstIt = FirstHashes.begin(); |
629 | auto SecondIt = SecondHashes.begin(); |
630 | while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) { |
631 | if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() && |
632 | FirstIt->second == SecondIt->second) { |
633 | ++FirstIt; |
634 | ++SecondIt; |
635 | continue; |
636 | } |
637 | |
638 | DR.FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first; |
639 | DR.SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first; |
640 | |
641 | DR.FirstDiffType = |
642 | DR.FirstDecl ? DifferenceSelector(DR.FirstDecl) : EndOfClass; |
643 | DR.SecondDiffType = |
644 | DR.SecondDecl ? DifferenceSelector(DR.SecondDecl) : EndOfClass; |
645 | return DR; |
646 | } |
647 | return DR; |
648 | } |
649 | |
650 | void ODRDiagsEmitter::diagnoseSubMismatchUnexpected( |
651 | DiffResult &DR, const NamedDecl *FirstRecord, StringRef FirstModule, |
652 | const NamedDecl *SecondRecord, StringRef SecondModule) const { |
653 | Diag(Loc: FirstRecord->getLocation(), |
654 | DiagID: diag::err_module_odr_violation_different_definitions) |
655 | << FirstRecord << FirstModule.empty() << FirstModule; |
656 | |
657 | if (DR.FirstDecl) { |
658 | Diag(Loc: DR.FirstDecl->getLocation(), DiagID: diag::note_first_module_difference) |
659 | << FirstRecord << DR.FirstDecl->getSourceRange(); |
660 | } |
661 | |
662 | Diag(Loc: SecondRecord->getLocation(), |
663 | DiagID: diag::note_module_odr_violation_different_definitions) |
664 | << SecondModule; |
665 | |
666 | if (DR.SecondDecl) { |
667 | Diag(Loc: DR.SecondDecl->getLocation(), DiagID: diag::note_second_module_difference) |
668 | << DR.SecondDecl->getSourceRange(); |
669 | } |
670 | } |
671 | |
672 | void ODRDiagsEmitter::diagnoseSubMismatchDifferentDeclKinds( |
673 | DiffResult &DR, const NamedDecl *FirstRecord, StringRef FirstModule, |
674 | const NamedDecl *SecondRecord, StringRef SecondModule) const { |
675 | auto GetMismatchedDeclLoc = [](const NamedDecl *Container, |
676 | ODRMismatchDecl DiffType, const Decl *D) { |
677 | SourceLocation Loc; |
678 | SourceRange Range; |
679 | if (DiffType == EndOfClass) { |
680 | if (auto *Tag = dyn_cast<TagDecl>(Val: Container)) |
681 | Loc = Tag->getBraceRange().getEnd(); |
682 | else if (auto *IF = dyn_cast<ObjCInterfaceDecl>(Val: Container)) |
683 | Loc = IF->getAtEndRange().getBegin(); |
684 | else |
685 | Loc = Container->getEndLoc(); |
686 | } else { |
687 | Loc = D->getLocation(); |
688 | Range = D->getSourceRange(); |
689 | } |
690 | return std::make_pair(x&: Loc, y&: Range); |
691 | }; |
692 | |
693 | auto FirstDiagInfo = |
694 | GetMismatchedDeclLoc(FirstRecord, DR.FirstDiffType, DR.FirstDecl); |
695 | Diag(Loc: FirstDiagInfo.first, DiagID: diag::err_module_odr_violation_mismatch_decl) |
696 | << FirstRecord << FirstModule.empty() << FirstModule |
697 | << FirstDiagInfo.second << DR.FirstDiffType; |
698 | |
699 | auto SecondDiagInfo = |
700 | GetMismatchedDeclLoc(SecondRecord, DR.SecondDiffType, DR.SecondDecl); |
701 | Diag(Loc: SecondDiagInfo.first, DiagID: diag::note_module_odr_violation_mismatch_decl) |
702 | << SecondModule.empty() << SecondModule << SecondDiagInfo.second |
703 | << DR.SecondDiffType; |
704 | } |
705 | |
706 | bool ODRDiagsEmitter::diagnoseMismatch( |
707 | const CXXRecordDecl *FirstRecord, const CXXRecordDecl *SecondRecord, |
708 | const struct CXXRecordDecl::DefinitionData *SecondDD) const { |
709 | // Multiple different declarations got merged together; tell the user |
710 | // where they came from. |
711 | if (FirstRecord == SecondRecord) |
712 | return false; |
713 | |
714 | std::string FirstModule = getOwningModuleNameForDiagnostic(D: FirstRecord); |
715 | std::string SecondModule = getOwningModuleNameForDiagnostic(D: SecondRecord); |
716 | |
717 | const struct CXXRecordDecl::DefinitionData *FirstDD = |
718 | FirstRecord->DefinitionData; |
719 | assert(FirstDD && SecondDD && "Definitions without DefinitionData" ); |
720 | |
721 | // Diagnostics from DefinitionData are emitted here. |
722 | if (FirstDD != SecondDD) { |
723 | // Keep in sync with err_module_odr_violation_definition_data. |
724 | enum ODRDefinitionDataDifference { |
725 | NumBases, |
726 | NumVBases, |
727 | BaseType, |
728 | BaseVirtual, |
729 | BaseAccess, |
730 | }; |
731 | auto DiagBaseError = [FirstRecord, &FirstModule, |
732 | this](SourceLocation Loc, SourceRange Range, |
733 | ODRDefinitionDataDifference DiffType) { |
734 | return Diag(Loc, DiagID: diag::err_module_odr_violation_definition_data) |
735 | << FirstRecord << FirstModule.empty() << FirstModule << Range |
736 | << DiffType; |
737 | }; |
738 | auto DiagBaseNote = [&SecondModule, |
739 | this](SourceLocation Loc, SourceRange Range, |
740 | ODRDefinitionDataDifference DiffType) { |
741 | return Diag(Loc, DiagID: diag::note_module_odr_violation_definition_data) |
742 | << SecondModule << Range << DiffType; |
743 | }; |
744 | auto GetSourceRange = [](const struct CXXRecordDecl::DefinitionData *DD) { |
745 | unsigned NumBases = DD->NumBases; |
746 | if (NumBases == 0) |
747 | return SourceRange(); |
748 | ArrayRef<CXXBaseSpecifier> bases = DD->bases(); |
749 | return SourceRange(bases[0].getBeginLoc(), |
750 | bases[NumBases - 1].getEndLoc()); |
751 | }; |
752 | |
753 | unsigned FirstNumBases = FirstDD->NumBases; |
754 | unsigned FirstNumVBases = FirstDD->NumVBases; |
755 | unsigned SecondNumBases = SecondDD->NumBases; |
756 | unsigned SecondNumVBases = SecondDD->NumVBases; |
757 | if (FirstNumBases != SecondNumBases) { |
758 | DiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD), |
759 | NumBases) |
760 | << FirstNumBases; |
761 | DiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD), |
762 | NumBases) |
763 | << SecondNumBases; |
764 | return true; |
765 | } |
766 | |
767 | if (FirstNumVBases != SecondNumVBases) { |
768 | DiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD), |
769 | NumVBases) |
770 | << FirstNumVBases; |
771 | DiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD), |
772 | NumVBases) |
773 | << SecondNumVBases; |
774 | return true; |
775 | } |
776 | |
777 | ArrayRef<CXXBaseSpecifier> FirstBases = FirstDD->bases(); |
778 | ArrayRef<CXXBaseSpecifier> SecondBases = SecondDD->bases(); |
779 | for (unsigned I = 0; I < FirstNumBases; ++I) { |
780 | const CXXBaseSpecifier FirstBase = FirstBases[I]; |
781 | const CXXBaseSpecifier SecondBase = SecondBases[I]; |
782 | if (computeODRHash(Ty: FirstBase.getType()) != |
783 | computeODRHash(Ty: SecondBase.getType())) { |
784 | DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(), |
785 | BaseType) |
786 | << (I + 1) << FirstBase.getType(); |
787 | DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(), |
788 | BaseType) |
789 | << (I + 1) << SecondBase.getType(); |
790 | return true; |
791 | } |
792 | |
793 | if (FirstBase.isVirtual() != SecondBase.isVirtual()) { |
794 | DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(), |
795 | BaseVirtual) |
796 | << (I + 1) << FirstBase.isVirtual() << FirstBase.getType(); |
797 | DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(), |
798 | BaseVirtual) |
799 | << (I + 1) << SecondBase.isVirtual() << SecondBase.getType(); |
800 | return true; |
801 | } |
802 | |
803 | if (FirstBase.getAccessSpecifierAsWritten() != |
804 | SecondBase.getAccessSpecifierAsWritten()) { |
805 | DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(), |
806 | BaseAccess) |
807 | << (I + 1) << FirstBase.getType() |
808 | << (int)FirstBase.getAccessSpecifierAsWritten(); |
809 | DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(), |
810 | BaseAccess) |
811 | << (I + 1) << SecondBase.getType() |
812 | << (int)SecondBase.getAccessSpecifierAsWritten(); |
813 | return true; |
814 | } |
815 | } |
816 | } |
817 | |
818 | const ClassTemplateDecl *FirstTemplate = |
819 | FirstRecord->getDescribedClassTemplate(); |
820 | const ClassTemplateDecl *SecondTemplate = |
821 | SecondRecord->getDescribedClassTemplate(); |
822 | |
823 | assert(!FirstTemplate == !SecondTemplate && |
824 | "Both pointers should be null or non-null" ); |
825 | |
826 | if (FirstTemplate && SecondTemplate) { |
827 | ArrayRef<const NamedDecl *> FirstTemplateParams = |
828 | FirstTemplate->getTemplateParameters()->asArray(); |
829 | ArrayRef<const NamedDecl *> SecondTemplateParams = |
830 | SecondTemplate->getTemplateParameters()->asArray(); |
831 | assert(FirstTemplateParams.size() == SecondTemplateParams.size() && |
832 | "Number of template parameters should be equal." ); |
833 | for (auto Pair : llvm::zip(t&: FirstTemplateParams, u&: SecondTemplateParams)) { |
834 | const NamedDecl *FirstDecl = std::get<0>(t&: Pair); |
835 | const NamedDecl *SecondDecl = std::get<1>(t&: Pair); |
836 | if (computeODRHash(D: FirstDecl) == computeODRHash(D: SecondDecl)) |
837 | continue; |
838 | |
839 | assert(FirstDecl->getKind() == SecondDecl->getKind() && |
840 | "Parameter Decl's should be the same kind." ); |
841 | |
842 | enum ODRTemplateDifference { |
843 | ParamEmptyName, |
844 | ParamName, |
845 | ParamSingleDefaultArgument, |
846 | ParamDifferentDefaultArgument, |
847 | }; |
848 | |
849 | auto hasDefaultArg = [](const NamedDecl *D) { |
850 | if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Val: D)) |
851 | return TTP->hasDefaultArgument() && |
852 | !TTP->defaultArgumentWasInherited(); |
853 | if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Val: D)) |
854 | return NTTP->hasDefaultArgument() && |
855 | !NTTP->defaultArgumentWasInherited(); |
856 | auto *TTP = cast<TemplateTemplateParmDecl>(Val: D); |
857 | return TTP->hasDefaultArgument() && !TTP->defaultArgumentWasInherited(); |
858 | }; |
859 | bool hasFirstArg = hasDefaultArg(FirstDecl); |
860 | bool hasSecondArg = hasDefaultArg(SecondDecl); |
861 | |
862 | ODRTemplateDifference ErrDiffType; |
863 | ODRTemplateDifference NoteDiffType; |
864 | |
865 | DeclarationName FirstName = FirstDecl->getDeclName(); |
866 | DeclarationName SecondName = SecondDecl->getDeclName(); |
867 | |
868 | if (FirstName != SecondName) { |
869 | bool FirstNameEmpty = |
870 | FirstName.isIdentifier() && !FirstName.getAsIdentifierInfo(); |
871 | bool SecondNameEmpty = |
872 | SecondName.isIdentifier() && !SecondName.getAsIdentifierInfo(); |
873 | ErrDiffType = FirstNameEmpty ? ParamEmptyName : ParamName; |
874 | NoteDiffType = SecondNameEmpty ? ParamEmptyName : ParamName; |
875 | } else if (hasFirstArg == hasSecondArg) |
876 | ErrDiffType = NoteDiffType = ParamDifferentDefaultArgument; |
877 | else |
878 | ErrDiffType = NoteDiffType = ParamSingleDefaultArgument; |
879 | |
880 | Diag(Loc: FirstDecl->getLocation(), |
881 | DiagID: diag::err_module_odr_violation_template_parameter) |
882 | << FirstRecord << FirstModule.empty() << FirstModule |
883 | << FirstDecl->getSourceRange() << ErrDiffType << hasFirstArg |
884 | << FirstName; |
885 | Diag(Loc: SecondDecl->getLocation(), |
886 | DiagID: diag::note_module_odr_violation_template_parameter) |
887 | << SecondModule << SecondDecl->getSourceRange() << NoteDiffType |
888 | << hasSecondArg << SecondName; |
889 | return true; |
890 | } |
891 | } |
892 | |
893 | auto PopulateHashes = [](DeclHashes &Hashes, const RecordDecl *Record, |
894 | const DeclContext *DC) { |
895 | for (const Decl *D : Record->decls()) { |
896 | if (!ODRHash::isSubDeclToBeProcessed(D, Parent: DC)) |
897 | continue; |
898 | Hashes.emplace_back(Args&: D, Args: computeODRHash(D)); |
899 | } |
900 | }; |
901 | |
902 | DeclHashes FirstHashes; |
903 | DeclHashes SecondHashes; |
904 | const DeclContext *DC = FirstRecord; |
905 | PopulateHashes(FirstHashes, FirstRecord, DC); |
906 | PopulateHashes(SecondHashes, SecondRecord, DC); |
907 | |
908 | DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes); |
909 | ODRMismatchDecl FirstDiffType = DR.FirstDiffType; |
910 | ODRMismatchDecl SecondDiffType = DR.SecondDiffType; |
911 | const Decl *FirstDecl = DR.FirstDecl; |
912 | const Decl *SecondDecl = DR.SecondDecl; |
913 | |
914 | if (FirstDiffType == Other || SecondDiffType == Other) { |
915 | diagnoseSubMismatchUnexpected(DR, FirstRecord, FirstModule, SecondRecord, |
916 | SecondModule); |
917 | return true; |
918 | } |
919 | |
920 | if (FirstDiffType != SecondDiffType) { |
921 | diagnoseSubMismatchDifferentDeclKinds(DR, FirstRecord, FirstModule, |
922 | SecondRecord, SecondModule); |
923 | return true; |
924 | } |
925 | |
926 | // Used with err_module_odr_violation_record and |
927 | // note_module_odr_violation_record |
928 | enum ODRCXXRecordDifference { |
929 | StaticAssertCondition, |
930 | StaticAssertMessage, |
931 | StaticAssertOnlyMessage, |
932 | MethodName, |
933 | MethodDeleted, |
934 | MethodDefaulted, |
935 | MethodVirtual, |
936 | MethodStatic, |
937 | MethodVolatile, |
938 | MethodConst, |
939 | MethodInline, |
940 | MethodParameterSingleDefaultArgument, |
941 | MethodParameterDifferentDefaultArgument, |
942 | MethodNoTemplateArguments, |
943 | MethodDifferentNumberTemplateArguments, |
944 | MethodDifferentTemplateArgument, |
945 | MethodSingleBody, |
946 | MethodDifferentBody, |
947 | FriendTypeFunction, |
948 | FriendType, |
949 | FriendFunction, |
950 | FunctionTemplateDifferentNumberParameters, |
951 | FunctionTemplateParameterDifferentKind, |
952 | FunctionTemplateParameterName, |
953 | FunctionTemplateParameterSingleDefaultArgument, |
954 | FunctionTemplateParameterDifferentDefaultArgument, |
955 | FunctionTemplateParameterDifferentType, |
956 | FunctionTemplatePackParameter, |
957 | }; |
958 | auto DiagError = [FirstRecord, &FirstModule, |
959 | this](SourceLocation Loc, SourceRange Range, |
960 | ODRCXXRecordDifference DiffType) { |
961 | return Diag(Loc, DiagID: diag::err_module_odr_violation_record) |
962 | << FirstRecord << FirstModule.empty() << FirstModule << Range |
963 | << DiffType; |
964 | }; |
965 | auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range, |
966 | ODRCXXRecordDifference DiffType) { |
967 | return Diag(Loc, DiagID: diag::note_module_odr_violation_record) |
968 | << SecondModule << Range << DiffType; |
969 | }; |
970 | |
971 | assert(FirstDiffType == SecondDiffType); |
972 | switch (FirstDiffType) { |
973 | case Other: |
974 | case EndOfClass: |
975 | case PublicSpecifer: |
976 | case PrivateSpecifer: |
977 | case ProtectedSpecifer: |
978 | case ObjCMethod: |
979 | case ObjCIvar: |
980 | case ObjCProperty: |
981 | llvm_unreachable("Invalid diff type" ); |
982 | |
983 | case StaticAssert: { |
984 | const StaticAssertDecl *FirstSA = cast<StaticAssertDecl>(Val: FirstDecl); |
985 | const StaticAssertDecl *SecondSA = cast<StaticAssertDecl>(Val: SecondDecl); |
986 | |
987 | const Expr *FirstExpr = FirstSA->getAssertExpr(); |
988 | const Expr *SecondExpr = SecondSA->getAssertExpr(); |
989 | unsigned FirstODRHash = computeODRHash(S: FirstExpr); |
990 | unsigned SecondODRHash = computeODRHash(S: SecondExpr); |
991 | if (FirstODRHash != SecondODRHash) { |
992 | DiagError(FirstExpr->getBeginLoc(), FirstExpr->getSourceRange(), |
993 | StaticAssertCondition); |
994 | DiagNote(SecondExpr->getBeginLoc(), SecondExpr->getSourceRange(), |
995 | StaticAssertCondition); |
996 | return true; |
997 | } |
998 | |
999 | const Expr *FirstMessage = FirstSA->getMessage(); |
1000 | const Expr *SecondMessage = SecondSA->getMessage(); |
1001 | assert((FirstMessage || SecondMessage) && "Both messages cannot be empty" ); |
1002 | if ((FirstMessage && !SecondMessage) || (!FirstMessage && SecondMessage)) { |
1003 | SourceLocation FirstLoc, SecondLoc; |
1004 | SourceRange FirstRange, SecondRange; |
1005 | if (FirstMessage) { |
1006 | FirstLoc = FirstMessage->getBeginLoc(); |
1007 | FirstRange = FirstMessage->getSourceRange(); |
1008 | } else { |
1009 | FirstLoc = FirstSA->getBeginLoc(); |
1010 | FirstRange = FirstSA->getSourceRange(); |
1011 | } |
1012 | if (SecondMessage) { |
1013 | SecondLoc = SecondMessage->getBeginLoc(); |
1014 | SecondRange = SecondMessage->getSourceRange(); |
1015 | } else { |
1016 | SecondLoc = SecondSA->getBeginLoc(); |
1017 | SecondRange = SecondSA->getSourceRange(); |
1018 | } |
1019 | DiagError(FirstLoc, FirstRange, StaticAssertOnlyMessage) |
1020 | << (FirstMessage == nullptr); |
1021 | DiagNote(SecondLoc, SecondRange, StaticAssertOnlyMessage) |
1022 | << (SecondMessage == nullptr); |
1023 | return true; |
1024 | } |
1025 | |
1026 | if (FirstMessage && SecondMessage) { |
1027 | unsigned FirstMessageODRHash = computeODRHash(S: FirstMessage); |
1028 | unsigned SecondMessageODRHash = computeODRHash(S: SecondMessage); |
1029 | if (FirstMessageODRHash != SecondMessageODRHash) { |
1030 | DiagError(FirstMessage->getBeginLoc(), FirstMessage->getSourceRange(), |
1031 | StaticAssertMessage); |
1032 | DiagNote(SecondMessage->getBeginLoc(), SecondMessage->getSourceRange(), |
1033 | StaticAssertMessage); |
1034 | return true; |
1035 | } |
1036 | } |
1037 | break; |
1038 | } |
1039 | |
1040 | case Field: { |
1041 | if (diagnoseSubMismatchField(FirstRecord, FirstModule, SecondModule, |
1042 | FirstField: cast<FieldDecl>(Val: FirstDecl), |
1043 | SecondField: cast<FieldDecl>(Val: SecondDecl))) |
1044 | return true; |
1045 | break; |
1046 | } |
1047 | |
1048 | case CXXMethod: { |
1049 | enum { |
1050 | DiagMethod, |
1051 | DiagConstructor, |
1052 | DiagDestructor, |
1053 | } FirstMethodType, |
1054 | SecondMethodType; |
1055 | auto GetMethodTypeForDiagnostics = [](const CXXMethodDecl *D) { |
1056 | if (isa<CXXConstructorDecl>(Val: D)) |
1057 | return DiagConstructor; |
1058 | if (isa<CXXDestructorDecl>(Val: D)) |
1059 | return DiagDestructor; |
1060 | return DiagMethod; |
1061 | }; |
1062 | const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(Val: FirstDecl); |
1063 | const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(Val: SecondDecl); |
1064 | FirstMethodType = GetMethodTypeForDiagnostics(FirstMethod); |
1065 | SecondMethodType = GetMethodTypeForDiagnostics(SecondMethod); |
1066 | DeclarationName FirstName = FirstMethod->getDeclName(); |
1067 | DeclarationName SecondName = SecondMethod->getDeclName(); |
1068 | auto DiagMethodError = [&DiagError, FirstMethod, FirstMethodType, |
1069 | FirstName](ODRCXXRecordDifference DiffType) { |
1070 | return DiagError(FirstMethod->getLocation(), |
1071 | FirstMethod->getSourceRange(), DiffType) |
1072 | << FirstMethodType << FirstName; |
1073 | }; |
1074 | auto DiagMethodNote = [&DiagNote, SecondMethod, SecondMethodType, |
1075 | SecondName](ODRCXXRecordDifference DiffType) { |
1076 | return DiagNote(SecondMethod->getLocation(), |
1077 | SecondMethod->getSourceRange(), DiffType) |
1078 | << SecondMethodType << SecondName; |
1079 | }; |
1080 | |
1081 | if (FirstMethodType != SecondMethodType || FirstName != SecondName) { |
1082 | DiagMethodError(MethodName); |
1083 | DiagMethodNote(MethodName); |
1084 | return true; |
1085 | } |
1086 | |
1087 | const bool FirstDeleted = FirstMethod->isDeletedAsWritten(); |
1088 | const bool SecondDeleted = SecondMethod->isDeletedAsWritten(); |
1089 | if (FirstDeleted != SecondDeleted) { |
1090 | DiagMethodError(MethodDeleted) << FirstDeleted; |
1091 | DiagMethodNote(MethodDeleted) << SecondDeleted; |
1092 | return true; |
1093 | } |
1094 | |
1095 | const bool FirstDefaulted = FirstMethod->isExplicitlyDefaulted(); |
1096 | const bool SecondDefaulted = SecondMethod->isExplicitlyDefaulted(); |
1097 | if (FirstDefaulted != SecondDefaulted) { |
1098 | DiagMethodError(MethodDefaulted) << FirstDefaulted; |
1099 | DiagMethodNote(MethodDefaulted) << SecondDefaulted; |
1100 | return true; |
1101 | } |
1102 | |
1103 | const bool FirstVirtual = FirstMethod->isVirtualAsWritten(); |
1104 | const bool SecondVirtual = SecondMethod->isVirtualAsWritten(); |
1105 | const bool FirstPure = FirstMethod->isPureVirtual(); |
1106 | const bool SecondPure = SecondMethod->isPureVirtual(); |
1107 | if ((FirstVirtual || SecondVirtual) && |
1108 | (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) { |
1109 | DiagMethodError(MethodVirtual) << FirstPure << FirstVirtual; |
1110 | DiagMethodNote(MethodVirtual) << SecondPure << SecondVirtual; |
1111 | return true; |
1112 | } |
1113 | |
1114 | // CXXMethodDecl::isStatic uses the canonical Decl. With Decl merging, |
1115 | // FirstDecl is the canonical Decl of SecondDecl, so the storage |
1116 | // class needs to be checked instead. |
1117 | StorageClass FirstStorage = FirstMethod->getStorageClass(); |
1118 | StorageClass SecondStorage = SecondMethod->getStorageClass(); |
1119 | const bool FirstStatic = FirstStorage == SC_Static; |
1120 | const bool SecondStatic = SecondStorage == SC_Static; |
1121 | if (FirstStatic != SecondStatic) { |
1122 | DiagMethodError(MethodStatic) << FirstStatic; |
1123 | DiagMethodNote(MethodStatic) << SecondStatic; |
1124 | return true; |
1125 | } |
1126 | |
1127 | const bool FirstVolatile = FirstMethod->isVolatile(); |
1128 | const bool SecondVolatile = SecondMethod->isVolatile(); |
1129 | if (FirstVolatile != SecondVolatile) { |
1130 | DiagMethodError(MethodVolatile) << FirstVolatile; |
1131 | DiagMethodNote(MethodVolatile) << SecondVolatile; |
1132 | return true; |
1133 | } |
1134 | |
1135 | const bool FirstConst = FirstMethod->isConst(); |
1136 | const bool SecondConst = SecondMethod->isConst(); |
1137 | if (FirstConst != SecondConst) { |
1138 | DiagMethodError(MethodConst) << FirstConst; |
1139 | DiagMethodNote(MethodConst) << SecondConst; |
1140 | return true; |
1141 | } |
1142 | |
1143 | const bool FirstInline = FirstMethod->isInlineSpecified(); |
1144 | const bool SecondInline = SecondMethod->isInlineSpecified(); |
1145 | if (FirstInline != SecondInline) { |
1146 | DiagMethodError(MethodInline) << FirstInline; |
1147 | DiagMethodNote(MethodInline) << SecondInline; |
1148 | return true; |
1149 | } |
1150 | |
1151 | if (diagnoseSubMismatchMethodParameters(Diags, FirstContainer: FirstRecord, |
1152 | FirstModule, SecondModule, |
1153 | FirstMethod, SecondMethod)) |
1154 | return true; |
1155 | |
1156 | for (unsigned I = 0, N = FirstMethod->param_size(); I < N; ++I) { |
1157 | const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(i: I); |
1158 | const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(i: I); |
1159 | |
1160 | const Expr *FirstInit = FirstParam->getInit(); |
1161 | const Expr *SecondInit = SecondParam->getInit(); |
1162 | if ((FirstInit == nullptr) != (SecondInit == nullptr)) { |
1163 | DiagMethodError(MethodParameterSingleDefaultArgument) |
1164 | << (I + 1) << (FirstInit == nullptr) |
1165 | << (FirstInit ? FirstInit->getSourceRange() : SourceRange()); |
1166 | DiagMethodNote(MethodParameterSingleDefaultArgument) |
1167 | << (I + 1) << (SecondInit == nullptr) |
1168 | << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); |
1169 | return true; |
1170 | } |
1171 | |
1172 | if (FirstInit && SecondInit && |
1173 | computeODRHash(S: FirstInit) != computeODRHash(S: SecondInit)) { |
1174 | DiagMethodError(MethodParameterDifferentDefaultArgument) |
1175 | << (I + 1) << FirstInit->getSourceRange(); |
1176 | DiagMethodNote(MethodParameterDifferentDefaultArgument) |
1177 | << (I + 1) << SecondInit->getSourceRange(); |
1178 | return true; |
1179 | } |
1180 | } |
1181 | |
1182 | const TemplateArgumentList *FirstTemplateArgs = |
1183 | FirstMethod->getTemplateSpecializationArgs(); |
1184 | const TemplateArgumentList *SecondTemplateArgs = |
1185 | SecondMethod->getTemplateSpecializationArgs(); |
1186 | |
1187 | if ((FirstTemplateArgs && !SecondTemplateArgs) || |
1188 | (!FirstTemplateArgs && SecondTemplateArgs)) { |
1189 | DiagMethodError(MethodNoTemplateArguments) |
1190 | << (FirstTemplateArgs != nullptr); |
1191 | DiagMethodNote(MethodNoTemplateArguments) |
1192 | << (SecondTemplateArgs != nullptr); |
1193 | return true; |
1194 | } |
1195 | |
1196 | if (FirstTemplateArgs && SecondTemplateArgs) { |
1197 | // Remove pack expansions from argument list. |
1198 | auto ExpandTemplateArgumentList = [](const TemplateArgumentList *TAL) { |
1199 | llvm::SmallVector<const TemplateArgument *, 8> ExpandedList; |
1200 | for (const TemplateArgument &TA : TAL->asArray()) { |
1201 | if (TA.getKind() != TemplateArgument::Pack) { |
1202 | ExpandedList.push_back(Elt: &TA); |
1203 | continue; |
1204 | } |
1205 | llvm::append_range(C&: ExpandedList, |
1206 | R: llvm::make_pointer_range(Range: TA.getPackAsArray())); |
1207 | } |
1208 | return ExpandedList; |
1209 | }; |
1210 | llvm::SmallVector<const TemplateArgument *, 8> FirstExpandedList = |
1211 | ExpandTemplateArgumentList(FirstTemplateArgs); |
1212 | llvm::SmallVector<const TemplateArgument *, 8> SecondExpandedList = |
1213 | ExpandTemplateArgumentList(SecondTemplateArgs); |
1214 | |
1215 | if (FirstExpandedList.size() != SecondExpandedList.size()) { |
1216 | DiagMethodError(MethodDifferentNumberTemplateArguments) |
1217 | << (unsigned)FirstExpandedList.size(); |
1218 | DiagMethodNote(MethodDifferentNumberTemplateArguments) |
1219 | << (unsigned)SecondExpandedList.size(); |
1220 | return true; |
1221 | } |
1222 | |
1223 | for (unsigned i = 0, e = FirstExpandedList.size(); i != e; ++i) { |
1224 | const TemplateArgument &FirstTA = *FirstExpandedList[i], |
1225 | &SecondTA = *SecondExpandedList[i]; |
1226 | if (computeODRHash(TA: FirstTA) == computeODRHash(TA: SecondTA)) |
1227 | continue; |
1228 | |
1229 | DiagMethodError(MethodDifferentTemplateArgument) << FirstTA << i + 1; |
1230 | DiagMethodNote(MethodDifferentTemplateArgument) << SecondTA << i + 1; |
1231 | return true; |
1232 | } |
1233 | } |
1234 | |
1235 | // Compute the hash of the method as if it has no body. |
1236 | auto ComputeCXXMethodODRHash = [](const CXXMethodDecl *D) { |
1237 | ODRHash Hasher; |
1238 | Hasher.AddFunctionDecl(Function: D, SkipBody: true /*SkipBody*/); |
1239 | return Hasher.CalculateHash(); |
1240 | }; |
1241 | |
1242 | // Compare the hash generated to the hash stored. A difference means |
1243 | // that a body was present in the original source. Due to merging, |
1244 | // the standard way of detecting a body will not work. |
1245 | const bool HasFirstBody = |
1246 | ComputeCXXMethodODRHash(FirstMethod) != FirstMethod->getODRHash(); |
1247 | const bool HasSecondBody = |
1248 | ComputeCXXMethodODRHash(SecondMethod) != SecondMethod->getODRHash(); |
1249 | |
1250 | if (HasFirstBody != HasSecondBody) { |
1251 | DiagMethodError(MethodSingleBody) << HasFirstBody; |
1252 | DiagMethodNote(MethodSingleBody) << HasSecondBody; |
1253 | return true; |
1254 | } |
1255 | |
1256 | if (HasFirstBody && HasSecondBody) { |
1257 | DiagMethodError(MethodDifferentBody); |
1258 | DiagMethodNote(MethodDifferentBody); |
1259 | return true; |
1260 | } |
1261 | |
1262 | break; |
1263 | } |
1264 | |
1265 | case TypeAlias: |
1266 | case TypeDef: { |
1267 | if (diagnoseSubMismatchTypedef(FirstRecord, FirstModule, SecondModule, |
1268 | FirstTD: cast<TypedefNameDecl>(Val: FirstDecl), |
1269 | SecondTD: cast<TypedefNameDecl>(Val: SecondDecl), |
1270 | IsTypeAlias: FirstDiffType == TypeAlias)) |
1271 | return true; |
1272 | break; |
1273 | } |
1274 | case Var: { |
1275 | if (diagnoseSubMismatchVar(FirstRecord, FirstModule, SecondModule, |
1276 | FirstVD: cast<VarDecl>(Val: FirstDecl), |
1277 | SecondVD: cast<VarDecl>(Val: SecondDecl))) |
1278 | return true; |
1279 | break; |
1280 | } |
1281 | case Friend: { |
1282 | const FriendDecl *FirstFriend = cast<FriendDecl>(Val: FirstDecl); |
1283 | const FriendDecl *SecondFriend = cast<FriendDecl>(Val: SecondDecl); |
1284 | |
1285 | const NamedDecl *FirstND = FirstFriend->getFriendDecl(); |
1286 | const NamedDecl *SecondND = SecondFriend->getFriendDecl(); |
1287 | |
1288 | TypeSourceInfo *FirstTSI = FirstFriend->getFriendType(); |
1289 | TypeSourceInfo *SecondTSI = SecondFriend->getFriendType(); |
1290 | |
1291 | if (FirstND && SecondND) { |
1292 | DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(), |
1293 | FriendFunction) |
1294 | << FirstND; |
1295 | DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(), |
1296 | FriendFunction) |
1297 | << SecondND; |
1298 | return true; |
1299 | } |
1300 | |
1301 | if (FirstTSI && SecondTSI) { |
1302 | QualType FirstFriendType = FirstTSI->getType(); |
1303 | QualType SecondFriendType = SecondTSI->getType(); |
1304 | assert(computeODRHash(FirstFriendType) != |
1305 | computeODRHash(SecondFriendType)); |
1306 | DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(), |
1307 | FriendType) |
1308 | << FirstFriendType; |
1309 | DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(), |
1310 | FriendType) |
1311 | << SecondFriendType; |
1312 | return true; |
1313 | } |
1314 | |
1315 | DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(), |
1316 | FriendTypeFunction) |
1317 | << (FirstTSI == nullptr); |
1318 | DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(), |
1319 | FriendTypeFunction) |
1320 | << (SecondTSI == nullptr); |
1321 | return true; |
1322 | } |
1323 | case FunctionTemplate: { |
1324 | const FunctionTemplateDecl *FirstTemplate = |
1325 | cast<FunctionTemplateDecl>(Val: FirstDecl); |
1326 | const FunctionTemplateDecl *SecondTemplate = |
1327 | cast<FunctionTemplateDecl>(Val: SecondDecl); |
1328 | |
1329 | TemplateParameterList *FirstTPL = FirstTemplate->getTemplateParameters(); |
1330 | TemplateParameterList *SecondTPL = SecondTemplate->getTemplateParameters(); |
1331 | |
1332 | auto DiagTemplateError = [&DiagError, |
1333 | FirstTemplate](ODRCXXRecordDifference DiffType) { |
1334 | return DiagError(FirstTemplate->getLocation(), |
1335 | FirstTemplate->getSourceRange(), DiffType) |
1336 | << FirstTemplate; |
1337 | }; |
1338 | auto DiagTemplateNote = [&DiagNote, |
1339 | SecondTemplate](ODRCXXRecordDifference DiffType) { |
1340 | return DiagNote(SecondTemplate->getLocation(), |
1341 | SecondTemplate->getSourceRange(), DiffType) |
1342 | << SecondTemplate; |
1343 | }; |
1344 | |
1345 | if (FirstTPL->size() != SecondTPL->size()) { |
1346 | DiagTemplateError(FunctionTemplateDifferentNumberParameters) |
1347 | << FirstTPL->size(); |
1348 | DiagTemplateNote(FunctionTemplateDifferentNumberParameters) |
1349 | << SecondTPL->size(); |
1350 | return true; |
1351 | } |
1352 | |
1353 | for (unsigned i = 0, e = FirstTPL->size(); i != e; ++i) { |
1354 | NamedDecl *FirstParam = FirstTPL->getParam(Idx: i); |
1355 | NamedDecl *SecondParam = SecondTPL->getParam(Idx: i); |
1356 | |
1357 | if (FirstParam->getKind() != SecondParam->getKind()) { |
1358 | enum { |
1359 | TemplateTypeParameter, |
1360 | NonTypeTemplateParameter, |
1361 | TemplateTemplateParameter, |
1362 | }; |
1363 | auto GetParamType = [](NamedDecl *D) { |
1364 | switch (D->getKind()) { |
1365 | default: |
1366 | llvm_unreachable("Unexpected template parameter type" ); |
1367 | case Decl::TemplateTypeParm: |
1368 | return TemplateTypeParameter; |
1369 | case Decl::NonTypeTemplateParm: |
1370 | return NonTypeTemplateParameter; |
1371 | case Decl::TemplateTemplateParm: |
1372 | return TemplateTemplateParameter; |
1373 | } |
1374 | }; |
1375 | |
1376 | DiagTemplateError(FunctionTemplateParameterDifferentKind) |
1377 | << (i + 1) << GetParamType(FirstParam); |
1378 | DiagTemplateNote(FunctionTemplateParameterDifferentKind) |
1379 | << (i + 1) << GetParamType(SecondParam); |
1380 | return true; |
1381 | } |
1382 | |
1383 | if (FirstParam->getName() != SecondParam->getName()) { |
1384 | DiagTemplateError(FunctionTemplateParameterName) |
1385 | << (i + 1) << (bool)FirstParam->getIdentifier() << FirstParam; |
1386 | DiagTemplateNote(FunctionTemplateParameterName) |
1387 | << (i + 1) << (bool)SecondParam->getIdentifier() << SecondParam; |
1388 | return true; |
1389 | } |
1390 | |
1391 | if (isa<TemplateTypeParmDecl>(Val: FirstParam) && |
1392 | isa<TemplateTypeParmDecl>(Val: SecondParam)) { |
1393 | TemplateTypeParmDecl *FirstTTPD = |
1394 | cast<TemplateTypeParmDecl>(Val: FirstParam); |
1395 | TemplateTypeParmDecl *SecondTTPD = |
1396 | cast<TemplateTypeParmDecl>(Val: SecondParam); |
1397 | bool HasFirstDefaultArgument = |
1398 | FirstTTPD->hasDefaultArgument() && |
1399 | !FirstTTPD->defaultArgumentWasInherited(); |
1400 | bool HasSecondDefaultArgument = |
1401 | SecondTTPD->hasDefaultArgument() && |
1402 | !SecondTTPD->defaultArgumentWasInherited(); |
1403 | if (HasFirstDefaultArgument != HasSecondDefaultArgument) { |
1404 | DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument) |
1405 | << (i + 1) << HasFirstDefaultArgument; |
1406 | DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument) |
1407 | << (i + 1) << HasSecondDefaultArgument; |
1408 | return true; |
1409 | } |
1410 | |
1411 | if (HasFirstDefaultArgument && HasSecondDefaultArgument) { |
1412 | TemplateArgument FirstTA = |
1413 | FirstTTPD->getDefaultArgument().getArgument(); |
1414 | TemplateArgument SecondTA = |
1415 | SecondTTPD->getDefaultArgument().getArgument(); |
1416 | if (computeODRHash(TA: FirstTA) != computeODRHash(TA: SecondTA)) { |
1417 | DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument) |
1418 | << (i + 1) << FirstTA; |
1419 | DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument) |
1420 | << (i + 1) << SecondTA; |
1421 | return true; |
1422 | } |
1423 | } |
1424 | |
1425 | if (FirstTTPD->isParameterPack() != SecondTTPD->isParameterPack()) { |
1426 | DiagTemplateError(FunctionTemplatePackParameter) |
1427 | << (i + 1) << FirstTTPD->isParameterPack(); |
1428 | DiagTemplateNote(FunctionTemplatePackParameter) |
1429 | << (i + 1) << SecondTTPD->isParameterPack(); |
1430 | return true; |
1431 | } |
1432 | } |
1433 | |
1434 | if (isa<TemplateTemplateParmDecl>(Val: FirstParam) && |
1435 | isa<TemplateTemplateParmDecl>(Val: SecondParam)) { |
1436 | TemplateTemplateParmDecl *FirstTTPD = |
1437 | cast<TemplateTemplateParmDecl>(Val: FirstParam); |
1438 | TemplateTemplateParmDecl *SecondTTPD = |
1439 | cast<TemplateTemplateParmDecl>(Val: SecondParam); |
1440 | |
1441 | TemplateParameterList *FirstTPL = FirstTTPD->getTemplateParameters(); |
1442 | TemplateParameterList *SecondTPL = SecondTTPD->getTemplateParameters(); |
1443 | |
1444 | auto ComputeTemplateParameterListODRHash = |
1445 | [](const TemplateParameterList *TPL) { |
1446 | assert(TPL); |
1447 | ODRHash Hasher; |
1448 | Hasher.AddTemplateParameterList(TPL); |
1449 | return Hasher.CalculateHash(); |
1450 | }; |
1451 | |
1452 | if (ComputeTemplateParameterListODRHash(FirstTPL) != |
1453 | ComputeTemplateParameterListODRHash(SecondTPL)) { |
1454 | DiagTemplateError(FunctionTemplateParameterDifferentType) << (i + 1); |
1455 | DiagTemplateNote(FunctionTemplateParameterDifferentType) << (i + 1); |
1456 | return true; |
1457 | } |
1458 | |
1459 | bool HasFirstDefaultArgument = |
1460 | FirstTTPD->hasDefaultArgument() && |
1461 | !FirstTTPD->defaultArgumentWasInherited(); |
1462 | bool HasSecondDefaultArgument = |
1463 | SecondTTPD->hasDefaultArgument() && |
1464 | !SecondTTPD->defaultArgumentWasInherited(); |
1465 | if (HasFirstDefaultArgument != HasSecondDefaultArgument) { |
1466 | DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument) |
1467 | << (i + 1) << HasFirstDefaultArgument; |
1468 | DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument) |
1469 | << (i + 1) << HasSecondDefaultArgument; |
1470 | return true; |
1471 | } |
1472 | |
1473 | if (HasFirstDefaultArgument && HasSecondDefaultArgument) { |
1474 | TemplateArgument FirstTA = |
1475 | FirstTTPD->getDefaultArgument().getArgument(); |
1476 | TemplateArgument SecondTA = |
1477 | SecondTTPD->getDefaultArgument().getArgument(); |
1478 | if (computeODRHash(TA: FirstTA) != computeODRHash(TA: SecondTA)) { |
1479 | DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument) |
1480 | << (i + 1) << FirstTA; |
1481 | DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument) |
1482 | << (i + 1) << SecondTA; |
1483 | return true; |
1484 | } |
1485 | } |
1486 | |
1487 | if (FirstTTPD->isParameterPack() != SecondTTPD->isParameterPack()) { |
1488 | DiagTemplateError(FunctionTemplatePackParameter) |
1489 | << (i + 1) << FirstTTPD->isParameterPack(); |
1490 | DiagTemplateNote(FunctionTemplatePackParameter) |
1491 | << (i + 1) << SecondTTPD->isParameterPack(); |
1492 | return true; |
1493 | } |
1494 | } |
1495 | |
1496 | if (isa<NonTypeTemplateParmDecl>(Val: FirstParam) && |
1497 | isa<NonTypeTemplateParmDecl>(Val: SecondParam)) { |
1498 | NonTypeTemplateParmDecl *FirstNTTPD = |
1499 | cast<NonTypeTemplateParmDecl>(Val: FirstParam); |
1500 | NonTypeTemplateParmDecl *SecondNTTPD = |
1501 | cast<NonTypeTemplateParmDecl>(Val: SecondParam); |
1502 | |
1503 | QualType FirstType = FirstNTTPD->getType(); |
1504 | QualType SecondType = SecondNTTPD->getType(); |
1505 | if (computeODRHash(Ty: FirstType) != computeODRHash(Ty: SecondType)) { |
1506 | DiagTemplateError(FunctionTemplateParameterDifferentType) << (i + 1); |
1507 | DiagTemplateNote(FunctionTemplateParameterDifferentType) << (i + 1); |
1508 | return true; |
1509 | } |
1510 | |
1511 | bool HasFirstDefaultArgument = |
1512 | FirstNTTPD->hasDefaultArgument() && |
1513 | !FirstNTTPD->defaultArgumentWasInherited(); |
1514 | bool HasSecondDefaultArgument = |
1515 | SecondNTTPD->hasDefaultArgument() && |
1516 | !SecondNTTPD->defaultArgumentWasInherited(); |
1517 | if (HasFirstDefaultArgument != HasSecondDefaultArgument) { |
1518 | DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument) |
1519 | << (i + 1) << HasFirstDefaultArgument; |
1520 | DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument) |
1521 | << (i + 1) << HasSecondDefaultArgument; |
1522 | return true; |
1523 | } |
1524 | |
1525 | if (HasFirstDefaultArgument && HasSecondDefaultArgument) { |
1526 | TemplateArgument FirstDefaultArgument = |
1527 | FirstNTTPD->getDefaultArgument().getArgument(); |
1528 | TemplateArgument SecondDefaultArgument = |
1529 | SecondNTTPD->getDefaultArgument().getArgument(); |
1530 | |
1531 | if (computeODRHash(TA: FirstDefaultArgument) != |
1532 | computeODRHash(TA: SecondDefaultArgument)) { |
1533 | DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument) |
1534 | << (i + 1) << FirstDefaultArgument; |
1535 | DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument) |
1536 | << (i + 1) << SecondDefaultArgument; |
1537 | return true; |
1538 | } |
1539 | } |
1540 | |
1541 | if (FirstNTTPD->isParameterPack() != SecondNTTPD->isParameterPack()) { |
1542 | DiagTemplateError(FunctionTemplatePackParameter) |
1543 | << (i + 1) << FirstNTTPD->isParameterPack(); |
1544 | DiagTemplateNote(FunctionTemplatePackParameter) |
1545 | << (i + 1) << SecondNTTPD->isParameterPack(); |
1546 | return true; |
1547 | } |
1548 | } |
1549 | } |
1550 | break; |
1551 | } |
1552 | } |
1553 | |
1554 | Diag(Loc: FirstDecl->getLocation(), |
1555 | DiagID: diag::err_module_odr_violation_mismatch_decl_unknown) |
1556 | << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType |
1557 | << FirstDecl->getSourceRange(); |
1558 | Diag(Loc: SecondDecl->getLocation(), |
1559 | DiagID: diag::note_module_odr_violation_mismatch_decl_unknown) |
1560 | << SecondModule.empty() << SecondModule << FirstDiffType |
1561 | << SecondDecl->getSourceRange(); |
1562 | return true; |
1563 | } |
1564 | |
1565 | bool ODRDiagsEmitter::diagnoseMismatch(const RecordDecl *FirstRecord, |
1566 | const RecordDecl *SecondRecord) const { |
1567 | if (FirstRecord == SecondRecord) |
1568 | return false; |
1569 | |
1570 | std::string FirstModule = getOwningModuleNameForDiagnostic(D: FirstRecord); |
1571 | std::string SecondModule = getOwningModuleNameForDiagnostic(D: SecondRecord); |
1572 | |
1573 | auto PopulateHashes = [](DeclHashes &Hashes, const RecordDecl *Record, |
1574 | const DeclContext *DC) { |
1575 | for (const Decl *D : Record->decls()) { |
1576 | if (!ODRHash::isSubDeclToBeProcessed(D, Parent: DC)) |
1577 | continue; |
1578 | Hashes.emplace_back(Args&: D, Args: computeODRHash(D)); |
1579 | } |
1580 | }; |
1581 | |
1582 | DeclHashes FirstHashes; |
1583 | DeclHashes SecondHashes; |
1584 | const DeclContext *DC = FirstRecord; |
1585 | PopulateHashes(FirstHashes, FirstRecord, DC); |
1586 | PopulateHashes(SecondHashes, SecondRecord, DC); |
1587 | |
1588 | DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes); |
1589 | ODRMismatchDecl FirstDiffType = DR.FirstDiffType; |
1590 | ODRMismatchDecl SecondDiffType = DR.SecondDiffType; |
1591 | const Decl *FirstDecl = DR.FirstDecl; |
1592 | const Decl *SecondDecl = DR.SecondDecl; |
1593 | |
1594 | if (FirstDiffType == Other || SecondDiffType == Other) { |
1595 | diagnoseSubMismatchUnexpected(DR, FirstRecord, FirstModule, SecondRecord, |
1596 | SecondModule); |
1597 | return true; |
1598 | } |
1599 | |
1600 | if (FirstDiffType != SecondDiffType) { |
1601 | diagnoseSubMismatchDifferentDeclKinds(DR, FirstRecord, FirstModule, |
1602 | SecondRecord, SecondModule); |
1603 | return true; |
1604 | } |
1605 | |
1606 | assert(FirstDiffType == SecondDiffType); |
1607 | switch (FirstDiffType) { |
1608 | // Already handled. |
1609 | case EndOfClass: |
1610 | case Other: |
1611 | // C++ only, invalid in this context. |
1612 | case PublicSpecifer: |
1613 | case PrivateSpecifer: |
1614 | case ProtectedSpecifer: |
1615 | case StaticAssert: |
1616 | case CXXMethod: |
1617 | case TypeAlias: |
1618 | case Friend: |
1619 | case FunctionTemplate: |
1620 | // Cannot be contained by RecordDecl, invalid in this context. |
1621 | case ObjCMethod: |
1622 | case ObjCIvar: |
1623 | case ObjCProperty: |
1624 | llvm_unreachable("Invalid diff type" ); |
1625 | |
1626 | case Field: { |
1627 | if (diagnoseSubMismatchField(FirstRecord, FirstModule, SecondModule, |
1628 | FirstField: cast<FieldDecl>(Val: FirstDecl), |
1629 | SecondField: cast<FieldDecl>(Val: SecondDecl))) |
1630 | return true; |
1631 | break; |
1632 | } |
1633 | case TypeDef: { |
1634 | if (diagnoseSubMismatchTypedef(FirstRecord, FirstModule, SecondModule, |
1635 | FirstTD: cast<TypedefNameDecl>(Val: FirstDecl), |
1636 | SecondTD: cast<TypedefNameDecl>(Val: SecondDecl), |
1637 | /*IsTypeAlias=*/false)) |
1638 | return true; |
1639 | break; |
1640 | } |
1641 | case Var: { |
1642 | if (diagnoseSubMismatchVar(FirstRecord, FirstModule, SecondModule, |
1643 | FirstVD: cast<VarDecl>(Val: FirstDecl), |
1644 | SecondVD: cast<VarDecl>(Val: SecondDecl))) |
1645 | return true; |
1646 | break; |
1647 | } |
1648 | } |
1649 | |
1650 | Diag(Loc: FirstDecl->getLocation(), |
1651 | DiagID: diag::err_module_odr_violation_mismatch_decl_unknown) |
1652 | << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType |
1653 | << FirstDecl->getSourceRange(); |
1654 | Diag(Loc: SecondDecl->getLocation(), |
1655 | DiagID: diag::note_module_odr_violation_mismatch_decl_unknown) |
1656 | << SecondModule.empty() << SecondModule << FirstDiffType |
1657 | << SecondDecl->getSourceRange(); |
1658 | return true; |
1659 | } |
1660 | |
1661 | bool ODRDiagsEmitter::diagnoseMismatch( |
1662 | const FunctionDecl *FirstFunction, |
1663 | const FunctionDecl *SecondFunction) const { |
1664 | if (FirstFunction == SecondFunction) |
1665 | return false; |
1666 | |
1667 | // Keep in sync with select options in err_module_odr_violation_function. |
1668 | enum ODRFunctionDifference { |
1669 | ReturnType, |
1670 | ParameterName, |
1671 | ParameterType, |
1672 | ParameterSingleDefaultArgument, |
1673 | ParameterDifferentDefaultArgument, |
1674 | FunctionBody, |
1675 | }; |
1676 | |
1677 | std::string FirstModule = getOwningModuleNameForDiagnostic(D: FirstFunction); |
1678 | std::string SecondModule = getOwningModuleNameForDiagnostic(D: SecondFunction); |
1679 | |
1680 | auto DiagError = [FirstFunction, &FirstModule, |
1681 | this](SourceLocation Loc, SourceRange Range, |
1682 | ODRFunctionDifference DiffType) { |
1683 | return Diag(Loc, DiagID: diag::err_module_odr_violation_function) |
1684 | << FirstFunction << FirstModule.empty() << FirstModule << Range |
1685 | << DiffType; |
1686 | }; |
1687 | auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range, |
1688 | ODRFunctionDifference DiffType) { |
1689 | return Diag(Loc, DiagID: diag::note_module_odr_violation_function) |
1690 | << SecondModule << Range << DiffType; |
1691 | }; |
1692 | |
1693 | if (computeODRHash(Ty: FirstFunction->getReturnType()) != |
1694 | computeODRHash(Ty: SecondFunction->getReturnType())) { |
1695 | DiagError(FirstFunction->getReturnTypeSourceRange().getBegin(), |
1696 | FirstFunction->getReturnTypeSourceRange(), ReturnType) |
1697 | << FirstFunction->getReturnType(); |
1698 | DiagNote(SecondFunction->getReturnTypeSourceRange().getBegin(), |
1699 | SecondFunction->getReturnTypeSourceRange(), ReturnType) |
1700 | << SecondFunction->getReturnType(); |
1701 | return true; |
1702 | } |
1703 | |
1704 | assert(FirstFunction->param_size() == SecondFunction->param_size() && |
1705 | "Merged functions with different number of parameters" ); |
1706 | |
1707 | size_t ParamSize = FirstFunction->param_size(); |
1708 | for (unsigned I = 0; I < ParamSize; ++I) { |
1709 | const ParmVarDecl *FirstParam = FirstFunction->getParamDecl(i: I); |
1710 | const ParmVarDecl *SecondParam = SecondFunction->getParamDecl(i: I); |
1711 | |
1712 | assert(Context.hasSameType(FirstParam->getType(), SecondParam->getType()) && |
1713 | "Merged function has different parameter types." ); |
1714 | |
1715 | if (FirstParam->getDeclName() != SecondParam->getDeclName()) { |
1716 | DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), |
1717 | ParameterName) |
1718 | << I + 1 << FirstParam->getDeclName(); |
1719 | DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), |
1720 | ParameterName) |
1721 | << I + 1 << SecondParam->getDeclName(); |
1722 | return true; |
1723 | }; |
1724 | |
1725 | QualType FirstParamType = FirstParam->getType(); |
1726 | QualType SecondParamType = SecondParam->getType(); |
1727 | if (FirstParamType != SecondParamType && |
1728 | computeODRHash(Ty: FirstParamType) != computeODRHash(Ty: SecondParamType)) { |
1729 | if (const DecayedType *ParamDecayedType = |
1730 | FirstParamType->getAs<DecayedType>()) { |
1731 | DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), |
1732 | ParameterType) |
1733 | << (I + 1) << FirstParamType << true |
1734 | << ParamDecayedType->getOriginalType(); |
1735 | } else { |
1736 | DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), |
1737 | ParameterType) |
1738 | << (I + 1) << FirstParamType << false; |
1739 | } |
1740 | |
1741 | if (const DecayedType *ParamDecayedType = |
1742 | SecondParamType->getAs<DecayedType>()) { |
1743 | DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), |
1744 | ParameterType) |
1745 | << (I + 1) << SecondParamType << true |
1746 | << ParamDecayedType->getOriginalType(); |
1747 | } else { |
1748 | DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), |
1749 | ParameterType) |
1750 | << (I + 1) << SecondParamType << false; |
1751 | } |
1752 | return true; |
1753 | } |
1754 | |
1755 | // Note, these calls can trigger deserialization. |
1756 | const Expr *FirstInit = FirstParam->getInit(); |
1757 | const Expr *SecondInit = SecondParam->getInit(); |
1758 | if ((FirstInit == nullptr) != (SecondInit == nullptr)) { |
1759 | DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), |
1760 | ParameterSingleDefaultArgument) |
1761 | << (I + 1) << (FirstInit == nullptr) |
1762 | << (FirstInit ? FirstInit->getSourceRange() : SourceRange()); |
1763 | DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), |
1764 | ParameterSingleDefaultArgument) |
1765 | << (I + 1) << (SecondInit == nullptr) |
1766 | << (SecondInit ? SecondInit->getSourceRange() : SourceRange()); |
1767 | return true; |
1768 | } |
1769 | |
1770 | if (FirstInit && SecondInit && |
1771 | computeODRHash(S: FirstInit) != computeODRHash(S: SecondInit)) { |
1772 | DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(), |
1773 | ParameterDifferentDefaultArgument) |
1774 | << (I + 1) << FirstInit->getSourceRange(); |
1775 | DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(), |
1776 | ParameterDifferentDefaultArgument) |
1777 | << (I + 1) << SecondInit->getSourceRange(); |
1778 | return true; |
1779 | } |
1780 | |
1781 | assert(computeODRHash(FirstParam) == computeODRHash(SecondParam) && |
1782 | "Undiagnosed parameter difference." ); |
1783 | } |
1784 | |
1785 | // If no error has been generated before now, assume the problem is in |
1786 | // the body and generate a message. |
1787 | DiagError(FirstFunction->getLocation(), FirstFunction->getSourceRange(), |
1788 | FunctionBody); |
1789 | DiagNote(SecondFunction->getLocation(), SecondFunction->getSourceRange(), |
1790 | FunctionBody); |
1791 | return true; |
1792 | } |
1793 | |
1794 | bool ODRDiagsEmitter::diagnoseMismatch(const EnumDecl *FirstEnum, |
1795 | const EnumDecl *SecondEnum) const { |
1796 | if (FirstEnum == SecondEnum) |
1797 | return false; |
1798 | |
1799 | // Keep in sync with select options in err_module_odr_violation_enum. |
1800 | enum ODREnumDifference { |
1801 | SingleScopedEnum, |
1802 | EnumTagKeywordMismatch, |
1803 | SingleSpecifiedType, |
1804 | DifferentSpecifiedTypes, |
1805 | DifferentNumberEnumConstants, |
1806 | EnumConstantName, |
1807 | EnumConstantSingleInitializer, |
1808 | EnumConstantDifferentInitializer, |
1809 | }; |
1810 | |
1811 | std::string FirstModule = getOwningModuleNameForDiagnostic(D: FirstEnum); |
1812 | std::string SecondModule = getOwningModuleNameForDiagnostic(D: SecondEnum); |
1813 | |
1814 | auto DiagError = [FirstEnum, &FirstModule, this](const auto *DiagAnchor, |
1815 | ODREnumDifference DiffType) { |
1816 | return Diag(Loc: DiagAnchor->getLocation(), DiagID: diag::err_module_odr_violation_enum) |
1817 | << FirstEnum << FirstModule.empty() << FirstModule |
1818 | << DiagAnchor->getSourceRange() << DiffType; |
1819 | }; |
1820 | auto DiagNote = [&SecondModule, this](const auto *DiagAnchor, |
1821 | ODREnumDifference DiffType) { |
1822 | return Diag(Loc: DiagAnchor->getLocation(), DiagID: diag::note_module_odr_violation_enum) |
1823 | << SecondModule << DiagAnchor->getSourceRange() << DiffType; |
1824 | }; |
1825 | |
1826 | if (FirstEnum->isScoped() != SecondEnum->isScoped()) { |
1827 | DiagError(FirstEnum, SingleScopedEnum) << FirstEnum->isScoped(); |
1828 | DiagNote(SecondEnum, SingleScopedEnum) << SecondEnum->isScoped(); |
1829 | return true; |
1830 | } |
1831 | |
1832 | if (FirstEnum->isScoped() && SecondEnum->isScoped()) { |
1833 | if (FirstEnum->isScopedUsingClassTag() != |
1834 | SecondEnum->isScopedUsingClassTag()) { |
1835 | DiagError(FirstEnum, EnumTagKeywordMismatch) |
1836 | << FirstEnum->isScopedUsingClassTag(); |
1837 | DiagNote(SecondEnum, EnumTagKeywordMismatch) |
1838 | << SecondEnum->isScopedUsingClassTag(); |
1839 | return true; |
1840 | } |
1841 | } |
1842 | |
1843 | QualType FirstUnderlyingType = |
1844 | FirstEnum->getIntegerTypeSourceInfo() |
1845 | ? FirstEnum->getIntegerTypeSourceInfo()->getType() |
1846 | : QualType(); |
1847 | QualType SecondUnderlyingType = |
1848 | SecondEnum->getIntegerTypeSourceInfo() |
1849 | ? SecondEnum->getIntegerTypeSourceInfo()->getType() |
1850 | : QualType(); |
1851 | if (FirstUnderlyingType.isNull() != SecondUnderlyingType.isNull()) { |
1852 | DiagError(FirstEnum, SingleSpecifiedType) << !FirstUnderlyingType.isNull(); |
1853 | DiagNote(SecondEnum, SingleSpecifiedType) << !SecondUnderlyingType.isNull(); |
1854 | return true; |
1855 | } |
1856 | |
1857 | if (!FirstUnderlyingType.isNull() && !SecondUnderlyingType.isNull()) { |
1858 | if (computeODRHash(Ty: FirstUnderlyingType) != |
1859 | computeODRHash(Ty: SecondUnderlyingType)) { |
1860 | DiagError(FirstEnum, DifferentSpecifiedTypes) << FirstUnderlyingType; |
1861 | DiagNote(SecondEnum, DifferentSpecifiedTypes) << SecondUnderlyingType; |
1862 | return true; |
1863 | } |
1864 | } |
1865 | |
1866 | // Compare enum constants. |
1867 | using DeclHashes = |
1868 | llvm::SmallVector<std::pair<const EnumConstantDecl *, unsigned>, 4>; |
1869 | auto PopulateHashes = [FirstEnum](DeclHashes &Hashes, const EnumDecl *Enum) { |
1870 | for (const Decl *D : Enum->decls()) { |
1871 | // Due to decl merging, the first EnumDecl is the parent of |
1872 | // Decls in both records. |
1873 | if (!ODRHash::isSubDeclToBeProcessed(D, Parent: FirstEnum)) |
1874 | continue; |
1875 | assert(isa<EnumConstantDecl>(D) && "Unexpected Decl kind" ); |
1876 | Hashes.emplace_back(Args: cast<EnumConstantDecl>(Val: D), Args: computeODRHash(D)); |
1877 | } |
1878 | }; |
1879 | DeclHashes FirstHashes; |
1880 | PopulateHashes(FirstHashes, FirstEnum); |
1881 | DeclHashes SecondHashes; |
1882 | PopulateHashes(SecondHashes, SecondEnum); |
1883 | |
1884 | if (FirstHashes.size() != SecondHashes.size()) { |
1885 | DiagError(FirstEnum, DifferentNumberEnumConstants) |
1886 | << (int)FirstHashes.size(); |
1887 | DiagNote(SecondEnum, DifferentNumberEnumConstants) |
1888 | << (int)SecondHashes.size(); |
1889 | return true; |
1890 | } |
1891 | |
1892 | for (unsigned I = 0, N = FirstHashes.size(); I < N; ++I) { |
1893 | if (FirstHashes[I].second == SecondHashes[I].second) |
1894 | continue; |
1895 | const EnumConstantDecl *FirstConstant = FirstHashes[I].first; |
1896 | const EnumConstantDecl *SecondConstant = SecondHashes[I].first; |
1897 | |
1898 | if (FirstConstant->getDeclName() != SecondConstant->getDeclName()) { |
1899 | DiagError(FirstConstant, EnumConstantName) << I + 1 << FirstConstant; |
1900 | DiagNote(SecondConstant, EnumConstantName) << I + 1 << SecondConstant; |
1901 | return true; |
1902 | } |
1903 | |
1904 | const Expr *FirstInit = FirstConstant->getInitExpr(); |
1905 | const Expr *SecondInit = SecondConstant->getInitExpr(); |
1906 | if (!FirstInit && !SecondInit) |
1907 | continue; |
1908 | |
1909 | if (!FirstInit || !SecondInit) { |
1910 | DiagError(FirstConstant, EnumConstantSingleInitializer) |
1911 | << I + 1 << FirstConstant << (FirstInit != nullptr); |
1912 | DiagNote(SecondConstant, EnumConstantSingleInitializer) |
1913 | << I + 1 << SecondConstant << (SecondInit != nullptr); |
1914 | return true; |
1915 | } |
1916 | |
1917 | if (computeODRHash(S: FirstInit) != computeODRHash(S: SecondInit)) { |
1918 | DiagError(FirstConstant, EnumConstantDifferentInitializer) |
1919 | << I + 1 << FirstConstant; |
1920 | DiagNote(SecondConstant, EnumConstantDifferentInitializer) |
1921 | << I + 1 << SecondConstant; |
1922 | return true; |
1923 | } |
1924 | } |
1925 | return false; |
1926 | } |
1927 | |
1928 | bool ODRDiagsEmitter::diagnoseMismatch( |
1929 | const ObjCInterfaceDecl *FirstID, const ObjCInterfaceDecl *SecondID, |
1930 | const struct ObjCInterfaceDecl::DefinitionData *SecondDD) const { |
1931 | // Multiple different declarations got merged together; tell the user |
1932 | // where they came from. |
1933 | if (FirstID == SecondID) |
1934 | return false; |
1935 | |
1936 | std::string FirstModule = getOwningModuleNameForDiagnostic(D: FirstID); |
1937 | std::string SecondModule = getOwningModuleNameForDiagnostic(D: SecondID); |
1938 | |
1939 | // Keep in sync with err_module_odr_violation_objc_interface. |
1940 | enum ODRInterfaceDifference { |
1941 | SuperClassType, |
1942 | IVarAccess, |
1943 | }; |
1944 | |
1945 | auto DiagError = [FirstID, &FirstModule, |
1946 | this](SourceLocation Loc, SourceRange Range, |
1947 | ODRInterfaceDifference DiffType) { |
1948 | return Diag(Loc, DiagID: diag::err_module_odr_violation_objc_interface) |
1949 | << FirstID << FirstModule.empty() << FirstModule << Range |
1950 | << DiffType; |
1951 | }; |
1952 | auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range, |
1953 | ODRInterfaceDifference DiffType) { |
1954 | return Diag(Loc, DiagID: diag::note_module_odr_violation_objc_interface) |
1955 | << SecondModule.empty() << SecondModule << Range << DiffType; |
1956 | }; |
1957 | |
1958 | const struct ObjCInterfaceDecl::DefinitionData *FirstDD = &FirstID->data(); |
1959 | assert(FirstDD && SecondDD && "Definitions without DefinitionData" ); |
1960 | if (FirstDD != SecondDD) { |
1961 | // Check for matching super class. |
1962 | auto GetSuperClassSourceRange = [](const TypeSourceInfo *SuperInfo, |
1963 | const ObjCInterfaceDecl *ID) { |
1964 | if (!SuperInfo) |
1965 | return ID->getSourceRange(); |
1966 | TypeLoc Loc = SuperInfo->getTypeLoc(); |
1967 | return SourceRange(Loc.getBeginLoc(), Loc.getEndLoc()); |
1968 | }; |
1969 | |
1970 | ObjCInterfaceDecl *FirstSuperClass = FirstID->getSuperClass(); |
1971 | ObjCInterfaceDecl *SecondSuperClass = nullptr; |
1972 | const TypeSourceInfo *FirstSuperInfo = FirstID->getSuperClassTInfo(); |
1973 | const TypeSourceInfo *SecondSuperInfo = SecondDD->SuperClassTInfo; |
1974 | if (SecondSuperInfo) |
1975 | SecondSuperClass = |
1976 | SecondSuperInfo->getType()->castAs<ObjCObjectType>()->getInterface(); |
1977 | |
1978 | if ((FirstSuperClass && SecondSuperClass && |
1979 | FirstSuperClass->getODRHash() != SecondSuperClass->getODRHash()) || |
1980 | (FirstSuperClass && !SecondSuperClass) || |
1981 | (!FirstSuperClass && SecondSuperClass)) { |
1982 | QualType FirstType; |
1983 | if (FirstSuperInfo) |
1984 | FirstType = FirstSuperInfo->getType(); |
1985 | |
1986 | DiagError(FirstID->getLocation(), |
1987 | GetSuperClassSourceRange(FirstSuperInfo, FirstID), |
1988 | SuperClassType) |
1989 | << (bool)FirstSuperInfo << FirstType; |
1990 | |
1991 | QualType SecondType; |
1992 | if (SecondSuperInfo) |
1993 | SecondType = SecondSuperInfo->getType(); |
1994 | |
1995 | DiagNote(SecondID->getLocation(), |
1996 | GetSuperClassSourceRange(SecondSuperInfo, SecondID), |
1997 | SuperClassType) |
1998 | << (bool)SecondSuperInfo << SecondType; |
1999 | return true; |
2000 | } |
2001 | |
2002 | // Check both interfaces reference the same protocols. |
2003 | auto &FirstProtos = FirstID->getReferencedProtocols(); |
2004 | auto &SecondProtos = SecondDD->ReferencedProtocols; |
2005 | if (diagnoseSubMismatchProtocols(FirstProtocols: FirstProtos, FirstContainer: FirstID, FirstModule, |
2006 | SecondProtocols: SecondProtos, SecondContainer: SecondID, SecondModule)) |
2007 | return true; |
2008 | } |
2009 | |
2010 | auto PopulateHashes = [](DeclHashes &Hashes, const ObjCInterfaceDecl *ID, |
2011 | const DeclContext *DC) { |
2012 | for (auto *D : ID->decls()) { |
2013 | if (!ODRHash::isSubDeclToBeProcessed(D, Parent: DC)) |
2014 | continue; |
2015 | Hashes.emplace_back(Args&: D, Args: computeODRHash(D)); |
2016 | } |
2017 | }; |
2018 | |
2019 | DeclHashes FirstHashes; |
2020 | DeclHashes SecondHashes; |
2021 | // Use definition as DeclContext because definitions are merged when |
2022 | // DeclContexts are merged and separate when DeclContexts are separate. |
2023 | PopulateHashes(FirstHashes, FirstID, FirstID->getDefinition()); |
2024 | PopulateHashes(SecondHashes, SecondID, SecondID->getDefinition()); |
2025 | |
2026 | DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes); |
2027 | ODRMismatchDecl FirstDiffType = DR.FirstDiffType; |
2028 | ODRMismatchDecl SecondDiffType = DR.SecondDiffType; |
2029 | const Decl *FirstDecl = DR.FirstDecl; |
2030 | const Decl *SecondDecl = DR.SecondDecl; |
2031 | |
2032 | if (FirstDiffType == Other || SecondDiffType == Other) { |
2033 | diagnoseSubMismatchUnexpected(DR, FirstRecord: FirstID, FirstModule, SecondRecord: SecondID, |
2034 | SecondModule); |
2035 | return true; |
2036 | } |
2037 | |
2038 | if (FirstDiffType != SecondDiffType) { |
2039 | diagnoseSubMismatchDifferentDeclKinds(DR, FirstRecord: FirstID, FirstModule, SecondRecord: SecondID, |
2040 | SecondModule); |
2041 | return true; |
2042 | } |
2043 | |
2044 | assert(FirstDiffType == SecondDiffType); |
2045 | switch (FirstDiffType) { |
2046 | // Already handled. |
2047 | case EndOfClass: |
2048 | case Other: |
2049 | // Cannot be contained by ObjCInterfaceDecl, invalid in this context. |
2050 | case Field: |
2051 | case TypeDef: |
2052 | case Var: |
2053 | // C++ only, invalid in this context. |
2054 | case PublicSpecifer: |
2055 | case PrivateSpecifer: |
2056 | case ProtectedSpecifer: |
2057 | case StaticAssert: |
2058 | case CXXMethod: |
2059 | case TypeAlias: |
2060 | case Friend: |
2061 | case FunctionTemplate: |
2062 | llvm_unreachable("Invalid diff type" ); |
2063 | |
2064 | case ObjCMethod: { |
2065 | if (diagnoseSubMismatchObjCMethod(FirstObjCContainer: FirstID, FirstModule, SecondModule, |
2066 | FirstMethod: cast<ObjCMethodDecl>(Val: FirstDecl), |
2067 | SecondMethod: cast<ObjCMethodDecl>(Val: SecondDecl))) |
2068 | return true; |
2069 | break; |
2070 | } |
2071 | case ObjCIvar: { |
2072 | if (diagnoseSubMismatchField(FirstRecord: FirstID, FirstModule, SecondModule, |
2073 | FirstField: cast<FieldDecl>(Val: FirstDecl), |
2074 | SecondField: cast<FieldDecl>(Val: SecondDecl))) |
2075 | return true; |
2076 | |
2077 | // Check if the access match. |
2078 | const ObjCIvarDecl *FirstIvar = cast<ObjCIvarDecl>(Val: FirstDecl); |
2079 | const ObjCIvarDecl *SecondIvar = cast<ObjCIvarDecl>(Val: SecondDecl); |
2080 | if (FirstIvar->getCanonicalAccessControl() != |
2081 | SecondIvar->getCanonicalAccessControl()) { |
2082 | DiagError(FirstIvar->getLocation(), FirstIvar->getSourceRange(), |
2083 | IVarAccess) |
2084 | << FirstIvar->getName() |
2085 | << (int)FirstIvar->getCanonicalAccessControl(); |
2086 | DiagNote(SecondIvar->getLocation(), SecondIvar->getSourceRange(), |
2087 | IVarAccess) |
2088 | << SecondIvar->getName() |
2089 | << (int)SecondIvar->getCanonicalAccessControl(); |
2090 | return true; |
2091 | } |
2092 | break; |
2093 | } |
2094 | case ObjCProperty: { |
2095 | if (diagnoseSubMismatchObjCProperty(FirstObjCContainer: FirstID, FirstModule, SecondModule, |
2096 | FirstProp: cast<ObjCPropertyDecl>(Val: FirstDecl), |
2097 | SecondProp: cast<ObjCPropertyDecl>(Val: SecondDecl))) |
2098 | return true; |
2099 | break; |
2100 | } |
2101 | } |
2102 | |
2103 | Diag(Loc: FirstDecl->getLocation(), |
2104 | DiagID: diag::err_module_odr_violation_mismatch_decl_unknown) |
2105 | << FirstID << FirstModule.empty() << FirstModule << FirstDiffType |
2106 | << FirstDecl->getSourceRange(); |
2107 | Diag(Loc: SecondDecl->getLocation(), |
2108 | DiagID: diag::note_module_odr_violation_mismatch_decl_unknown) |
2109 | << SecondModule.empty() << SecondModule << FirstDiffType |
2110 | << SecondDecl->getSourceRange(); |
2111 | return true; |
2112 | } |
2113 | |
2114 | bool ODRDiagsEmitter::diagnoseMismatch( |
2115 | const ObjCProtocolDecl *FirstProtocol, |
2116 | const ObjCProtocolDecl *SecondProtocol, |
2117 | const struct ObjCProtocolDecl::DefinitionData *SecondDD) const { |
2118 | if (FirstProtocol == SecondProtocol) |
2119 | return false; |
2120 | |
2121 | std::string FirstModule = getOwningModuleNameForDiagnostic(D: FirstProtocol); |
2122 | std::string SecondModule = getOwningModuleNameForDiagnostic(D: SecondProtocol); |
2123 | |
2124 | const ObjCProtocolDecl::DefinitionData *FirstDD = &FirstProtocol->data(); |
2125 | assert(FirstDD && SecondDD && "Definitions without DefinitionData" ); |
2126 | // Diagnostics from ObjCProtocol DefinitionData are emitted here. |
2127 | if (FirstDD != SecondDD) { |
2128 | // Check both protocols reference the same protocols. |
2129 | const ObjCProtocolList &FirstProtocols = |
2130 | FirstProtocol->getReferencedProtocols(); |
2131 | const ObjCProtocolList &SecondProtocols = SecondDD->ReferencedProtocols; |
2132 | if (diagnoseSubMismatchProtocols(FirstProtocols, FirstContainer: FirstProtocol, FirstModule, |
2133 | SecondProtocols, SecondContainer: SecondProtocol, |
2134 | SecondModule)) |
2135 | return true; |
2136 | } |
2137 | |
2138 | auto PopulateHashes = [](DeclHashes &Hashes, const ObjCProtocolDecl *ID, |
2139 | const DeclContext *DC) { |
2140 | for (const Decl *D : ID->decls()) { |
2141 | if (!ODRHash::isSubDeclToBeProcessed(D, Parent: DC)) |
2142 | continue; |
2143 | Hashes.emplace_back(Args&: D, Args: computeODRHash(D)); |
2144 | } |
2145 | }; |
2146 | |
2147 | DeclHashes FirstHashes; |
2148 | DeclHashes SecondHashes; |
2149 | // Use definition as DeclContext because definitions are merged when |
2150 | // DeclContexts are merged and separate when DeclContexts are separate. |
2151 | PopulateHashes(FirstHashes, FirstProtocol, FirstProtocol->getDefinition()); |
2152 | PopulateHashes(SecondHashes, SecondProtocol, SecondProtocol->getDefinition()); |
2153 | |
2154 | DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes); |
2155 | ODRMismatchDecl FirstDiffType = DR.FirstDiffType; |
2156 | ODRMismatchDecl SecondDiffType = DR.SecondDiffType; |
2157 | const Decl *FirstDecl = DR.FirstDecl; |
2158 | const Decl *SecondDecl = DR.SecondDecl; |
2159 | |
2160 | if (FirstDiffType == Other || SecondDiffType == Other) { |
2161 | diagnoseSubMismatchUnexpected(DR, FirstRecord: FirstProtocol, FirstModule, |
2162 | SecondRecord: SecondProtocol, SecondModule); |
2163 | return true; |
2164 | } |
2165 | |
2166 | if (FirstDiffType != SecondDiffType) { |
2167 | diagnoseSubMismatchDifferentDeclKinds(DR, FirstRecord: FirstProtocol, FirstModule, |
2168 | SecondRecord: SecondProtocol, SecondModule); |
2169 | return true; |
2170 | } |
2171 | |
2172 | assert(FirstDiffType == SecondDiffType); |
2173 | switch (FirstDiffType) { |
2174 | // Already handled. |
2175 | case EndOfClass: |
2176 | case Other: |
2177 | // Cannot be contained by ObjCProtocolDecl, invalid in this context. |
2178 | case Field: |
2179 | case TypeDef: |
2180 | case Var: |
2181 | case ObjCIvar: |
2182 | // C++ only, invalid in this context. |
2183 | case PublicSpecifer: |
2184 | case PrivateSpecifer: |
2185 | case ProtectedSpecifer: |
2186 | case StaticAssert: |
2187 | case CXXMethod: |
2188 | case TypeAlias: |
2189 | case Friend: |
2190 | case FunctionTemplate: |
2191 | llvm_unreachable("Invalid diff type" ); |
2192 | case ObjCMethod: { |
2193 | if (diagnoseSubMismatchObjCMethod(FirstObjCContainer: FirstProtocol, FirstModule, SecondModule, |
2194 | FirstMethod: cast<ObjCMethodDecl>(Val: FirstDecl), |
2195 | SecondMethod: cast<ObjCMethodDecl>(Val: SecondDecl))) |
2196 | return true; |
2197 | break; |
2198 | } |
2199 | case ObjCProperty: { |
2200 | if (diagnoseSubMismatchObjCProperty(FirstObjCContainer: FirstProtocol, FirstModule, |
2201 | SecondModule, |
2202 | FirstProp: cast<ObjCPropertyDecl>(Val: FirstDecl), |
2203 | SecondProp: cast<ObjCPropertyDecl>(Val: SecondDecl))) |
2204 | return true; |
2205 | break; |
2206 | } |
2207 | } |
2208 | |
2209 | Diag(Loc: FirstDecl->getLocation(), |
2210 | DiagID: diag::err_module_odr_violation_mismatch_decl_unknown) |
2211 | << FirstProtocol << FirstModule.empty() << FirstModule << FirstDiffType |
2212 | << FirstDecl->getSourceRange(); |
2213 | Diag(Loc: SecondDecl->getLocation(), |
2214 | DiagID: diag::note_module_odr_violation_mismatch_decl_unknown) |
2215 | << SecondModule.empty() << SecondModule << FirstDiffType |
2216 | << SecondDecl->getSourceRange(); |
2217 | return true; |
2218 | } |
2219 | |