forked from OSchip/llvm-project
[ASTImporter][NFC] Add comprehensive tests for ODR violation handling strategies
Summary: In this patch we provide additional and comprehensive tests for the ODR handling strategies. This is the continuation of https://reviews.llvm.org/D59692. Reviewers: shafik, a_sidorin, balazske, a.sidorin Subscribers: mgorny, rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D66951 llvm-svn: 372564
This commit is contained in:
parent
f7caf3cac8
commit
c65628a49a
clang/unittests/AST
|
@ -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<Decl> 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<Decl> 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<Decl> 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<Decl> 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<Decl> 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<Decl> 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<Decl> getPattern() { return varDecl(hasName("X")); }
|
||||
Language getLang() { return Lang_CXX; }
|
||||
};
|
||||
|
||||
struct ClassTemplate {
|
||||
using DeclTy = ClassTemplateDecl;
|
||||
static constexpr auto *Prototype = "template <class> class X;";
|
||||
static constexpr auto *ConflictingPrototype = "template <int> class X;";
|
||||
static constexpr auto *Definition = "template <class> class X {};";
|
||||
static constexpr auto *ConflictingDefinition =
|
||||
"template <class> class X { int A; };";
|
||||
static constexpr auto *ConflictingProtoDef = "template <int> class X { };";
|
||||
BindableMatcher<Decl> getPattern() {
|
||||
return classTemplateDecl(hasName("X"), unless(isImplicit()));
|
||||
}
|
||||
Language getLang() { return Lang_CXX; }
|
||||
};
|
||||
|
||||
struct FunctionTemplate {
|
||||
using DeclTy = FunctionTemplateDecl;
|
||||
static constexpr auto *Definition0 =
|
||||
R"(
|
||||
template <class T>
|
||||
void X(T a) {};
|
||||
)";
|
||||
// This is actually not a conflicting definition, but another primary template.
|
||||
static constexpr auto *Definition1 =
|
||||
R"(
|
||||
template <class T>
|
||||
void X(T* a) {};
|
||||
)";
|
||||
BindableMatcher<Decl> 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<Decl, VarTemplateDecl>
|
||||
varTemplateDecl;
|
||||
|
||||
struct VarTemplate {
|
||||
using DeclTy = VarTemplateDecl;
|
||||
static constexpr auto *Definition =
|
||||
R"(
|
||||
template <class T>
|
||||
constexpr T X = 0;
|
||||
)";
|
||||
static constexpr auto *ConflictingDefinition =
|
||||
R"(
|
||||
template <int>
|
||||
constexpr int X = 0;
|
||||
)";
|
||||
BindableMatcher<Decl> getPattern() { return varTemplateDecl(hasName("X")); }
|
||||
Language getLang() { return Lang_CXX14; }
|
||||
};
|
||||
|
||||
struct ClassTemplateSpec {
|
||||
using DeclTy = ClassTemplateSpecializationDecl;
|
||||
static constexpr auto *Prototype =
|
||||
R"(
|
||||
template <class T> class X;
|
||||
template <> class X<int>;
|
||||
)";
|
||||
static constexpr auto *Definition =
|
||||
R"(
|
||||
template <class T> class X;
|
||||
template <> class X<int> {};
|
||||
)";
|
||||
static constexpr auto *ConflictingDefinition =
|
||||
R"(
|
||||
template <class T> class X;
|
||||
template <> class X<int> { int A; };
|
||||
)";
|
||||
BindableMatcher<Decl> 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 <class T>
|
||||
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 <class T>
|
||||
void X(T a);
|
||||
template <> void X(double a) {};
|
||||
)";
|
||||
|
||||
BindableMatcher<Decl> 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 <class T> T X = 0;
|
||||
template <> int X<int> = 0;
|
||||
)";
|
||||
static constexpr auto *ConflictingDefinition =
|
||||
R"(
|
||||
template <class T> T X = 0;
|
||||
template <> float X<int> = 1.0;
|
||||
)";
|
||||
BindableMatcher<Decl> getPattern() {
|
||||
return varTemplateSpecializationDecl(hasName("X"), unless(isImplicit()));
|
||||
}
|
||||
Language getLang() { return Lang_CXX14; }
|
||||
};
|
||||
|
||||
template <typename TypeParam, ASTImporter::ODRHandlingType ODRHandlingParam>
|
||||
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<Decl> getPattern() { return TypeParam().getPattern(); }
|
||||
static Language getLang() { return TypeParam().getLang(); }
|
||||
|
||||
template <std::string (*ToTUContent)(), std::string (*FromTUContent)(),
|
||||
void (*ResultChecker)(llvm::Expected<Decl *> &, Decl *, Decl *)>
|
||||
void TypedTest_ImportAfter() {
|
||||
Decl *ToTU = getToTuDecl(ToTUContent(), getLang());
|
||||
auto *ToD = FirstDeclMatcher<DeclTy>().match(ToTU, getPattern());
|
||||
|
||||
Decl *FromTU = getTuDecl(FromTUContent(), getLang());
|
||||
auto *FromD = FirstDeclMatcher<DeclTy>().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<Decl *> &Result, Decl *ToTU,
|
||||
Decl *ToD) {
|
||||
ASSERT_TRUE(isSuccess(Result));
|
||||
Decl *ImportedD = *Result;
|
||||
ASSERT_TRUE(ImportedD);
|
||||
EXPECT_NE(ImportedD, ToD);
|
||||
EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 2u);
|
||||
|
||||
// There may be a hidden fwd spec decl before a function spec decl.
|
||||
if (auto *ImportedF = dyn_cast<FunctionDecl>(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<Decl *> &Result,
|
||||
Decl *ToTU, Decl *ToD) {
|
||||
EXPECT_TRUE(isImportError(Result, ImportError::NameConflict));
|
||||
EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
|
||||
}
|
||||
|
||||
// Check that a Decl was not imported because lookup found the same decl.
|
||||
static void CheckImportFoundExisting(llvm::Expected<Decl *> &Result,
|
||||
Decl *ToTU, Decl *ToD) {
|
||||
ASSERT_TRUE(isSuccess(Result));
|
||||
EXPECT_EQ(DeclCounter<DeclTy>().match(ToTU, getPattern()), 1u);
|
||||
}
|
||||
|
||||
void TypedTest_ImportConflictingDefAfterDef() {
|
||||
TypedTest_ImportAfter<getDefinition, getConflictingDefinition,
|
||||
CheckImportedAsNew>();
|
||||
}
|
||||
void TypedTest_ImportConflictingProtoAfterProto() {
|
||||
TypedTest_ImportAfter<getPrototype, getConflictingPrototype,
|
||||
CheckImportedAsNew>();
|
||||
}
|
||||
void TypedTest_ImportConflictingProtoAfterDef() {
|
||||
TypedTest_ImportAfter<getDefinition, getConflictingPrototype,
|
||||
CheckImportedAsNew>();
|
||||
}
|
||||
void TypedTest_ImportConflictingDefAfterProto() {
|
||||
TypedTest_ImportAfter<getConflictingPrototype, getDefinition,
|
||||
CheckImportedAsNew>();
|
||||
}
|
||||
void TypedTest_ImportConflictingProtoDefAfterProto() {
|
||||
TypedTest_ImportAfter<getPrototype, getConflictingProtoDef,
|
||||
CheckImportedAsNew>();
|
||||
}
|
||||
void TypedTest_ImportConflictingProtoAfterProtoDef() {
|
||||
TypedTest_ImportAfter<getConflictingProtoDef, getPrototype,
|
||||
CheckImportedAsNew>();
|
||||
}
|
||||
void TypedTest_ImportConflictingProtoDefAfterDef() {
|
||||
TypedTest_ImportAfter<getDefinition, getConflictingProtoDef,
|
||||
CheckImportedAsNew>();
|
||||
}
|
||||
void TypedTest_ImportConflictingDefAfterProtoDef() {
|
||||
TypedTest_ImportAfter<getConflictingProtoDef, getDefinition,
|
||||
CheckImportedAsNew>();
|
||||
}
|
||||
|
||||
void TypedTest_DontImportConflictingProtoAfterProto() {
|
||||
TypedTest_ImportAfter<getPrototype, getConflictingPrototype,
|
||||
CheckImportNameConflict>();
|
||||
}
|
||||
void TypedTest_DontImportConflictingDefAfterDef() {
|
||||
TypedTest_ImportAfter<getDefinition, getConflictingDefinition,
|
||||
CheckImportNameConflict>();
|
||||
}
|
||||
void TypedTest_DontImportConflictingProtoAfterDef() {
|
||||
TypedTest_ImportAfter<getDefinition, getConflictingPrototype,
|
||||
CheckImportNameConflict>();
|
||||
}
|
||||
void TypedTest_DontImportConflictingDefAfterProto() {
|
||||
TypedTest_ImportAfter<getConflictingPrototype, getDefinition,
|
||||
CheckImportNameConflict>();
|
||||
}
|
||||
void TypedTest_DontImportConflictingProtoDefAfterProto() {
|
||||
TypedTest_ImportAfter<getPrototype, getConflictingProtoDef,
|
||||
CheckImportNameConflict>();
|
||||
}
|
||||
void TypedTest_DontImportConflictingProtoAfterProtoDef() {
|
||||
TypedTest_ImportAfter<getConflictingProtoDef, getPrototype,
|
||||
CheckImportNameConflict>();
|
||||
}
|
||||
void TypedTest_DontImportConflictingProtoDefAfterDef() {
|
||||
TypedTest_ImportAfter<getDefinition, getConflictingProtoDef,
|
||||
CheckImportNameConflict>();
|
||||
}
|
||||
void TypedTest_DontImportConflictingDefAfterProtoDef() {
|
||||
TypedTest_ImportAfter<getConflictingProtoDef, getDefinition,
|
||||
CheckImportNameConflict>();
|
||||
}
|
||||
|
||||
// Used for function templates and function template specializations.
|
||||
void TypedTest_ImportDifferentDefAfterDef() {
|
||||
TypedTest_ImportAfter<TypeParam::getDef0, TypeParam::getDef1,
|
||||
CheckImportedAsNew>();
|
||||
}
|
||||
void TypedTest_DontImportSameDefAfterDef() {
|
||||
TypedTest_ImportAfter<TypeParam::getDef0, TypeParam::getDef0,
|
||||
CheckImportFoundExisting>();
|
||||
}
|
||||
};
|
||||
|
||||
// ==============================
|
||||
// Define the parametrized tests.
|
||||
// ==============================
|
||||
|
||||
#define ASTIMPORTER_ODR_INSTANTIATE_TYPED_TEST_CASE( \
|
||||
TypeParam, ODRHandlingParam, NamePrefix, TestCase) \
|
||||
using TypeParam##ODRHandlingParam = \
|
||||
ODRViolation<TypeParam, ASTImporter::ODRHandlingType::ODRHandlingParam>; \
|
||||
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
|
|
@ -5481,187 +5481,6 @@ TEST_P(ASTImporterOptionSpecificTestBase,
|
|||
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 <typename DeclTy, typename PatternTy>
|
||||
static void CheckImportedAsNew(llvm::Expected<Decl *> &Result, Decl *ToTU,
|
||||
PatternTy Pattern) {
|
||||
ASSERT_TRUE(isSuccess(Result));
|
||||
Decl *ImportedD = *Result;
|
||||
ASSERT_TRUE(ImportedD);
|
||||
auto *ToD = FirstDeclMatcher<DeclTy>().match(ToTU, Pattern);
|
||||
EXPECT_NE(ImportedD, ToD);
|
||||
EXPECT_FALSE(ImportedD->getPreviousDecl());
|
||||
EXPECT_EQ(DeclCounter<DeclTy>().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<TypedefNameDecl>().match(FromTU, Pattern);
|
||||
|
||||
Expected<Decl *> Result = importOrError(FromX, Lang_CXX11);
|
||||
CheckImportedAsNew<TypedefNameDecl>(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<TypedefNameDecl>().match(FromTU, Pattern);
|
||||
Expected<Decl *> Result = importOrError(FromX, Lang_CXX11);
|
||||
CheckImportedAsNew<TypedefNameDecl>(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<EnumDecl>().match(FromTU, Pattern);
|
||||
Expected<Decl *> Result = importOrError(FromX, Lang_CXX11);
|
||||
CheckImportedAsNew<EnumDecl>(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<EnumConstantDecl>().match(FromTU, Pattern);
|
||||
Expected<Decl *> Result = importOrError(FromX, Lang_CXX11);
|
||||
CheckImportedAsNew<EnumConstantDecl>(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<RecordDecl>().match(FromTU, Pattern);
|
||||
Expected<Decl *> Result = importOrError(FromX, Lang_CXX11);
|
||||
CheckImportedAsNew<RecordDecl>(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<VarDecl>().match(FromTU, Pattern);
|
||||
Expected<Decl *> Result = importOrError(FromX, Lang_CXX11);
|
||||
CheckImportedAsNew<VarDecl>(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<FunctionDecl>().match(FromTU, Pattern);
|
||||
Expected<Decl *> Result = importOrError(FromX, Lang_CXX11);
|
||||
CheckImportedAsNew<FunctionDecl>(Result, ToTU, Pattern);
|
||||
}
|
||||
|
||||
TEST_P(ConflictingDeclsWithLiberalStrategy, ClassTemplateDecl) {
|
||||
Decl *ToTU = getToTuDecl(
|
||||
R"(
|
||||
template <class>
|
||||
struct X;
|
||||
)",
|
||||
Lang_CXX11);
|
||||
Decl *FromTU = getTuDecl(
|
||||
R"(
|
||||
template <int>
|
||||
struct X;
|
||||
)",
|
||||
Lang_CXX11);
|
||||
auto Pattern = classTemplateDecl(hasName("X"));
|
||||
auto *FromX = FirstDeclMatcher<ClassTemplateDecl>().match(FromTU, Pattern);
|
||||
Expected<Decl *> Result = importOrError(FromX, Lang_CXX11);
|
||||
CheckImportedAsNew<ClassTemplateDecl>(Result, ToTU, Pattern);
|
||||
}
|
||||
|
||||
TEST_P(ConflictingDeclsWithLiberalStrategy, DISABLED_VarTemplateDecl) {
|
||||
const internal::VariadicDynCastAllOfMatcher<Decl, VarTemplateDecl>
|
||||
varTemplateDecl;
|
||||
Decl *ToTU = getToTuDecl(
|
||||
R"(
|
||||
template <class T>
|
||||
constexpr T X;
|
||||
)",
|
||||
Lang_CXX14);
|
||||
Decl *FromTU = getTuDecl(
|
||||
R"(
|
||||
template <int>
|
||||
constexpr int X = 0;
|
||||
)",
|
||||
Lang_CXX14);
|
||||
auto Pattern = varTemplateDecl(hasName("X"));
|
||||
auto *FromX = FirstDeclMatcher<VarTemplateDecl>().match(
|
||||
FromTU, varTemplateDecl(hasName("X")));
|
||||
Expected<Decl *> Result = importOrError(FromX, Lang_CXX11);
|
||||
CheckImportedAsNew<VarTemplateDecl>(Result, ToTU, Pattern);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ParameterizedTests, SVEBuiltins,
|
||||
::testing::Values(ArgVector{"-target",
|
||||
"aarch64-linux-gnu"}), );
|
||||
|
@ -5838,8 +5657,5 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportVariables,
|
|||
INSTANTIATE_TEST_CASE_P(ParameterizedTests, LLDBLookupTest,
|
||||
DefaultTestValuesForRunOptions, );
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ParameterizedTests, ConflictingDeclsWithLiberalStrategy,
|
||||
DefaultTestValuesForRunOptions, );
|
||||
|
||||
} // end namespace ast_matchers
|
||||
} // end namespace clang
|
||||
|
|
|
@ -11,6 +11,7 @@ add_clang_unittest(ASTTests
|
|||
ASTImporterFixtures.cpp
|
||||
ASTImporterTest.cpp
|
||||
ASTImporterGenericRedeclTest.cpp
|
||||
ASTImporterODRStrategiesTest.cpp
|
||||
ASTImporterVisibilityTest.cpp
|
||||
ASTTraverserTest.cpp
|
||||
ASTTypeTraitsTest.cpp
|
||||
|
|
Loading…
Reference in New Issue