[clang] 3e7350f - [ODRHash diagnostics] Move `ODRDiagsEmitter` to libAST in separate files. NFC.
Volodymyr Sapsai via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 7 14:41:03 PDT 2022
Author: Volodymyr Sapsai
Date: 2022-09-07T14:40:37-07:00
New Revision: 3e7350f3173b02b3c77917100b2228f1964c55c6
URL: https://github.com/llvm/llvm-project/commit/3e7350f3173b02b3c77917100b2228f1964c55c6
DIFF: https://github.com/llvm/llvm-project/commit/3e7350f3173b02b3c77917100b2228f1964c55c6.diff
LOG: [ODRHash diagnostics] Move `ODRDiagsEmitter` to libAST in separate files. NFC.
Intend to use `ODRDiagsEmitter` during parsing to diagnose a parsed
definition differing from a definition with the same name from a hidden
[sub]module.
Differential Revision: https://reviews.llvm.org/D128695
Added:
clang/include/clang/AST/ODRDiagsEmitter.h
clang/lib/AST/ODRDiagsEmitter.cpp
Modified:
clang/include/clang/Basic/DiagnosticASTKinds.td
clang/include/clang/Basic/DiagnosticSerializationKinds.td
clang/lib/AST/CMakeLists.txt
clang/lib/Serialization/ASTReader.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/AST/ODRDiagsEmitter.h b/clang/include/clang/AST/ODRDiagsEmitter.h
new file mode 100644
index 0000000000000..37e7dd4b05c9d
--- /dev/null
+++ b/clang/include/clang/AST/ODRDiagsEmitter.h
@@ -0,0 +1,127 @@
+//===- ODRDiagsEmitter.h - Emits diagnostic 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_ODRDIAGSEMITTER_H
+#define LLVM_CLANG_AST_ODRDIAGSEMITTER_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+
+namespace clang {
+
+class ODRDiagsEmitter {
+public:
+ ODRDiagsEmitter(DiagnosticsEngine &Diags, const ASTContext &Context,
+ const LangOptions &LangOpts)
+ : Diags(Diags), Context(Context), LangOpts(LangOpts) {}
+
+ /// Diagnose ODR mismatch between 2 FunctionDecl.
+ ///
+ /// Returns true if found a mismatch and diagnosed it.
+ bool diagnoseMismatch(const FunctionDecl *FirstFunction,
+ const FunctionDecl *SecondFunction) const;
+
+ /// Diagnose ODR mismatch between 2 EnumDecl.
+ ///
+ /// Returns true if found a mismatch and diagnosed it.
+ bool diagnoseMismatch(const EnumDecl *FirstEnum,
+ const EnumDecl *SecondEnum) const;
+
+ /// Diagnose ODR mismatch between 2 CXXRecordDecl.
+ ///
+ /// Returns true if found a mismatch and diagnosed it.
+ /// To compare 2 declarations with merged and identical definition data
+ /// you need to provide pre-merge definition data in \p SecondDD.
+ bool
+ diagnoseMismatch(const CXXRecordDecl *FirstRecord,
+ const CXXRecordDecl *SecondRecord,
+ const struct CXXRecordDecl::DefinitionData *SecondDD) const;
+
+ /// Get the best name we know for the module that owns the given
+ /// declaration, or an empty string if the declaration is not from a module.
+ static std::string getOwningModuleNameForDiagnostic(const Decl *D);
+
+private:
+ using DeclHashes = llvm::SmallVector<std::pair<const Decl *, unsigned>, 4>;
+
+ // Used with err_module_odr_violation_mismatch_decl and
+ // note_module_odr_violation_mismatch_decl
+ // This list should be the same Decl's as in ODRHash::isDeclToBeProcessed
+ enum ODRMismatchDecl {
+ EndOfClass,
+ PublicSpecifer,
+ PrivateSpecifer,
+ ProtectedSpecifer,
+ StaticAssert,
+ Field,
+ CXXMethod,
+ TypeAlias,
+ TypeDef,
+ Var,
+ Friend,
+ FunctionTemplate,
+ Other
+ };
+
+ struct DiffResult {
+ const Decl *FirstDecl = nullptr, *SecondDecl = nullptr;
+ ODRMismatchDecl FirstDiffType = Other, SecondDiffType = Other;
+ };
+
+ // If there is a diagnoseable
diff erence, FirstDiffType and
+ // SecondDiffType will not be Other and FirstDecl and SecondDecl will be
+ // filled in if not EndOfClass.
+ static DiffResult FindTypeDiffs(DeclHashes &FirstHashes,
+ DeclHashes &SecondHashes);
+
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const {
+ return Diags.Report(Loc, DiagID);
+ }
+
+ // Use this to diagnose that an unexpected Decl was encountered
+ // or no
diff erence was detected. This causes a generic error
+ // message to be emitted.
+ void diagnoseSubMismatchUnexpected(DiffResult &DR,
+ const NamedDecl *FirstRecord,
+ StringRef FirstModule,
+ const NamedDecl *SecondRecord,
+ StringRef SecondModule) const;
+
+ void diagnoseSubMismatchDifferentDeclKinds(DiffResult &DR,
+ const NamedDecl *FirstRecord,
+ StringRef FirstModule,
+ const NamedDecl *SecondRecord,
+ StringRef SecondModule) const;
+
+ bool diagnoseSubMismatchField(const NamedDecl *FirstRecord,
+ StringRef FirstModule, StringRef SecondModule,
+ const FieldDecl *FirstField,
+ const FieldDecl *SecondField) const;
+
+ bool diagnoseSubMismatchTypedef(const NamedDecl *FirstRecord,
+ StringRef FirstModule, StringRef SecondModule,
+ const TypedefNameDecl *FirstTD,
+ const TypedefNameDecl *SecondTD,
+ bool IsTypeAlias) const;
+
+ bool diagnoseSubMismatchVar(const NamedDecl *FirstRecord,
+ StringRef FirstModule, StringRef SecondModule,
+ const VarDecl *FirstVD,
+ const VarDecl *SecondVD) const;
+
+private:
+ DiagnosticsEngine &Diags;
+ const ASTContext &Context;
+ const LangOptions &LangOpts;
+};
+
+} // namespace clang
+
+#endif
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 02b0cf01aa057..7f47dc8ce0d88 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -566,6 +566,301 @@ def warn_odr_non_type_parameter_type_inconsistent : Warning<
InGroup<ODR>;
def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">;
+// Compare ODR hashes
+def err_module_odr_violation_
diff erent_definitions : Error<
+ "%q0 has
diff erent definitions in
diff erent modules; "
+ "%select{definition in module '%2' is here|defined here}1">;
+def note_first_module_
diff erence : Note<
+ "in first definition, possible
diff erence is here">;
+def note_module_odr_violation_
diff erent_definitions : Note<
+ "definition in module '%0' is here">;
+def note_second_module_
diff erence : Note<
+ "in second definition, possible
diff erence is here">;
+
+def err_module_odr_violation_definition_data : Error <
+ "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "%4 base %plural{1:class|:classes}4|"
+ "%4 virtual base %plural{1:class|:classes}4|"
+ "%ordinal4 base class with type %5|"
+ "%ordinal4 %select{non-virtual|virtual}5 base class %6|"
+ "%ordinal4 base class %5 with "
+ "%select{public|protected|private|no}6 access specifier}3">;
+
+def note_module_odr_violation_definition_data : Note <
+ "but in '%0' found "
+ "%select{"
+ "%2 base %plural{1:class|:classes}2|"
+ "%2 virtual base %plural{1:class|:classes}2|"
+ "%ordinal2 base class with
diff erent type %3|"
+ "%ordinal2 %select{non-virtual|virtual}3 base class %4|"
+ "%ordinal2 base class %3 with "
+ "%select{public|protected|private|no}4 access specifier}1">;
+
+def err_module_odr_violation_template_parameter : Error <
+ "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "unnamed template parameter|"
+ "template parameter %5|"
+ "template parameter with %select{no |}4default argument|"
+ "template parameter with default argument}3">;
+
+def note_module_odr_violation_template_parameter : Note <
+ "but in '%0' found "
+ "%select{"
+ "unnamed template parameter %2|"
+ "template parameter %3|"
+ "template parameter with %select{no |}2default argument|"
+ "template parameter with
diff erent default argument}1">;
+
+def err_module_odr_violation_mismatch_decl : Error<
+ "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{end of class|public access specifier|private access specifier|"
+ "protected access specifier|static assert|field|method|type alias|typedef|"
+ "data member|friend declaration|function template}3">;
+def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found "
+ "%select{end of class|public access specifier|private access specifier|"
+ "protected access specifier|static assert|field|method|type alias|typedef|"
+ "data member|friend declaration|function template}1">;
+
+def err_module_odr_violation_record : Error<
+ "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "static assert with condition|"
+ "static assert with message|"
+ "static assert with %select{|no }4message|"
+ "%select{method %5|constructor|destructor}4|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not deleted|deleted}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not defaulted|defaulted}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{|pure }6%select{not virtual|virtual}7|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not static|static}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not volatile|volatile}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not const|const}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "is %select{not inline|inline}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "that has %6 parameter%s6|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter of type %7%select{| decayed from %9}8|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter named %7|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter with%select{out|}7 a default argument|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %ordinal6 parameter with a default argument|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %select{no |}6template arguments|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %6 template argument%s6|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %6 for %ordinal7 template argument|"
+ "%select{method %5|constructor|destructor}4 "
+ "with %select{no body|body}6|"
+ "%select{method %5|constructor|destructor}4 "
+ "with body|"
+ "friend %select{class|function}4|"
+ "friend %4|"
+ "friend function %4|"
+ "function template %4 with %5 template parameter%s5|"
+ "function template %4 with %ordinal5 template parameter being a "
+ "%select{type|non-type|template}6 template parameter|"
+ "function template %4 with %ordinal5 template parameter "
+ "%select{with no name|named %7}6|"
+ "function template %4 with %ordinal5 template parameter with "
+ "%select{no |}6default argument|"
+ "function template %4 with %ordinal5 template parameter with "
+ "default argument %6|"
+ "function template %4 with %ordinal5 template parameter with one type|"
+ "function template %4 with %ordinal5 template parameter %select{not |}6"
+ "being a template parameter pack|"
+ "}3">;
+
+def note_module_odr_violation_record : Note<"but in '%0' found "
+ "%select{"
+ "static assert with
diff erent condition|"
+ "static assert with
diff erent message|"
+ "static assert with %select{|no }2message|"
+ "%select{method %3|constructor|destructor}2|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not deleted|deleted}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not defaulted|defaulted}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{|pure }4%select{not virtual|virtual}5|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not static|static}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not volatile|volatile}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not const|const}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "is %select{not inline|inline}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "that has %4 parameter%s4|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter of type %5%select{| decayed from %7}6|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter named %5|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter with%select{out|}5 a default argument|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %ordinal4 parameter with a
diff erent default argument|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %select{no |}4template arguments|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %4 template argument%s4|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %4 for %ordinal5 template argument|"
+ "%select{method %3|constructor|destructor}2 "
+ "with %select{no body|body}4|"
+ "%select{method %3|constructor|destructor}2 "
+ "with
diff erent body|"
+ "friend %select{class|function}2|"
+ "friend %2|"
+ "friend function %2|"
+ "function template %2 with %3 template parameter%s3|"
+ "function template %2 with %ordinal3 template paramter being a "
+ "%select{type|non-type|template}4 template parameter|"
+ "function template %2 with %ordinal3 template parameter "
+ "%select{with no name|named %5}4|"
+ "function template %2 with %ordinal3 template parameter with "
+ "%select{no |}4default argument|"
+ "function template %2 with %ordinal3 template parameter with "
+ "default argument %4|"
+ "function template %2 with %ordinal3 template parameter with
diff erent type|"
+ "function template %2 with %ordinal3 template parameter %select{not |}4"
+ "being a template parameter pack|"
+ "}1">;
+
+def err_module_odr_violation_field : Error<
+ "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "field %4|"
+ "field %4 with type %5|"
+ "%select{non-|}5bitfield %4|"
+ "bitfield %4 with one width expression|"
+ "%select{non-|}5mutable field %4|"
+ "field %4 with %select{no|an}5 initalizer|"
+ "field %4 with an initializer"
+ "}3">;
+def note_module_odr_violation_field : Note<"but in '%0' found "
+ "%select{"
+ "field %2|"
+ "field %2 with type %3|"
+ "%select{non-|}3bitfield %2|"
+ "bitfield %2 with
diff erent width expression|"
+ "%select{non-|}3mutable field %2|"
+ "field %2 with %select{no|an}3 initializer|"
+ "field %2 with a
diff erent initializer"
+ "}1">;
+
+def err_module_odr_violation_typedef : Error<
+ "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "%select{typedef|type alias}4 name %5|"
+ "%select{typedef|type alias}4 %5 with underlying type %6"
+ "}3">;
+def note_module_odr_violation_typedef : Note<"but in '%0' found "
+ "%select{"
+ "%select{typedef|type alias}2 name %3|"
+ "%select{typedef|type alias}2 %3 with
diff erent underlying type %4"
+ "}1">;
+
+def err_module_odr_violation_variable : Error<
+ "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
+ "%select{definition in module '%2'|defined here}1 found "
+ "%select{"
+ "data member with name %4|"
+ "data member %4 with type %5|"
+ "data member %4 with%select{out|}5 an initializer|"
+ "data member %4 with an initializer|"
+ "data member %4 %select{is constexpr|is not constexpr}5"
+ "}3">;
+def note_module_odr_violation_variable : Note<"but in '%0' found "
+ "%select{"
+ "data member with name %2|"
+ "data member %2 with
diff erent type %3|"
+ "data member %2 with%select{out|}3 an initializer|"
+ "data member %2 with a
diff erent initializer|"
+ "data member %2 %select{is constexpr|is not constexpr}3"
+ "}1">;
+
+def err_module_odr_violation_function : Error<
+ "%q0 has
diff erent definitions in
diff erent modules; "
+ "%select{definition in module '%2'|defined here}1 "
+ "first
diff erence is "
+ "%select{"
+ "return type is %4|"
+ "%ordinal4 parameter with name %5|"
+ "%ordinal4 parameter with type %5%select{| decayed from %7}6|"
+ "%ordinal4 parameter with%select{out|}5 a default argument|"
+ "%ordinal4 parameter with a default argument|"
+ "function body"
+ "}3">;
+
+def note_module_odr_violation_function : Note<"but in '%0' found "
+ "%select{"
+ "
diff erent return type %2|"
+ "%ordinal2 parameter with name %3|"
+ "%ordinal2 parameter with type %3%select{| decayed from %5}4|"
+ "%ordinal2 parameter with%select{out|}3 a default argument|"
+ "%ordinal2 parameter with a
diff erent default argument|"
+ "a
diff erent body"
+ "}1">;
+
+def err_module_odr_violation_enum : Error<
+ "%q0 has
diff erent definitions in
diff erent modules; "
+ "%select{definition in module '%2'|defined here}1 "
+ "first
diff erence is "
+ "%select{"
+ "enum that is %select{not scoped|scoped}4|"
+ "enum scoped with keyword %select{struct|class}4|"
+ "enum %select{without|with}4 specified type|"
+ "enum with specified type %4|"
+ "enum with %4 element%s4|"
+ "%ordinal4 element has name %5|"
+ "%ordinal4 element %5 %select{has|does not have}6 an initializer|"
+ "%ordinal4 element %5 has an initializer|"
+ "}3">;
+
+def note_module_odr_violation_enum : Note<"but in '%0' found "
+ "%select{"
+ "enum that is %select{not scoped|scoped}2|"
+ "enum scoped with keyword %select{struct|class}2|"
+ "enum %select{without|with}2 specified type|"
+ "enum with specified type %2|"
+ "enum with %2 element%s2|"
+ "%ordinal2 element has name %3|"
+ "%ordinal2 element %3 %select{has|does not have}4 an initializer|"
+ "%ordinal2 element %3 has
diff erent initializer|"
+ "}1">;
+
+def err_module_odr_violation_mismatch_decl_unknown : Error<
+ "%q0 %select{with definition in module '%2'|defined here}1 has
diff erent "
+ "definitions in
diff erent modules; first
diff erence is this "
+ "%select{||||static assert|field|method|type alias|typedef|data member|"
+ "friend declaration|function template|"
+ "unexpected decl}3">;
+def note_module_odr_violation_mismatch_decl_unknown : Note<
+ "but in '%0' found "
+ "%select{||||
diff erent static assert|
diff erent field|
diff erent method|"
+ "
diff erent type alias|
diff erent typedef|
diff erent data member|"
+ "
diff erent friend declaration|
diff erent function template|"
+ "another unexpected decl}1">;
+
+
def remark_sanitize_address_insert_extra_padding_accepted : Remark<
"-fsanitize-address-field-padding applied to %0">, ShowInSystemHeader,
InGroup<SanitizeAddressRemarks>;
diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td
index 0bd3734a4a049..f515ea0d9f6dd 100644
--- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -115,302 +115,10 @@ def note_module_odr_violation_no_possible_decls : Note<
"definition has no member %0">;
def note_module_odr_violation_possible_decl : Note<
"declaration of %0 does not match">;
-def err_module_odr_violation_
diff erent_definitions : Error<
- "%q0 has
diff erent definitions in
diff erent modules; "
- "%select{definition in module '%2' is here|defined here}1">;
-def note_first_module_
diff erence : Note<
- "in first definition, possible
diff erence is here">;
-def note_module_odr_violation_
diff erent_definitions : Note<
- "definition in module '%0' is here">;
-def note_second_module_
diff erence : Note<
- "in second definition, possible
diff erence is here">;
def err_module_odr_violation_
diff erent_instantiations : Error<
"instantiation of %q0 is
diff erent in
diff erent modules">;
-def err_module_odr_violation_definition_data : Error <
- "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
- "%select{definition in module '%2'|defined here}1 found "
- "%select{"
- "%4 base %plural{1:class|:classes}4|"
- "%4 virtual base %plural{1:class|:classes}4|"
- "%ordinal4 base class with type %5|"
- "%ordinal4 %select{non-virtual|virtual}5 base class %6|"
- "%ordinal4 base class %5 with "
- "%select{public|protected|private|no}6 access specifier}3">;
-
-def note_module_odr_violation_definition_data : Note <
- "but in '%0' found "
- "%select{"
- "%2 base %plural{1:class|:classes}2|"
- "%2 virtual base %plural{1:class|:classes}2|"
- "%ordinal2 base class with
diff erent type %3|"
- "%ordinal2 %select{non-virtual|virtual}3 base class %4|"
- "%ordinal2 base class %3 with "
- "%select{public|protected|private|no}4 access specifier}1">;
-
-def err_module_odr_violation_template_parameter : Error <
- "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
- "%select{definition in module '%2'|defined here}1 found "
- "%select{"
- "unnamed template parameter|"
- "template parameter %5|"
- "template parameter with %select{no |}4default argument|"
- "template parameter with default argument}3">;
-
-def note_module_odr_violation_template_parameter : Note <
- "but in '%0' found "
- "%select{"
- "unnamed template parameter %2|"
- "template parameter %3|"
- "template parameter with %select{no |}2default argument|"
- "template parameter with
diff erent default argument}1">;
-
-def err_module_odr_violation_mismatch_decl : Error<
- "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
- "%select{definition in module '%2'|defined here}1 found "
- "%select{end of class|public access specifier|private access specifier|"
- "protected access specifier|static assert|field|method|type alias|typedef|"
- "data member|friend declaration|function template}3">;
-def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found "
- "%select{end of class|public access specifier|private access specifier|"
- "protected access specifier|static assert|field|method|type alias|typedef|"
- "data member|friend declaration|function template}1">;
-
-def err_module_odr_violation_record : Error<
- "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
- "%select{definition in module '%2'|defined here}1 found "
- "%select{"
- "static assert with condition|"
- "static assert with message|"
- "static assert with %select{|no }4message|"
- "%select{method %5|constructor|destructor}4|"
- "%select{method %5|constructor|destructor}4 "
- "is %select{not deleted|deleted}6|"
- "%select{method %5|constructor|destructor}4 "
- "is %select{not defaulted|defaulted}6|"
- "%select{method %5|constructor|destructor}4 "
- "is %select{|pure }6%select{not virtual|virtual}7|"
- "%select{method %5|constructor|destructor}4 "
- "is %select{not static|static}6|"
- "%select{method %5|constructor|destructor}4 "
- "is %select{not volatile|volatile}6|"
- "%select{method %5|constructor|destructor}4 "
- "is %select{not const|const}6|"
- "%select{method %5|constructor|destructor}4 "
- "is %select{not inline|inline}6|"
- "%select{method %5|constructor|destructor}4 "
- "that has %6 parameter%s6|"
- "%select{method %5|constructor|destructor}4 "
- "with %ordinal6 parameter of type %7%select{| decayed from %9}8|"
- "%select{method %5|constructor|destructor}4 "
- "with %ordinal6 parameter named %7|"
- "%select{method %5|constructor|destructor}4 "
- "with %ordinal6 parameter with%select{out|}7 a default argument|"
- "%select{method %5|constructor|destructor}4 "
- "with %ordinal6 parameter with a default argument|"
- "%select{method %5|constructor|destructor}4 "
- "with %select{no |}6template arguments|"
- "%select{method %5|constructor|destructor}4 "
- "with %6 template argument%s6|"
- "%select{method %5|constructor|destructor}4 "
- "with %6 for %ordinal7 template argument|"
- "%select{method %5|constructor|destructor}4 "
- "with %select{no body|body}6|"
- "%select{method %5|constructor|destructor}4 "
- "with body|"
- "friend %select{class|function}4|"
- "friend %4|"
- "friend function %4|"
- "function template %4 with %5 template parameter%s5|"
- "function template %4 with %ordinal5 template parameter being a "
- "%select{type|non-type|template}6 template parameter|"
- "function template %4 with %ordinal5 template parameter "
- "%select{with no name|named %7}6|"
- "function template %4 with %ordinal5 template parameter with "
- "%select{no |}6default argument|"
- "function template %4 with %ordinal5 template parameter with "
- "default argument %6|"
- "function template %4 with %ordinal5 template parameter with one type|"
- "function template %4 with %ordinal5 template parameter %select{not |}6"
- "being a template parameter pack|"
- "}3">;
-
-def note_module_odr_violation_record : Note<"but in '%0' found "
- "%select{"
- "static assert with
diff erent condition|"
- "static assert with
diff erent message|"
- "static assert with %select{|no }2message|"
- "%select{method %3|constructor|destructor}2|"
- "%select{method %3|constructor|destructor}2 "
- "is %select{not deleted|deleted}4|"
- "%select{method %3|constructor|destructor}2 "
- "is %select{not defaulted|defaulted}4|"
- "%select{method %3|constructor|destructor}2 "
- "is %select{|pure }4%select{not virtual|virtual}5|"
- "%select{method %3|constructor|destructor}2 "
- "is %select{not static|static}4|"
- "%select{method %3|constructor|destructor}2 "
- "is %select{not volatile|volatile}4|"
- "%select{method %3|constructor|destructor}2 "
- "is %select{not const|const}4|"
- "%select{method %3|constructor|destructor}2 "
- "is %select{not inline|inline}4|"
- "%select{method %3|constructor|destructor}2 "
- "that has %4 parameter%s4|"
- "%select{method %3|constructor|destructor}2 "
- "with %ordinal4 parameter of type %5%select{| decayed from %7}6|"
- "%select{method %3|constructor|destructor}2 "
- "with %ordinal4 parameter named %5|"
- "%select{method %3|constructor|destructor}2 "
- "with %ordinal4 parameter with%select{out|}5 a default argument|"
- "%select{method %3|constructor|destructor}2 "
- "with %ordinal4 parameter with a
diff erent default argument|"
- "%select{method %3|constructor|destructor}2 "
- "with %select{no |}4template arguments|"
- "%select{method %3|constructor|destructor}2 "
- "with %4 template argument%s4|"
- "%select{method %3|constructor|destructor}2 "
- "with %4 for %ordinal5 template argument|"
- "%select{method %3|constructor|destructor}2 "
- "with %select{no body|body}4|"
- "%select{method %3|constructor|destructor}2 "
- "with
diff erent body|"
- "friend %select{class|function}2|"
- "friend %2|"
- "friend function %2|"
- "function template %2 with %3 template parameter%s3|"
- "function template %2 with %ordinal3 template paramter being a "
- "%select{type|non-type|template}4 template parameter|"
- "function template %2 with %ordinal3 template parameter "
- "%select{with no name|named %5}4|"
- "function template %2 with %ordinal3 template parameter with "
- "%select{no |}4default argument|"
- "function template %2 with %ordinal3 template parameter with "
- "default argument %4|"
- "function template %2 with %ordinal3 template parameter with
diff erent type|"
- "function template %2 with %ordinal3 template parameter %select{not |}4"
- "being a template parameter pack|"
- "}1">;
-
-def err_module_odr_violation_field : Error<
- "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
- "%select{definition in module '%2'|defined here}1 found "
- "%select{"
- "field %4|"
- "field %4 with type %5|"
- "%select{non-|}5bitfield %4|"
- "bitfield %4 with one width expression|"
- "%select{non-|}5mutable field %4|"
- "field %4 with %select{no|an}5 initalizer|"
- "field %4 with an initializer"
- "}3">;
-def note_module_odr_violation_field : Note<"but in '%0' found "
- "%select{"
- "field %2|"
- "field %2 with type %3|"
- "%select{non-|}3bitfield %2|"
- "bitfield %2 with
diff erent width expression|"
- "%select{non-|}3mutable field %2|"
- "field %2 with %select{no|an}3 initializer|"
- "field %2 with a
diff erent initializer"
- "}1">;
-
-def err_module_odr_violation_typedef : Error<
- "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
- "%select{definition in module '%2'|defined here}1 found "
- "%select{"
- "%select{typedef|type alias}4 name %5|"
- "%select{typedef|type alias}4 %5 with underlying type %6"
- "}3">;
-def note_module_odr_violation_typedef : Note<"but in '%0' found "
- "%select{"
- "%select{typedef|type alias}2 name %3|"
- "%select{typedef|type alias}2 %3 with
diff erent underlying type %4"
- "}1">;
-
-def err_module_odr_violation_variable : Error<
- "%q0 has
diff erent definitions in
diff erent modules; first
diff erence is "
- "%select{definition in module '%2'|defined here}1 found "
- "%select{"
- "data member with name %4|"
- "data member %4 with type %5|"
- "data member %4 with%select{out|}5 an initializer|"
- "data member %4 with an initializer|"
- "data member %4 %select{is constexpr|is not constexpr}5"
- "}3">;
-def note_module_odr_violation_variable : Note<"but in '%0' found "
- "%select{"
- "data member with name %2|"
- "data member %2 with
diff erent type %3|"
- "data member %2 with%select{out|}3 an initializer|"
- "data member %2 with a
diff erent initializer|"
- "data member %2 %select{is constexpr|is not constexpr}3"
- "}1">;
-
-def err_module_odr_violation_function : Error<
- "%q0 has
diff erent definitions in
diff erent modules; "
- "%select{definition in module '%2'|defined here}1 "
- "first
diff erence is "
- "%select{"
- "return type is %4|"
- "%ordinal4 parameter with name %5|"
- "%ordinal4 parameter with type %5%select{| decayed from %7}6|"
- "%ordinal4 parameter with%select{out|}5 a default argument|"
- "%ordinal4 parameter with a default argument|"
- "function body"
- "}3">;
-
-def note_module_odr_violation_function : Note<"but in '%0' found "
- "%select{"
- "
diff erent return type %2|"
- "%ordinal2 parameter with name %3|"
- "%ordinal2 parameter with type %3%select{| decayed from %5}4|"
- "%ordinal2 parameter with%select{out|}3 a default argument|"
- "%ordinal2 parameter with a
diff erent default argument|"
- "a
diff erent body"
- "}1">;
-
-def err_module_odr_violation_enum : Error<
- "%q0 has
diff erent definitions in
diff erent modules; "
- "%select{definition in module '%2'|defined here}1 "
- "first
diff erence is "
- "%select{"
- "enum that is %select{not scoped|scoped}4|"
- "enum scoped with keyword %select{struct|class}4|"
- "enum %select{without|with}4 specified type|"
- "enum with specified type %4|"
- "enum with %4 element%s4|"
- "%ordinal4 element has name %5|"
- "%ordinal4 element %5 %select{has|does not have}6 an initializer|"
- "%ordinal4 element %5 has an initializer|"
- "}3">;
-
-def note_module_odr_violation_enum : Note<"but in '%0' found "
- "%select{"
- "enum that is %select{not scoped|scoped}2|"
- "enum scoped with keyword %select{struct|class}2|"
- "enum %select{without|with}2 specified type|"
- "enum with specified type %2|"
- "enum with %2 element%s2|"
- "%ordinal2 element has name %3|"
- "%ordinal2 element %3 %select{has|does not have}4 an initializer|"
- "%ordinal2 element %3 has
diff erent initializer|"
- "}1">;
-
-def err_module_odr_violation_mismatch_decl_unknown : Error<
- "%q0 %select{with definition in module '%2'|defined here}1 has
diff erent "
- "definitions in
diff erent modules; first
diff erence is this "
- "%select{||||static assert|field|method|type alias|typedef|data member|"
- "friend declaration|function template|"
- "unexpected decl}3">;
-def note_module_odr_violation_mismatch_decl_unknown : Note<
- "but in '%0' found "
- "%select{||||
diff erent static assert|
diff erent field|
diff erent method|"
- "
diff erent type alias|
diff erent typedef|
diff erent data member|"
- "
diff erent friend declaration|
diff erent function template|"
- "another unexpected decl}1">;
-
def warn_duplicate_module_file_extension : Warning<
"duplicate module file extension block name '%0'">,
InGroup<ModuleFileExtension>;
diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index 24c8cb89c7ff6..fc7921788943d 100644
--- a/clang/lib/AST/CMakeLists.txt
+++ b/clang/lib/AST/CMakeLists.txt
@@ -91,6 +91,7 @@ add_clang_library(clangAST
MicrosoftMangle.cpp
NestedNameSpecifier.cpp
NSAPI.cpp
+ ODRDiagsEmitter.cpp
ODRHash.cpp
OpenMPClause.cpp
OSLog.cpp
diff --git a/clang/lib/AST/ODRDiagsEmitter.cpp b/clang/lib/AST/ODRDiagsEmitter.cpp
new file mode 100644
index 0000000000000..ac66f50a558fd
--- /dev/null
+++ b/clang/lib/AST/ODRDiagsEmitter.cpp
@@ -0,0 +1,1535 @@
+//===-- 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 {};
+}
+
+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 << SecondField->getSourceRange() << DiffType;
+ };
+
+ IdentifierInfo *FirstII = FirstField->getIdentifier();
+ IdentifierInfo *SecondII = SecondField->getIdentifier();
+ if (FirstII->getName() != SecondII->getName()) {
+ DiagError(FieldName) << FirstII;
+ DiagNote(FieldName) << SecondII;
+ return true;
+ }
+
+ assert(Context.hasSameType(FirstField->getType(), SecondField->getType()));
+ (void)Context;
+
+ QualType FirstType = FirstField->getType();
+ QualType SecondType = SecondField->getType();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagError(FieldTypeName) << FirstII << FirstType;
+ DiagNote(FieldTypeName) << SecondII << SecondType;
+ return true;
+ }
+
+ 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;
+}
+
+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;
+ }
+ };
+
+ 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_
diff erent_definitions)
+ << FirstRecord << FirstModule.empty() << FirstModule;
+
+ if (DR.FirstDecl) {
+ Diag(DR.FirstDecl->getLocation(), diag::note_first_module_
diff erence)
+ << FirstRecord << DR.FirstDecl->getSourceRange();
+ }
+
+ Diag(SecondRecord->getLocation(),
+ diag::note_module_odr_violation_
diff erent_definitions)
+ << SecondModule;
+
+ if (DR.SecondDecl) {
+ Diag(DR.SecondDecl->getLocation(), diag::note_second_module_
diff erence)
+ << 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;
+ auto *Tag = dyn_cast<TagDecl>(Container);
+ if (DiffType == EndOfClass && Tag) {
+ Loc = Tag->getBraceRange().getEnd();
+ } 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 << SecondDiagInfo.second << DR.SecondDiffType;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(
+ const CXXRecordDecl *FirstRecord, const CXXRecordDecl *SecondRecord,
+ const struct CXXRecordDecl::DefinitionData *SecondDD) const {
+ // Multiple
diff erent 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::isDeclToBeProcessed(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,
+ MethodNumberParameters,
+ MethodParameterType,
+ MethodParameterName,
+ 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:
+ 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;
+ }
+
+ const unsigned FirstNumParameters = FirstMethod->param_size();
+ const unsigned SecondNumParameters = SecondMethod->param_size();
+ if (FirstNumParameters != SecondNumParameters) {
+ DiagMethodError(MethodNumberParameters) << FirstNumParameters;
+ DiagMethodNote(MethodNumberParameters) << 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>()) {
+ DiagMethodError(MethodParameterType)
+ << (I + 1) << FirstParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagMethodError(MethodParameterType)
+ << (I + 1) << FirstParamType << false;
+ }
+
+ if (const DecayedType *ParamDecayedType =
+ SecondParamType->getAs<DecayedType>()) {
+ DiagMethodNote(MethodParameterType)
+ << (I + 1) << SecondParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagMethodNote(MethodParameterType)
+ << (I + 1) << SecondParamType << false;
+ }
+ return true;
+ }
+
+ DeclarationName FirstParamName = FirstParam->getDeclName();
+ DeclarationName SecondParamName = SecondParam->getDeclName();
+ if (FirstParamName != SecondParamName) {
+ DiagMethodError(MethodParameterName) << (I + 1) << FirstParamName;
+ DiagMethodNote(MethodParameterName) << (I + 1) << SecondParamName;
+ return true;
+ }
+
+ 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
diff erence 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 << 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
diff erent 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
diff erent 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
diff erence.");
+ }
+
+ // 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::isDeclToBeProcessed(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;
+}
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 568d948b541e5..2196a82604e9c 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -30,6 +30,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/NestedNameSpecifier.h"
+#include "clang/AST/ODRDiagsEmitter.h"
#include "clang/AST/ODRHash.h"
#include "clang/AST/OpenMPClause.h"
#include "clang/AST/RawCommentList.h"
@@ -9433,148 +9434,6 @@ void ASTReader::finishPendingActions() {
PendingMergedDefinitionsToDeduplicate.clear();
}
-namespace clang {
-class ODRDiagsEmitter {
-public:
- ODRDiagsEmitter(DiagnosticsEngine &Diags, const ASTContext &Context,
- const LangOptions &LangOpts)
- : Diags(Diags), Context(Context), LangOpts(LangOpts) {}
-
- /// Diagnose ODR mismatch between 2 FunctionDecl.
- ///
- /// Returns true if found a mismatch and diagnosed it.
- bool diagnoseMismatch(const FunctionDecl *FirstFunction,
- const FunctionDecl *SecondFunction) const;
-
- /// Diagnose ODR mismatch between 2 EnumDecl.
- ///
- /// Returns true if found a mismatch and diagnosed it.
- bool diagnoseMismatch(const EnumDecl *FirstEnum,
- const EnumDecl *SecondEnum) const;
-
- /// Diagnose ODR mismatch between 2 CXXRecordDecl.
- ///
- /// Returns true if found a mismatch and diagnosed it.
- /// To compare 2 declarations with merged and identical definition data
- /// you need to provide pre-merge definition data in \p SecondDD.
- bool
- diagnoseMismatch(const CXXRecordDecl *FirstRecord,
- const CXXRecordDecl *SecondRecord,
- const struct CXXRecordDecl::DefinitionData *SecondDD) const;
-
- /// Get the best name we know for the module that owns the given
- /// declaration, or an empty string if the declaration is not from a module.
- static std::string getOwningModuleNameForDiagnostic(const Decl *D);
-
-private:
- using DeclHashes = llvm::SmallVector<std::pair<const Decl *, unsigned>, 4>;
-
- // Used with err_module_odr_violation_mismatch_decl and
- // note_module_odr_violation_mismatch_decl
- // This list should be the same Decl's as in ODRHash::isDeclToBeProcessed
- enum ODRMismatchDecl {
- EndOfClass,
- PublicSpecifer,
- PrivateSpecifer,
- ProtectedSpecifer,
- StaticAssert,
- Field,
- CXXMethod,
- TypeAlias,
- TypeDef,
- Var,
- Friend,
- FunctionTemplate,
- Other
- };
-
- struct DiffResult {
- const Decl *FirstDecl = nullptr, *SecondDecl = nullptr;
- ODRMismatchDecl FirstDiffType = Other, SecondDiffType = Other;
- };
-
- // If there is a diagnoseable
diff erence, FirstDiffType and
- // SecondDiffType will not be Other and FirstDecl and SecondDecl will be
- // filled in if not EndOfClass.
- static DiffResult FindTypeDiffs(DeclHashes &FirstHashes,
- DeclHashes &SecondHashes);
-
- DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const {
- return Diags.Report(Loc, DiagID);
- }
-
- // Use this to diagnose that an unexpected Decl was encountered
- // or no
diff erence was detected. This causes a generic error
- // message to be emitted.
- void diagnoseSubMismatchUnexpected(DiffResult &DR,
- const NamedDecl *FirstRecord,
- StringRef FirstModule,
- const NamedDecl *SecondRecord,
- StringRef SecondModule) const;
-
- void diagnoseSubMismatchDifferentDeclKinds(DiffResult &DR,
- const NamedDecl *FirstRecord,
- StringRef FirstModule,
- const NamedDecl *SecondRecord,
- StringRef SecondModule) const;
-
- bool diagnoseSubMismatchField(const NamedDecl *FirstRecord,
- StringRef FirstModule, StringRef SecondModule,
- const FieldDecl *FirstField,
- const FieldDecl *SecondField) const;
-
- bool diagnoseSubMismatchTypedef(const NamedDecl *FirstRecord,
- StringRef FirstModule, StringRef SecondModule,
- const TypedefNameDecl *FirstTD,
- const TypedefNameDecl *SecondTD,
- bool IsTypeAlias) const;
-
- bool diagnoseSubMismatchVar(const NamedDecl *FirstRecord,
- StringRef FirstModule, StringRef SecondModule,
- const VarDecl *FirstVD,
- const VarDecl *SecondVD) const;
-
-private:
- DiagnosticsEngine &Diags;
- const ASTContext &Context;
- const LangOptions &LangOpts;
-};
-} // 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 {};
-}
-
void ASTReader::diagnoseOdrViolations() {
if (PendingOdrMergeFailures.empty() && PendingOdrMergeChecks.empty() &&
PendingFunctionOdrMergeFailures.empty() &&
@@ -9781,1527 +9640,6 @@ void ASTReader::diagnoseOdrViolations() {
}
}
-// clang-format off
- 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 << SecondField->getSourceRange() << DiffType;
- };
-
- IdentifierInfo *FirstII = FirstField->getIdentifier();
- IdentifierInfo *SecondII = SecondField->getIdentifier();
- if (FirstII->getName() != SecondII->getName()) {
- DiagError(FieldName) << FirstII;
- DiagNote(FieldName) << SecondII;
- return true;
- }
-
- assert(Context.hasSameType(FirstField->getType(), SecondField->getType()));
- (void)Context;
-
- QualType FirstType = FirstField->getType();
- QualType SecondType = SecondField->getType();
- if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
- DiagError(FieldTypeName) << FirstII << FirstType;
- DiagNote(FieldTypeName) << SecondII << SecondType;
- return true;
- }
-
- 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;
- }
-
- 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;
- }
- };
-
- 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_
diff erent_definitions)
- << FirstRecord << FirstModule.empty() << FirstModule;
-
- if (DR.FirstDecl) {
- Diag(DR.FirstDecl->getLocation(), diag::note_first_module_
diff erence)
- << FirstRecord << DR.FirstDecl->getSourceRange();
- }
-
- Diag(SecondRecord->getLocation(),
- diag::note_module_odr_violation_
diff erent_definitions)
- << SecondModule;
-
- if (DR.SecondDecl) {
- Diag(DR.SecondDecl->getLocation(), diag::note_second_module_
diff erence)
- << 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;
- auto *Tag = dyn_cast<TagDecl>(Container);
- if (DiffType == EndOfClass && Tag) {
- Loc = Tag->getBraceRange().getEnd();
- } 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 << SecondDiagInfo.second << DR.SecondDiffType;
- }
-
- bool ODRDiagsEmitter::diagnoseMismatch(
- const CXXRecordDecl *FirstRecord, const CXXRecordDecl *SecondRecord,
- const struct CXXRecordDecl::DefinitionData *SecondDD) const {
- // Multiple
diff erent 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::isDeclToBeProcessed(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,
- MethodNumberParameters,
- MethodParameterType,
- MethodParameterName,
- 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:
- 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;
- }
-
- const unsigned FirstNumParameters = FirstMethod->param_size();
- const unsigned SecondNumParameters = SecondMethod->param_size();
- if (FirstNumParameters != SecondNumParameters) {
- DiagMethodError(MethodNumberParameters) << FirstNumParameters;
- DiagMethodNote(MethodNumberParameters) << 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>()) {
- DiagMethodError(MethodParameterType)
- << (I + 1) << FirstParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- DiagMethodError(MethodParameterType)
- << (I + 1) << FirstParamType << false;
- }
-
- if (const DecayedType *ParamDecayedType =
- SecondParamType->getAs<DecayedType>()) {
- DiagMethodNote(MethodParameterType)
- << (I + 1) << SecondParamType << true
- << ParamDecayedType->getOriginalType();
- } else {
- DiagMethodNote(MethodParameterType)
- << (I + 1) << SecondParamType << false;
- }
- return true;
- }
-
- DeclarationName FirstParamName = FirstParam->getDeclName();
- DeclarationName SecondParamName = SecondParam->getDeclName();
- if (FirstParamName != SecondParamName) {
- DiagMethodError(MethodParameterName) << (I + 1) << FirstParamName;
- DiagMethodNote(MethodParameterName) << (I + 1) << SecondParamName;
- return true;
- }
-
- 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
diff erence 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 << 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
diff erent 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
diff erent 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
diff erence.");
- }
-
- // 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::isDeclToBeProcessed(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;
-}
-// clang-format on
-
void ASTReader::StartedDeserializing() {
if (++NumCurrentElementsDeserializing == 1 && ReadTimer.get())
ReadTimer->startTimer();
More information about the cfe-commits
mailing list