diff --git a/clang/unittests/AST/ASTImporterODRStrategiesTest.cpp b/clang/unittests/AST/ASTImporterODRStrategiesTest.cpp new file mode 100644 --- /dev/null +++ b/clang/unittests/AST/ASTImporterODRStrategiesTest.cpp @@ -0,0 +1,670 @@ +//===- unittest/AST/ASTImporterODRStrategiesTest.cpp -----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Type-parameterized tests to verify the import behaviour in case of ODR +// violation. +// +//===----------------------------------------------------------------------===// + +#include "ASTImporterFixtures.h" + +namespace clang { +namespace ast_matchers { + +using internal::BindableMatcher; + +// DeclTy: Type of the Decl to check. +// Prototype: "Prototype" (forward declaration) of the Decl. +// Definition: A definition for the Prototype. +// ConflictingPrototype: A prototype with the same name but different +// declaration. +// ConflictingDefinition: A different definition for Prototype. +// ConflictingProtoDef: A definition for ConflictingPrototype. +// getPattern: Return a matcher that matches any of Prototype, Definition, +// ConflictingPrototype, ConflictingDefinition, ConflictingProtoDef. + +struct Function { + using DeclTy = FunctionDecl; + static constexpr auto *Prototype = "void X(int);"; + static constexpr auto *ConflictingPrototype = "void X(double);"; + static constexpr auto *Definition = "void X(int a) {}"; + static constexpr auto *ConflictingDefinition = "void X(double a) {}"; + BindableMatcher getPattern() { + return functionDecl(hasName("X"), unless(isImplicit())); + } + Language getLang() { return Lang_C; } +}; + +struct Typedef { + using DeclTy = TypedefNameDecl; + static constexpr auto *Definition = "typedef int X;"; + static constexpr auto *ConflictingDefinition = "typedef double X;"; + BindableMatcher getPattern() { return typedefNameDecl(hasName("X")); } + Language getLang() { return Lang_CXX; } +}; + +struct TypedefAlias { + using DeclTy = TypedefNameDecl; + static constexpr auto *Definition = "using X = int;"; + static constexpr auto *ConflictingDefinition = "using X = double;"; + BindableMatcher getPattern() { return typedefNameDecl(hasName("X")); } + Language getLang() { return Lang_CXX11; } +}; + +struct Enum { + using DeclTy = EnumDecl; + static constexpr auto *Definition = "enum X { a, b };"; + static constexpr auto *ConflictingDefinition = "enum X { a, b, c };"; + BindableMatcher getPattern() { return enumDecl(hasName("X")); } + Language getLang() { return Lang_CXX; } +}; + +struct EnumConstant { + using DeclTy = EnumConstantDecl; + static constexpr auto *Definition = "enum E { X = 0 };"; + static constexpr auto *ConflictingDefinition = "enum E { X = 1 };"; + BindableMatcher getPattern() { return enumConstantDecl(hasName("X")); } + Language getLang() { return Lang_CXX; } +}; + +struct Class { + using DeclTy = CXXRecordDecl; + static constexpr auto *Prototype = "class X;"; + static constexpr auto *Definition = "class X {};"; + static constexpr auto *ConflictingDefinition = "class X { int A; };"; + BindableMatcher getPattern() { + return cxxRecordDecl(hasName("X"), unless(isImplicit())); + } + Language getLang() { return Lang_CXX; } +}; + +struct Variable { + using DeclTy = VarDecl; + static constexpr auto *Prototype = "extern int X;"; + static constexpr auto *ConflictingPrototype = "extern float X;"; + static constexpr auto *Definition = "int X;"; + static constexpr auto *ConflictingDefinition = "float X;"; + BindableMatcher getPattern() { return varDecl(hasName("X")); } + Language getLang() { return Lang_CXX; } +}; + +struct ClassTemplate { + using DeclTy = ClassTemplateDecl; + static constexpr auto *Prototype = "template class X;"; + static constexpr auto *ConflictingPrototype = "template class X;"; + static constexpr auto *Definition = "template class X {};"; + static constexpr auto *ConflictingDefinition = + "template class X { int A; };"; + static constexpr auto *ConflictingProtoDef = "template class X { };"; + BindableMatcher getPattern() { + return classTemplateDecl(hasName("X"), unless(isImplicit())); + } + Language getLang() { return Lang_CXX; } +}; + +struct FunctionTemplate { + using DeclTy = FunctionTemplateDecl; + static constexpr auto *Definition0 = + R"( + template + void X(T a) {}; + )"; + // This is actually not a conflicting definition, but another primary template. + static constexpr auto *Definition1 = + R"( + template + void X(T* a) {}; + )"; + BindableMatcher getPattern() { + return functionTemplateDecl(hasName("X"), unless(isImplicit())); + } + static std::string getDef0() { return Definition0; } + static std::string getDef1() { return Definition1; } + Language getLang() { return Lang_CXX; } +}; + +static const internal::VariadicDynCastAllOfMatcher + varTemplateDecl; + +struct VarTemplate { + using DeclTy = VarTemplateDecl; + static constexpr auto *Definition = + R"( + template + constexpr T X = 0; + )"; + static constexpr auto *ConflictingDefinition = + R"( + template + constexpr int X = 0; + )"; + BindableMatcher getPattern() { return varTemplateDecl(hasName("X")); } + Language getLang() { return Lang_CXX14; } +}; + +struct ClassTemplateSpec { + using DeclTy = ClassTemplateSpecializationDecl; + static constexpr auto *Prototype = + R"( + template class X; + template <> class X; + )"; + static constexpr auto *Definition = + R"( + template class X; + template <> class X {}; + )"; + static constexpr auto *ConflictingDefinition = + R"( + template class X; + template <> class X { int A; }; + )"; + BindableMatcher getPattern() { + return classTemplateSpecializationDecl(hasName("X"), unless(isImplicit())); + } + Language getLang() { return Lang_CXX; } +}; + +// Function template specializations are all "full" specializations. +// Structural equivalency does not check the body of functions, so we cannot +// create conflicting function template specializations. +struct FunctionTemplateSpec { + using DeclTy = FunctionDecl; + + static constexpr auto *Definition0 = + R"( + template + void X(T a); + template <> void X(int a) {}; + )"; + + // This is actually not a conflicting definition, but another full + // specialization. + // Thus, during the import we would create a new specialization with a + // different type argument. + static constexpr auto *Definition1 = + R"( + template + void X(T a); + template <> void X(double a) {}; + )"; + + BindableMatcher getPattern() { + return functionDecl(hasName("X"), isExplicitTemplateSpecialization(), + unless(isImplicit())); + } + static std::string getDef0() { return Definition0; } + static std::string getDef1() { return Definition1; } + Language getLang() { return Lang_CXX; } +}; + +static const internal::VariadicDynCastAllOfMatcher< + Decl, VarTemplateSpecializationDecl> + varTemplateSpecializationDecl; + +struct VarTemplateSpec { + using DeclTy = VarTemplateSpecializationDecl; + static constexpr auto *Definition = + R"( + template T X = 0; + template <> int X = 0; + )"; + static constexpr auto *ConflictingDefinition = + R"( + template T X = 0; + template <> float X = 1.0; + )"; + BindableMatcher getPattern() { + return varTemplateSpecializationDecl(hasName("X"), unless(isImplicit())); + } + Language getLang() { return Lang_CXX14; } +}; + +template +struct ODRViolation : ASTImporterOptionSpecificTestBase { + + using DeclTy = typename TypeParam::DeclTy; + + ODRViolation() { ODRHandling = ODRHandlingParam; } + + static std::string getPrototype() { return TypeParam::Prototype; } + static std::string getConflictingPrototype() { + return TypeParam::ConflictingPrototype; + } + static std::string getDefinition() { return TypeParam::Definition; } + static std::string getConflictingDefinition() { + return TypeParam::ConflictingDefinition; + } + static std::string getConflictingProtoDef() { + return TypeParam::ConflictingProtoDef; + } + static BindableMatcher getPattern() { return TypeParam().getPattern(); } + static Language getLang() { return TypeParam().getLang(); } + + template &, Decl *, Decl *)> + void TypedTest_ImportAfter() { + Decl *ToTU = getToTuDecl(ToTUContent(), getLang()); + auto *ToD = FirstDeclMatcher().match(ToTU, getPattern()); + + Decl *FromTU = getTuDecl(FromTUContent(), getLang()); + auto *FromD = FirstDeclMatcher().match(FromTU, getPattern()); + + auto Result = importOrError(FromD, getLang()); + + ResultChecker(Result, ToTU, ToD); + } + + // Check that a Decl has been successfully imported into a standalone redecl + // chain. + static void CheckImportedAsNew(llvm::Expected &Result, Decl *ToTU, + Decl *ToD) { + ASSERT_TRUE(isSuccess(Result)); + Decl *ImportedD = *Result; + ASSERT_TRUE(ImportedD); + EXPECT_NE(ImportedD, ToD); + EXPECT_EQ(DeclCounter().match(ToTU, getPattern()), 2u); + + // There may be a hidden fwd spec decl before a function spec decl. + if (auto *ImportedF = dyn_cast(ImportedD)) + if (ImportedF->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization) + return; + + EXPECT_FALSE(ImportedD->getPreviousDecl()); + } + + // Check that a Decl was not imported because of NameConflict. + static void CheckImportNameConflict(llvm::Expected &Result, + Decl *ToTU, Decl *ToD) { + EXPECT_TRUE(isImportError(Result, ImportError::NameConflict)); + EXPECT_EQ(DeclCounter().match(ToTU, getPattern()), 1u); + } + + // Check that a Decl was not imported because lookup found the same decl. + static void CheckImportFoundExisting(llvm::Expected &Result, + Decl *ToTU, Decl *ToD) { + ASSERT_TRUE(isSuccess(Result)); + EXPECT_EQ(DeclCounter().match(ToTU, getPattern()), 1u); + } + + void TypedTest_ImportConflictingDefAfterDef() { + TypedTest_ImportAfter(); + } + void TypedTest_ImportConflictingProtoAfterProto() { + TypedTest_ImportAfter(); + } + void TypedTest_ImportConflictingProtoAfterDef() { + TypedTest_ImportAfter(); + } + void TypedTest_ImportConflictingDefAfterProto() { + TypedTest_ImportAfter(); + } + void TypedTest_ImportConflictingProtoDefAfterProto() { + TypedTest_ImportAfter(); + } + void TypedTest_ImportConflictingProtoAfterProtoDef() { + TypedTest_ImportAfter(); + } + void TypedTest_ImportConflictingProtoDefAfterDef() { + TypedTest_ImportAfter(); + } + void TypedTest_ImportConflictingDefAfterProtoDef() { + TypedTest_ImportAfter(); + } + + void TypedTest_DontImportConflictingProtoAfterProto() { + TypedTest_ImportAfter(); + } + void TypedTest_DontImportConflictingDefAfterDef() { + TypedTest_ImportAfter(); + } + void TypedTest_DontImportConflictingProtoAfterDef() { + TypedTest_ImportAfter(); + } + void TypedTest_DontImportConflictingDefAfterProto() { + TypedTest_ImportAfter(); + } + void TypedTest_DontImportConflictingProtoDefAfterProto() { + TypedTest_ImportAfter(); + } + void TypedTest_DontImportConflictingProtoAfterProtoDef() { + TypedTest_ImportAfter(); + } + void TypedTest_DontImportConflictingProtoDefAfterDef() { + TypedTest_ImportAfter(); + } + void TypedTest_DontImportConflictingDefAfterProtoDef() { + TypedTest_ImportAfter(); + } + + // Used for function templates and function template specializations. + void TypedTest_ImportDifferentDefAfterDef() { + TypedTest_ImportAfter(); + } + void TypedTest_DontImportSameDefAfterDef() { + TypedTest_ImportAfter(); + } +}; + +// ============================== +// Define the parametrized tests. +// ============================== + +#define ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( \ + TypeParam, ODRHandlingParam, NamePrefix, TestCase) \ + using TypeParam##ODRHandlingParam = \ + ODRViolation; \ + TEST_P(TypeParam##ODRHandlingParam, NamePrefix##TestCase) { \ + TypedTest_##TestCase(); \ + } + +// clang-format off + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Function, Liberal, , + ImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Typedef, Liberal, , + ImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + TypedefAlias, Liberal, , + ImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Enum, Liberal, , + ImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + EnumConstant, Liberal, , + ImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Class, Liberal, , + ImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Variable, Liberal, , + ImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Liberal, , + ImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + VarTemplate, Liberal, , + ImportConflictingDefAfterDef) +// Class and variable template specializations/instantiatons are always +// imported conservatively, because the AST holds the specializations in a set, +// and the key within the set is a hash calculated from the arguments of the +// specialization. +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplateSpec, Liberal, , + DontImportConflictingDefAfterDef) // Don't import !!! +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + VarTemplateSpec, Liberal, , + DontImportConflictingDefAfterDef) // Don't import !!! + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Function, Conservative, , + DontImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Typedef, Conservative, , + DontImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + TypedefAlias, Conservative, , + DontImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Enum, Conservative, , + DontImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + EnumConstant, Conservative, , + DontImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Class, Conservative, , + DontImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Variable, Conservative, , + DontImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Conservative, , + DontImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + VarTemplate, Conservative, , + DontImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplateSpec, Conservative, , + DontImportConflictingDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + VarTemplateSpec, Conservative, , + DontImportConflictingDefAfterDef) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Function, Liberal, , + ImportConflictingProtoAfterProto) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Variable, Liberal, , + ImportConflictingProtoAfterProto) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Liberal, , + ImportConflictingProtoAfterProto) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Function, Conservative, , + DontImportConflictingProtoAfterProto) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Variable, Conservative, , + DontImportConflictingProtoAfterProto) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Conservative, , + DontImportConflictingProtoAfterProto) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Variable, Liberal, , + ImportConflictingProtoAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Liberal, , + ImportConflictingProtoAfterDef) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Variable, Conservative, , + DontImportConflictingProtoAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Conservative, , + DontImportConflictingProtoAfterDef) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Function, Liberal, , + ImportConflictingDefAfterProto) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Variable, Liberal, , + ImportConflictingDefAfterProto) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Liberal, , + ImportConflictingDefAfterProto) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Function, Conservative, , + DontImportConflictingDefAfterProto) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + Variable, Conservative, , + DontImportConflictingDefAfterProto) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Conservative, , + DontImportConflictingDefAfterProto) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Liberal, , + ImportConflictingProtoDefAfterProto) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Conservative, , + DontImportConflictingProtoDefAfterProto) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Liberal, , + ImportConflictingProtoAfterProtoDef) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Conservative, , + DontImportConflictingProtoAfterProtoDef) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Liberal, , + ImportConflictingProtoDefAfterDef) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Conservative, , + DontImportConflictingProtoDefAfterDef) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Liberal, , + ImportConflictingDefAfterProtoDef) + +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + ClassTemplate, Conservative, , + DontImportConflictingDefAfterProtoDef) + +// FunctionTemplate decls overload with each other. Thus, they are imported +// always as a new node, independently from any ODRHandling strategy. +// +// Function template specializations are "full" specializations. Structural +// equivalency does not check the body of functions, so we cannot create +// conflicting function template specializations. Thus, ODR handling strategies +// has nothing to do with function template specializations. Fully specialized +// function templates are imported as new nodes if their template arguments are +// different. +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + FunctionTemplate, Liberal, , + ImportDifferentDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + FunctionTemplateSpec, Liberal, , + ImportDifferentDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + FunctionTemplate, Conservative, , + ImportDifferentDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + FunctionTemplateSpec, Conservative, , + ImportDifferentDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + FunctionTemplate, Liberal, , + DontImportSameDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + FunctionTemplateSpec, Liberal, , + DontImportSameDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + FunctionTemplate, Conservative, , + DontImportSameDefAfterDef) +ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( + FunctionTemplateSpec, Conservative, , + DontImportSameDefAfterDef) + +// ====================== +// Instantiate the tests. +// ====================== + +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, FunctionConservative, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, TypedefConservative, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, TypedefAliasConservative, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, EnumConservative, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, EnumConstantConservative, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, ClassConservative, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, VariableConservative, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, ClassTemplateConservative, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, FunctionTemplateConservative, + DefaultTestValuesForRunOptions, ); +// FIXME: Make VarTemplate tests work. +//INSTANTIATE_TEST_CASE_P( + //ODRViolationTests, VarTemplateConservative, + //DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, FunctionTemplateSpecConservative, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, ClassTemplateSpecConservative, + DefaultTestValuesForRunOptions, ); +// FIXME: Make VarTemplateSpec tests work. +//INSTANTIATE_TEST_CASE_P( + //ODRViolationTests, VarTemplateSpecConservative, + //DefaultTestValuesForRunOptions, ); + +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, FunctionLiberal, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, TypedefLiberal, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, TypedefAliasLiberal, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, EnumLiberal, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, EnumConstantLiberal, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, ClassLiberal, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, VariableLiberal, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, ClassTemplateLiberal, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, FunctionTemplateLiberal, + DefaultTestValuesForRunOptions, ); +// FIXME: Make VarTemplate tests work. +// INSTANTIATE_TEST_CASE_P( +// ODRViolationTests, VarTemplateLiberal, +// DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, ClassTemplateSpecLiberal, + DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P( + ODRViolationTests, FunctionTemplateSpecLiberal, + DefaultTestValuesForRunOptions, ); +// FIXME: Make VarTemplateSpec tests work. +//INSTANTIATE_TEST_CASE_P( + //ODRViolationTests, VarTemplateSpecLiberal, + //DefaultTestValuesForRunOptions, ); + +// clang-format on + +} // end namespace ast_matchers +} // end namespace clang diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -5409,187 +5409,6 @@ EXPECT_EQ(ImportedX->isAggregate(), FromX->isAggregate()); } -struct ConflictingDeclsWithLiberalStrategy : ASTImporterOptionSpecificTestBase { - ConflictingDeclsWithLiberalStrategy() { - this->ODRHandling = ASTImporter::ODRHandlingType::Liberal; - } -}; - -// Check that a Decl has been successfully imported into a standalone redecl -// chain. -template -static void CheckImportedAsNew(llvm::Expected &Result, Decl *ToTU, - PatternTy Pattern) { - ASSERT_TRUE(isSuccess(Result)); - Decl *ImportedD = *Result; - ASSERT_TRUE(ImportedD); - auto *ToD = FirstDeclMatcher().match(ToTU, Pattern); - EXPECT_NE(ImportedD, ToD); - EXPECT_FALSE(ImportedD->getPreviousDecl()); - EXPECT_EQ(DeclCounter().match(ToTU, Pattern), 2u); -} - -TEST_P(ConflictingDeclsWithLiberalStrategy, Typedef) { - Decl *ToTU = getToTuDecl( - R"( - typedef int X; - )", - Lang_CXX11); - Decl *FromTU = getTuDecl( - R"( - typedef double X; - )", - Lang_CXX11); - auto Pattern = typedefNameDecl(hasName("X")); - auto *FromX = FirstDeclMatcher().match(FromTU, Pattern); - - Expected Result = importOrError(FromX, Lang_CXX11); - CheckImportedAsNew(Result, ToTU, Pattern); -} - -TEST_P(ConflictingDeclsWithLiberalStrategy, TypeAlias) { - Decl *ToTU = getToTuDecl( - R"( - using X = int; - )", - Lang_CXX11); - Decl *FromTU = getTuDecl( - R"( - using X = double; - )", - Lang_CXX11); - auto Pattern = typedefNameDecl(hasName("X")); - auto *FromX = FirstDeclMatcher().match(FromTU, Pattern); - Expected Result = importOrError(FromX, Lang_CXX11); - CheckImportedAsNew(Result, ToTU, Pattern); -} - -TEST_P(ConflictingDeclsWithLiberalStrategy, EnumDecl) { - Decl *ToTU = getToTuDecl( - R"( - enum X { a, b }; - )", - Lang_CXX11); - Decl *FromTU = getTuDecl( - R"( - enum X { a, b, c }; - )", - Lang_CXX11); - auto Pattern = enumDecl(hasName("X")); - auto *FromX = FirstDeclMatcher().match(FromTU, Pattern); - Expected Result = importOrError(FromX, Lang_CXX11); - CheckImportedAsNew(Result, ToTU, Pattern); -} - -TEST_P(ConflictingDeclsWithLiberalStrategy, EnumConstantDecl) { - Decl *ToTU = getToTuDecl( - R"( - enum E { X = 0 }; - )", - Lang_CXX11); - Decl *FromTU = getTuDecl( - R"( - enum E { X = 1 }; - )", - Lang_CXX11); - auto Pattern = enumConstantDecl(hasName("X")); - auto *FromX = FirstDeclMatcher().match(FromTU, Pattern); - Expected Result = importOrError(FromX, Lang_CXX11); - CheckImportedAsNew(Result, ToTU, Pattern); -} - -TEST_P(ConflictingDeclsWithLiberalStrategy, RecordDecl) { - Decl *ToTU = getToTuDecl( - R"( - class X { int a; }; - )", - Lang_CXX11); - Decl *FromTU = getTuDecl( - R"( - class X { int b; }; - )", - Lang_CXX11); - auto Pattern = cxxRecordDecl(hasName("X"), unless(isImplicit())); - auto *FromX = FirstDeclMatcher().match(FromTU, Pattern); - Expected Result = importOrError(FromX, Lang_CXX11); - CheckImportedAsNew(Result, ToTU, Pattern); -} - -TEST_P(ConflictingDeclsWithLiberalStrategy, VarDecl) { - Decl *ToTU = getToTuDecl( - R"( - int X; - )", - Lang_CXX11); - Decl *FromTU = getTuDecl( - R"( - double X; - )", - Lang_CXX11); - auto Pattern = varDecl(hasName("X")); - auto *FromX = FirstDeclMatcher().match(FromTU, Pattern); - Expected Result = importOrError(FromX, Lang_CXX11); - CheckImportedAsNew(Result, ToTU, Pattern); -} - -TEST_P(ConflictingDeclsWithLiberalStrategy, FunctionDecl) { - Decl *ToTU = getToTuDecl( - R"( - void X(int); - )", - Lang_C); // C, no overloading! - Decl *FromTU = getTuDecl( - R"( - void X(double); - )", - Lang_C); - auto Pattern = functionDecl(hasName("X")); - auto *FromX = FirstDeclMatcher().match(FromTU, Pattern); - Expected Result = importOrError(FromX, Lang_CXX11); - CheckImportedAsNew(Result, ToTU, Pattern); -} - -TEST_P(ConflictingDeclsWithLiberalStrategy, ClassTemplateDecl) { - Decl *ToTU = getToTuDecl( - R"( - template - struct X; - )", - Lang_CXX11); - Decl *FromTU = getTuDecl( - R"( - template - struct X; - )", - Lang_CXX11); - auto Pattern = classTemplateDecl(hasName("X")); - auto *FromX = FirstDeclMatcher().match(FromTU, Pattern); - Expected Result = importOrError(FromX, Lang_CXX11); - CheckImportedAsNew(Result, ToTU, Pattern); -} - -TEST_P(ConflictingDeclsWithLiberalStrategy, DISABLED_VarTemplateDecl) { - const internal::VariadicDynCastAllOfMatcher - varTemplateDecl; - Decl *ToTU = getToTuDecl( - R"( - template - constexpr T X; - )", - Lang_CXX14); - Decl *FromTU = getTuDecl( - R"( - template - constexpr int X = 0; - )", - Lang_CXX14); - auto Pattern = varTemplateDecl(hasName("X")); - auto *FromX = FirstDeclMatcher().match( - FromTU, varTemplateDecl(hasName("X"))); - Expected Result = importOrError(FromX, Lang_CXX11); - CheckImportedAsNew(Result, ToTU, Pattern); -} - INSTANTIATE_TEST_CASE_P(ParameterizedTests, SVEBuiltins, ::testing::Values(ArgVector{"-target", "aarch64-linux-gnu"}), ); @@ -5655,8 +5474,5 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, LLDBLookupTest, DefaultTestValuesForRunOptions, ); -INSTANTIATE_TEST_CASE_P(ParameterizedTests, ConflictingDeclsWithLiberalStrategy, - DefaultTestValuesForRunOptions, ); - } // end namespace ast_matchers } // end namespace clang diff --git a/clang/unittests/AST/CMakeLists.txt b/clang/unittests/AST/CMakeLists.txt --- a/clang/unittests/AST/CMakeLists.txt +++ b/clang/unittests/AST/CMakeLists.txt @@ -11,6 +11,7 @@ ASTImporterFixtures.cpp ASTImporterTest.cpp ASTImporterGenericRedeclTest.cpp + ASTImporterODRStrategiesTest.cpp ASTImporterVisibilityTest.cpp ASTTraverserTest.cpp ASTTypeTraitsTest.cpp