diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 0669aa1b809c3..34b49963c00ec 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -6755,6 +6755,14 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { Params, TemplatedFD)) return ToFunc; + // Fail if TemplatedFD is already part of a template. + // The template should have been found by structural equivalence check before, + // or ToFunc should be already imported. + // If not, there is AST incompatibility that can be caused by previous import + // errors. (NameConflict is not exact here.) + if (TemplatedFD->getDescribedTemplate()) + return make_error(ASTImportError::NameConflict); + TemplatedFD->setDescribedFunctionTemplate(ToFunc); ToFunc->setAccess(D->getAccess()); diff --git a/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp b/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp new file mode 100644 index 0000000000000..ffe860870a214 --- /dev/null +++ b/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp @@ -0,0 +1,52 @@ +namespace std { +inline namespace __cxx11 { +template +class basic_string; +} +template class basic_istream; +template struct __get_first_arg; +struct allocator_traits { + using type = __get_first_arg; +}; +} // namespace std +namespace std { +inline namespace __cxx11 { +template class basic_string { + allocator_traits _M_allocated_capacity; + void _M_assign(); +}; +} // namespace __cxx11 +} // namespace std +namespace std { +template void operator!=(_Alloc, _CharT); +template +basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &, + basic_string<_CharT, _Traits, _Alloc> &, + _CharT); +} // namespace std +namespace std { +template +void basic_string<_CharT, _Traits, _Alloc>::_M_assign() { + this != 0; +} +template +basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &, + basic_string<_CharT, _Traits, _Alloc> &, + _CharT) {} +} // namespace std +struct CommandLineOptionDefinition { + void *OutAddress; +}; +struct CommandLineCommand { + CommandLineOptionDefinition Options; +}; +namespace CommandLine { +extern const CommandLineCommand RootCommands[]; +extern const int RootExamples[]; +} // namespace CommandLine +using utf8 = char; +using u8string = std::basic_string; +u8string _rct2DataPath; +CommandLineOptionDefinition StandardOptions{&_rct2DataPath}; +const CommandLineCommand CommandLine::RootCommands[]{StandardOptions}; +const int CommandLine::RootExamples[]{}; diff --git a/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp.externalDefMap.ast-dump.txt b/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp.externalDefMap.ast-dump.txt new file mode 100644 index 0000000000000..6ffb3795d3e36 --- /dev/null +++ b/clang/test/Analysis/Inputs/ctu-test-import-failure-import.cpp.externalDefMap.ast-dump.txt @@ -0,0 +1,5 @@ +47:c:@N@std@S@allocator_traits@F@allocator_traits# ctu-test-import-failure-import.cpp.ast +29:c:@N@CommandLine@RootCommands ctu-test-import-failure-import.cpp.ast +55:c:@N@std@N@__cxx11@ST>3#T#T#T@basic_string@F@_M_assign# ctu-test-import-failure-import.cpp.ast +97:c:@S@CommandLineOptionDefinition@F@CommandLineOptionDefinition#&1$@S@CommandLineOptionDefinition# ctu-test-import-failure-import.cpp.ast +29:c:@N@CommandLine@RootExamples ctu-test-import-failure-import.cpp.ast \ No newline at end of file diff --git a/clang/test/Analysis/ctu-test-import-failure.cpp b/clang/test/Analysis/ctu-test-import-failure.cpp new file mode 100644 index 0000000000000..2295a66538fc9 --- /dev/null +++ b/clang/test/Analysis/ctu-test-import-failure.cpp @@ -0,0 +1,34 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: mkdir -p %t/ctudir +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++17 \ +// RUN: -emit-pch -o %t/ctudir/ctu-test-import-failure-import.cpp.ast %S/Inputs/ctu-test-import-failure-import.cpp +// RUN: cp %S/Inputs/ctu-test-import-failure-import.cpp.externalDefMap.ast-dump.txt %t/ctudir/externalDefMap.txt +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++17 -analyze \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \ +// RUN: -analyzer-config ctu-dir=%t/ctudir \ +// RUN: -verify %s + +// Check that importing this code does not cause crash. +// Import intentionally fails because mismatch of '__get_first_arg'. + +namespace std { +inline namespace __cxx11 {} +template class basic_istream; +struct __get_first_arg; +inline namespace __cxx11 { +template class basic_string; +} +template +basic_istream<_CharT, _Traits> &getline(basic_istream<_CharT, _Traits> &, + basic_string<_CharT, _Traits, _Alloc> &, + _CharT) {} +} // namespace std +namespace CommandLine { +extern const int RootExamples[]; +} + +// expected-warning@Inputs/ctu-test-import-failure-import.cpp:14{{incompatible definitions}} +// expected-warning@Inputs/ctu-test-import-failure-import.cpp:14{{incompatible definitions}} +// expected-note@Inputs/ctu-test-import-failure-import.cpp:14{{no corresponding field here}} +// expected-note@Inputs/ctu-test-import-failure-import.cpp:14{{no corresponding field here}}