Merge "Allow extending qualifiers of function parameters and return values" am: 82b8191b50

Original change: https://android-review.googlesource.com/c/platform/development/+/2337410

Change-Id: I4884d914a5f60d89ab5c99e0b6e0ea337c896584
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Hsin-Yi Chen
2022-12-28 10:52:26 +00:00
committed by Automerger Merge Worker
13 changed files with 781 additions and 63 deletions

View File

@@ -93,7 +93,8 @@ bool DiffWrapper<repr::FunctionIR>::DumpDiff(
repr::FunctionIR new_function = *newp_;
ReplaceTypeIdsWithTypeNames(old_types_, &old_function);
ReplaceTypeIdsWithTypeNames(new_types_, &new_function);
repr::FunctionDiffIR function_diff_ir(&old_function, &new_function);
repr::FunctionDiffIR function_diff_ir(&old_function, &new_function,
function_type_diff.IsExtension());
function_diff_ir.SetName(oldp_->GetName());
return ir_diff_dumper_->AddDiffMessageIR(&function_diff_ir,
Unwind(&type_queue), diff_kind);

View File

@@ -281,20 +281,6 @@ static bool CompareSizeAndAlignment(const TypeIR *old_type,
old_type->GetAlignment() == new_type->GetAlignment();
}
bool AbiDiffHelper::AreTypeSizeAndAlignmentEqual(
const std::string &old_type_id, const std::string &new_type_id) const {
AbiElementMap<const TypeIR *>::const_iterator old_it =
old_types_.find(old_type_id);
AbiElementMap<const TypeIR *>::const_iterator new_it =
new_types_.find(new_type_id);
if (old_it == old_types_.end() || new_it == new_types_.end()) {
return AreOpaqueTypesEqual(old_type_id, new_type_id);
}
return CompareSizeAndAlignment(old_it->second, new_it->second);
}
DiffStatusPair<std::unique_ptr<RecordFieldDiffIR>>
AbiDiffHelper::CompareCommonRecordFields(
const RecordFieldIR *old_field,
@@ -522,14 +508,13 @@ AbiDiffHelper::FixupDiffedFieldTypeIds(
DiffStatus AbiDiffHelper::CompareFunctionTypes(
const CFunctionLikeIR *old_type, const CFunctionLikeIR *new_type,
std::deque<std::string> *type_queue, DiffMessageIR::DiffKind diff_kind) {
DiffStatus param_diffs = CompareFunctionParameters(old_type->GetParameters(),
new_type->GetParameters(),
type_queue, diff_kind);
DiffStatus return_type_diff = CompareParameterOrReturnType(
old_type->GetReturnType(), new_type->GetReturnType(), type_queue,
diff_kind);
return param_diffs.CombineWith(return_type_diff);
DiffStatus status = CompareFunctionParameters(old_type->GetParameters(),
new_type->GetParameters(),
type_queue, diff_kind);
status.CombineWith(CompareReturnTypes(old_type->GetReturnType(),
new_type->GetReturnType(), type_queue,
diff_kind));
return status;
}
DiffStatus AbiDiffHelper::CompareRecordTypes(
@@ -696,36 +681,186 @@ DiffStatus AbiDiffHelper::CompareBuiltinTypes(
DiffStatus AbiDiffHelper::CompareFunctionParameters(
const std::vector<ParamIR> &old_parameters,
const std::vector<ParamIR> &new_parameters,
std::deque<std::string> *type_queue,
DiffMessageIR::DiffKind diff_kind) {
std::deque<std::string> *type_queue, DiffMessageIR::DiffKind diff_kind) {
size_t old_parameters_size = old_parameters.size();
if (old_parameters_size != new_parameters.size()) {
return DiffStatus::kDirectDiff;
}
uint64_t i = 0;
while (i < old_parameters_size) {
DiffStatus result = DiffStatus::kNoDiff;
for (uint64_t i = 0; i < old_parameters_size; i++) {
const ParamIR &old_parameter = old_parameters.at(i);
const ParamIR &new_parameter = new_parameters.at(i);
if (CompareParameterOrReturnType(old_parameter.GetReferencedType(),
new_parameter.GetReferencedType(),
type_queue, diff_kind)
.IsDirectDiff() ||
(old_parameter.GetIsDefault() != new_parameter.GetIsDefault())) {
return DiffStatus::kDirectDiff;
result.CombineWith(CompareParameterTypes(old_parameter.GetReferencedType(),
new_parameter.GetReferencedType(),
type_queue, diff_kind));
if (old_parameter.GetIsDefault() != new_parameter.GetIsDefault()) {
result.CombineWith(DiffStatus::kDirectDiff);
}
i++;
}
return DiffStatus::kNoDiff;
return result;
}
DiffStatus AbiDiffHelper::CompareParameterOrReturnType(
static const TypeIR *FindTypeById(
const AbiElementMap<const TypeIR *> &type_graph,
const std::string &type_id) {
auto it = type_graph.find(type_id);
return it == type_graph.end() ? nullptr : it->second;
}
struct Qualifiers {
bool is_const = false;
bool is_restricted = false;
bool is_volatile = false;
bool operator==(const Qualifiers &other) const {
return (is_const == other.is_const &&
is_restricted == other.is_restricted &&
is_volatile == other.is_volatile);
}
bool operator!=(const Qualifiers &other) const { return !(*this == other); }
};
// This function returns the qualifiers and sets type_id to the unqalified or
// opaque type.
static Qualifiers ResolveQualifiers(const AbiElementMap<const TypeIR *> &types,
std::string &type_id) {
Qualifiers qual;
while (true) {
const TypeIR *type_ir = FindTypeById(types, type_id);
if (type_ir == nullptr ||
type_ir->GetKind() != LinkableMessageKind::QualifiedTypeKind) {
return qual;
}
const QualifiedTypeIR *qualified_type_ir =
static_cast<const QualifiedTypeIR *>(type_ir);
qual.is_const |= qualified_type_ir->IsConst();
qual.is_restricted |= qualified_type_ir->IsRestricted();
qual.is_volatile |= qualified_type_ir->IsVolatile();
type_id = qualified_type_ir->GetReferencedType();
}
}
// This function returns whether the old_type can be implicitly casted to
// new_type. It resolves qualified pointers and references until it reaches a
// type that does not reference other types. It does not compare the final
// referenced types.
//
// If this function returns true, old_type_id and new_type_id are set to the
// final referenced types. are_qualifiers_equal represents whether the
// qualifiers are exactly the same.
//
// If this function returns false, old_type_id, new_type_id, and
// are_qualifiers_equal do not have valid values.
//
// This function follows C++ standard to determine whether qualifiers can be
// casted. The rules are described in
// Section 7.5 Qualification conversions [conv.qual] in C++17 standard
// and
// https://en.cppreference.com/w/cpp/language/implicit_conversion#Qualification_conversions
// Additionally, __restrict__ follows the same rules as const and volatile.
static bool ResolveImplicitlyConvertibleQualifiedReferences(
const AbiElementMap<const TypeIR *> &old_types,
const AbiElementMap<const TypeIR *> &new_types, std::string &old_type_id,
std::string &new_type_id, bool &are_qualifiers_equal) {
are_qualifiers_equal = true;
bool is_first_level = true;
bool is_const_since_second_level = true;
while (true) {
// Check qualifiers.
const Qualifiers old_qual = ResolveQualifiers(old_types, old_type_id);
const Qualifiers new_qual = ResolveQualifiers(new_types, new_type_id);
are_qualifiers_equal &= (old_qual == new_qual);
if (is_first_level) {
is_first_level = false;
} else {
if ((old_qual.is_const && !new_qual.is_const) ||
(old_qual.is_restricted && !new_qual.is_restricted) ||
(old_qual.is_volatile && !new_qual.is_volatile)) {
return false;
}
if (!is_const_since_second_level && old_qual != new_qual) {
return false;
}
is_const_since_second_level &= new_qual.is_const;
}
// Stop if the unqualified types differ or don't reference other types.
const TypeIR *old_type = FindTypeById(old_types, old_type_id);
const TypeIR *new_type = FindTypeById(new_types, new_type_id);
if (old_type == nullptr || new_type == nullptr) {
return true;
}
const LinkableMessageKind kind = old_type->GetKind();
if (kind != new_type->GetKind()) {
return true;
}
if (kind != LinkableMessageKind::PointerTypeKind &&
kind != LinkableMessageKind::LvalueReferenceTypeKind &&
kind != LinkableMessageKind::RvalueReferenceTypeKind) {
return true;
}
// Get the referenced types.
old_type_id = old_type->GetReferencedType();
new_type_id = new_type->GetReferencedType();
}
}
DiffStatus AbiDiffHelper::CompareParameterTypes(
const std::string &old_type_id, const std::string &new_type_id,
std::deque<std::string> *type_queue, DiffMessageIR::DiffKind diff_kind) {
if (!AreTypeSizeAndAlignmentEqual(old_type_id, new_type_id)) {
// Compare size and alignment.
const TypeIR *old_type_ir = FindTypeById(old_types_, old_type_id);
const TypeIR *new_type_ir = FindTypeById(new_types_, new_type_id);
if (old_type_ir != nullptr && new_type_ir != nullptr &&
!CompareSizeAndAlignment(old_type_ir, new_type_ir)) {
return DiffStatus::kDirectDiff;
}
return CompareAndDumpTypeDiff(old_type_id, new_type_id, type_queue,
diff_kind);
// Allow the new parameter to be more qualified than the old parameter.
std::string old_referenced_type_id = old_type_id;
std::string new_referenced_type_id = new_type_id;
bool are_qualifiers_equal;
if (!ResolveImplicitlyConvertibleQualifiedReferences(
old_types_, new_types_, old_referenced_type_id,
new_referenced_type_id, are_qualifiers_equal)) {
return DiffStatus::kDirectDiff;
}
// Compare the unqualified referenced types.
DiffStatus result = CompareAndDumpTypeDiff(
old_referenced_type_id, new_referenced_type_id, type_queue, diff_kind);
if (!are_qualifiers_equal) {
result.CombineWith(DiffStatus::kDirectExt);
}
return result;
}
// This function is the same as CompareParameterTypes except for the arguments
// to ResolveImplicitlyConvertibleQualifiedReferences.
DiffStatus AbiDiffHelper::CompareReturnTypes(
const std::string &old_type_id, const std::string &new_type_id,
std::deque<std::string> *type_queue, DiffMessageIR::DiffKind diff_kind) {
// Compare size and alignment.
const TypeIR *old_type_ir = FindTypeById(old_types_, old_type_id);
const TypeIR *new_type_ir = FindTypeById(new_types_, new_type_id);
if (old_type_ir != nullptr && new_type_ir != nullptr &&
!CompareSizeAndAlignment(old_type_ir, new_type_ir)) {
return DiffStatus::kDirectDiff;
}
// Allow the new return type to be less qualified than the old return type.
std::string old_referenced_type_id = old_type_id;
std::string new_referenced_type_id = new_type_id;
bool are_qualifiers_equal;
if (!ResolveImplicitlyConvertibleQualifiedReferences(
new_types_, old_types_, new_referenced_type_id,
old_referenced_type_id, are_qualifiers_equal)) {
return DiffStatus::kDirectDiff;
}
// Compare the unqualified referenced types.
DiffStatus result = CompareAndDumpTypeDiff(
old_referenced_type_id, new_referenced_type_id, type_queue, diff_kind);
if (!are_qualifiers_equal) {
result.CombineWith(DiffStatus::kDirectExt);
}
return result;
}
DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff(
@@ -786,10 +921,14 @@ DiffStatus AbiDiffHelper::CompareAndDumpTypeDiff(
}
if (kind == LinkableMessageKind::FunctionTypeKind) {
return CompareFunctionTypes(
DiffStatus result = CompareFunctionTypes(
static_cast<const FunctionTypeIR *>(old_type),
static_cast<const FunctionTypeIR *>(new_type),
type_queue, diff_kind);
static_cast<const FunctionTypeIR *>(new_type), type_queue, diff_kind);
// Do not allow extending function pointers, function references, etc.
if (result.IsExtension()) {
result.CombineWith(DiffStatus::kDirectDiff);
}
return result;
}
return DiffStatus::kNoDiff;
}

View File

@@ -36,8 +36,11 @@ class DiffStatus {
kNoDiff = 0,
// The diff has been added to the IRDiffDumper.
kIndirectDiff = 1,
// The diff has not been added to the IRDiffDumper, and the new ABI is
// an extension to the old ABI.
kDirectExt = 2,
// The diff has not been added to the IRDiffDumper.
kDirectDiff = 2,
kDirectDiff = 3,
};
// Allow implicit conversion.
@@ -45,7 +48,11 @@ class DiffStatus {
bool HasDiff() const { return status_ != kNoDiff; }
bool IsDirectDiff() const { return status_ == kDirectDiff; }
bool IsDirectDiff() const {
return status_ == kDirectDiff || status_ == kDirectExt;
}
bool IsExtension() const { return status_ == kDirectExt; }
DiffStatus &CombineWith(DiffStatus other) {
status_ = std::max(status_, other.status_);
@@ -93,9 +100,6 @@ class AbiDiffHelper {
bool AreOpaqueTypesEqual(const std::string &old_type_str,
const std::string &new_type_str) const;
bool AreTypeSizeAndAlignmentEqual(const std::string &old_type_str,
const std::string &new_type_str) const;
DiffStatus CompareAndDumpTypeDiff(
const std::string &old_type_str, const std::string &new_type_str,
std::deque<std::string> *type_queue = nullptr,
@@ -123,17 +127,6 @@ class AbiDiffHelper {
std::deque<std::string> *type_queue,
DiffMessageIR::DiffKind diff_kind);
DiffStatus CompareFunctionParameters(
const std::vector<ParamIR> &old_parameters,
const std::vector<ParamIR> &new_parameters,
std::deque<std::string> *type_queue,
IRDiffDumper::DiffKind diff_kind);
DiffStatus CompareParameterOrReturnType(const std::string &old_type_id,
const std::string &new_type_id,
std::deque<std::string> *type_queue,
IRDiffDumper::DiffKind diff_kind);
DiffStatus CompareTemplateInfo(
const std::vector<TemplateElementIR> &old_template_elements,
const std::vector<TemplateElementIR> &new_template_elements,
@@ -211,6 +204,21 @@ class AbiDiffHelper {
const VTableComponentIR &old_component,
const VTableComponentIR &new_component);
DiffStatus CompareFunctionParameters(
const std::vector<ParamIR> &old_parameters,
const std::vector<ParamIR> &new_parameters,
std::deque<std::string> *type_queue, IRDiffDumper::DiffKind diff_kind);
DiffStatus CompareParameterTypes(const std::string &old_type_id,
const std::string &new_type_id,
std::deque<std::string> *type_queue,
IRDiffDumper::DiffKind diff_kind);
DiffStatus CompareReturnTypes(const std::string &old_type_id,
const std::string &new_type_id,
std::deque<std::string> *type_queue,
IRDiffDumper::DiffKind diff_kind);
template <typename DiffType, typename DiffElement>
bool AddToDiff(DiffType *mutable_diff, const DiffElement *oldp,
const DiffElement *newp,

View File

@@ -347,9 +347,11 @@ class GlobalVarDiffIR : public DiffMessageIR {
class FunctionDiffIR : public DiffMessageIR {
public:
FunctionDiffIR(const FunctionIR *old_function,
const FunctionIR *new_function)
: old_function_(old_function), new_function_(new_function) {}
FunctionDiffIR(const FunctionIR *old_function, const FunctionIR *new_function,
bool is_extended)
: old_function_(old_function),
new_function_(new_function),
is_extended_(is_extended) {}
LinkableMessageKind Kind() const override {
return LinkableMessageKind::FunctionKind;
@@ -363,9 +365,12 @@ class FunctionDiffIR : public DiffMessageIR {
return new_function_;
}
bool IsExtended() const { return is_extended_; }
protected:
const FunctionIR *old_function_;
const FunctionIR *new_function_;
const bool is_extended_;
};

View File

@@ -55,7 +55,8 @@ CompatibilityStatusIR ProtobufIRDiffDumper::GetCompatibilityStatusIR() {
if (diff_tu_->enum_type_extension_diffs().size() != 0 ||
diff_tu_->functions_added().size() != 0 ||
diff_tu_->global_vars_added().size() != 0 ||
diff_tu_->record_type_extension_diffs().size() != 0) {
diff_tu_->record_type_extension_diffs().size() != 0 ||
diff_tu_->function_extension_diffs().size() != 0) {
combined_status = combined_status | CompatibilityStatusIR::Extension;
}
@@ -315,7 +316,8 @@ bool ProtobufIRDiffDumper::AddFunctionDiffIR(
const FunctionDiffIR *function_diff_ir, const std::string &type_stack,
DiffKind diff_kind) {
abi_diff::FunctionDeclDiff *added_function_diff =
diff_tu_->add_function_diffs();
function_diff_ir->IsExtended() ? diff_tu_->add_function_extension_diffs()
: diff_tu_->add_function_diffs();
if (!added_function_diff) {
return false;
}

View File

@@ -100,6 +100,7 @@ message TranslationUnitDiff {
// Functions and Global variables.
repeated FunctionDeclDiff function_diffs = 13;
repeated FunctionDeclDiff function_extension_diffs = 26;
repeated GlobalVarDeclDiff global_var_diffs = 14;
repeated abi_dump.FunctionDecl functions_removed = 15;

View File

@@ -0,0 +1,11 @@
struct Struct;
extern "C" {
void ConstParameter(char (&)[2]);
void VolatileParameter(Struct &&);
void Restrict(char *__restrict__);
const char *const *MultipleConst(char **);
}
const char &ConstReturn();
volatile Struct &&VolatileReturn();

View File

@@ -0,0 +1,11 @@
struct Struct;
extern "C" {
void ConstParameter(const char (&)[2]);
void VolatileParameter(volatile Struct &&);
void Restrict(char *);
char **MultipleConst(char const *const *const);
}
char &ConstReturn();
Struct &&VolatileReturn();

View File

@@ -0,0 +1,9 @@
libfunction_extensions {
global:
ConstParameter;
VolatileParameter;
Restrict;
MultipleConst;
_Z11ConstReturnv;
_Z14VolatileReturnv;
};

View File

@@ -736,6 +736,24 @@ TEST_MODULES = [
linker_flags=['-output-format', 'Json'],
has_reference_dump=True,
),
LsdumpModule(
name='libfunction_extensions',
arch='arm64',
srcs=['integration/function_extensions/include/base.h'],
version_script='integration/function_extensions/map.txt',
export_include_dirs=['integration/function_extensions/include'],
linker_flags=['-output-format', 'Json'],
has_reference_dump=True,
),
LsdumpModule(
name='liballowed_function_extensions',
arch='arm64',
srcs=['integration/function_extensions/include/extensions.h'],
version_script='integration/function_extensions/map.txt',
export_include_dirs=['integration/function_extensions/include'],
linker_flags=['-output-format', 'Json'],
has_reference_dump=True,
),
]
TEST_MODULES = {m.name: m for m in TEST_MODULES}

View File

@@ -0,0 +1,254 @@
{
"array_types" :
[
{
"alignment" : 1,
"linker_set_key" : "_ZTIA2_c",
"name" : "char[2]",
"referenced_type" : "_ZTIc",
"self_type" : "_ZTIA2_c",
"size" : 2,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
}
],
"builtin_types" :
[
{
"alignment" : 1,
"is_integral" : true,
"is_unsigned" : true,
"linker_set_key" : "_ZTIc",
"name" : "char",
"referenced_type" : "_ZTIc",
"self_type" : "_ZTIc",
"size" : 1
},
{
"linker_set_key" : "_ZTIv",
"name" : "void",
"referenced_type" : "_ZTIv",
"self_type" : "_ZTIv"
}
],
"elf_functions" :
[
{
"name" : "ConstParameter"
},
{
"name" : "MultipleConst"
},
{
"name" : "Restrict"
},
{
"name" : "VolatileParameter"
},
{
"name" : "_Z11ConstReturnv"
},
{
"name" : "_Z14VolatileReturnv"
}
],
"elf_objects" : [],
"enum_types" : [],
"function_types" : [],
"functions" :
[
{
"function_name" : "ConstParameter",
"linker_set_key" : "ConstParameter",
"parameters" :
[
{
"referenced_type" : "_ZTIRA2_Kc"
}
],
"return_type" : "_ZTIv",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"function_name" : "MultipleConst",
"linker_set_key" : "MultipleConst",
"parameters" :
[
{
"referenced_type" : "_ZTIKPKPKc"
}
],
"return_type" : "_ZTIPPc",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"function_name" : "Restrict",
"linker_set_key" : "Restrict",
"parameters" :
[
{
"referenced_type" : "_ZTIPc"
}
],
"return_type" : "_ZTIv",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"function_name" : "VolatileParameter",
"linker_set_key" : "VolatileParameter",
"parameters" :
[
{
"referenced_type" : "_ZTIOV6Struct"
}
],
"return_type" : "_ZTIv",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"function_name" : "ConstReturn",
"linker_set_key" : "_Z11ConstReturnv",
"return_type" : "_ZTIRc",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"function_name" : "VolatileReturn",
"linker_set_key" : "_Z14VolatileReturnv",
"return_type" : "_ZTIO6Struct",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
}
],
"global_vars" : [],
"lvalue_reference_types" :
[
{
"alignment" : 8,
"linker_set_key" : "_ZTIRA2_Kc",
"name" : "const char (&)[2]",
"referenced_type" : "_ZTIA2_Kc",
"self_type" : "_ZTIRA2_Kc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"alignment" : 8,
"linker_set_key" : "_ZTIRc",
"name" : "char &",
"referenced_type" : "_ZTIc",
"self_type" : "_ZTIRc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
}
],
"pointer_types" :
[
{
"alignment" : 8,
"linker_set_key" : "_ZTIPKPKc",
"name" : "const char *const *",
"referenced_type" : "_ZTIKPKc",
"self_type" : "_ZTIPKPKc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"alignment" : 8,
"linker_set_key" : "_ZTIPKc",
"name" : "const char *",
"referenced_type" : "_ZTIKc",
"self_type" : "_ZTIPKc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"alignment" : 8,
"linker_set_key" : "_ZTIPPc",
"name" : "char **",
"referenced_type" : "_ZTIPc",
"self_type" : "_ZTIPPc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"alignment" : 8,
"linker_set_key" : "_ZTIPc",
"name" : "char *",
"referenced_type" : "_ZTIc",
"self_type" : "_ZTIPc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
}
],
"qualified_types" :
[
{
"alignment" : 1,
"is_const" : true,
"linker_set_key" : "_ZTIA2_Kc",
"name" : "const char[2]",
"referenced_type" : "_ZTIA2_c",
"self_type" : "_ZTIA2_Kc",
"size" : 2,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"alignment" : 8,
"is_const" : true,
"linker_set_key" : "_ZTIKPKPKc",
"name" : "const char *const *const",
"referenced_type" : "_ZTIPKPKc",
"self_type" : "_ZTIKPKPKc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"alignment" : 8,
"is_const" : true,
"linker_set_key" : "_ZTIKPKc",
"name" : "const char *const",
"referenced_type" : "_ZTIPKc",
"self_type" : "_ZTIKPKc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"alignment" : 1,
"is_const" : true,
"linker_set_key" : "_ZTIKc",
"name" : "const char",
"referenced_type" : "_ZTIc",
"self_type" : "_ZTIKc",
"size" : 1,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"is_volatile" : true,
"linker_set_key" : "_ZTIV6Struct",
"name" : "volatile Struct",
"referenced_type" : "_ZTI6Struct",
"self_type" : "_ZTIV6Struct",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
}
],
"record_types" : [],
"rvalue_reference_types" :
[
{
"alignment" : 8,
"linker_set_key" : "_ZTIO6Struct",
"name" : "Struct &&",
"referenced_type" : "_ZTI6Struct",
"self_type" : "_ZTIO6Struct",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
},
{
"alignment" : 8,
"linker_set_key" : "_ZTIOV6Struct",
"name" : "volatile Struct &&",
"referenced_type" : "_ZTIV6Struct",
"self_type" : "_ZTIOV6Struct",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/extensions.h"
}
]
}

View File

@@ -0,0 +1,244 @@
{
"array_types" :
[
{
"alignment" : 1,
"linker_set_key" : "_ZTIA2_c",
"name" : "char[2]",
"referenced_type" : "_ZTIc",
"self_type" : "_ZTIA2_c",
"size" : 2,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
}
],
"builtin_types" :
[
{
"alignment" : 1,
"is_integral" : true,
"is_unsigned" : true,
"linker_set_key" : "_ZTIc",
"name" : "char",
"referenced_type" : "_ZTIc",
"self_type" : "_ZTIc",
"size" : 1
},
{
"linker_set_key" : "_ZTIv",
"name" : "void",
"referenced_type" : "_ZTIv",
"self_type" : "_ZTIv"
}
],
"elf_functions" :
[
{
"name" : "ConstParameter"
},
{
"name" : "MultipleConst"
},
{
"name" : "Restrict"
},
{
"name" : "VolatileParameter"
},
{
"name" : "_Z11ConstReturnv"
},
{
"name" : "_Z14VolatileReturnv"
}
],
"elf_objects" : [],
"enum_types" : [],
"function_types" : [],
"functions" :
[
{
"function_name" : "ConstParameter",
"linker_set_key" : "ConstParameter",
"parameters" :
[
{
"referenced_type" : "_ZTIRA2_c"
}
],
"return_type" : "_ZTIv",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"function_name" : "MultipleConst",
"linker_set_key" : "MultipleConst",
"parameters" :
[
{
"referenced_type" : "_ZTIPPc"
}
],
"return_type" : "_ZTIPKPKc",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"function_name" : "Restrict",
"linker_set_key" : "Restrict",
"parameters" :
[
{
"referenced_type" : "_ZTIrPc"
}
],
"return_type" : "_ZTIv",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"function_name" : "VolatileParameter",
"linker_set_key" : "VolatileParameter",
"parameters" :
[
{
"referenced_type" : "_ZTIO6Struct"
}
],
"return_type" : "_ZTIv",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"function_name" : "ConstReturn",
"linker_set_key" : "_Z11ConstReturnv",
"return_type" : "_ZTIRKc",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"function_name" : "VolatileReturn",
"linker_set_key" : "_Z14VolatileReturnv",
"return_type" : "_ZTIOV6Struct",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
}
],
"global_vars" : [],
"lvalue_reference_types" :
[
{
"alignment" : 8,
"linker_set_key" : "_ZTIRA2_c",
"name" : "char (&)[2]",
"referenced_type" : "_ZTIA2_c",
"self_type" : "_ZTIRA2_c",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"alignment" : 8,
"linker_set_key" : "_ZTIRKc",
"name" : "const char &",
"referenced_type" : "_ZTIKc",
"self_type" : "_ZTIRKc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
}
],
"pointer_types" :
[
{
"alignment" : 8,
"linker_set_key" : "_ZTIPKPKc",
"name" : "const char *const *",
"referenced_type" : "_ZTIKPKc",
"self_type" : "_ZTIPKPKc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"alignment" : 8,
"linker_set_key" : "_ZTIPKc",
"name" : "const char *",
"referenced_type" : "_ZTIKc",
"self_type" : "_ZTIPKc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"alignment" : 8,
"linker_set_key" : "_ZTIPPc",
"name" : "char **",
"referenced_type" : "_ZTIPc",
"self_type" : "_ZTIPPc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"alignment" : 8,
"linker_set_key" : "_ZTIPc",
"name" : "char *",
"referenced_type" : "_ZTIc",
"self_type" : "_ZTIPc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
}
],
"qualified_types" :
[
{
"alignment" : 8,
"is_const" : true,
"linker_set_key" : "_ZTIKPKc",
"name" : "const char *const",
"referenced_type" : "_ZTIPKc",
"self_type" : "_ZTIKPKc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"alignment" : 1,
"is_const" : true,
"linker_set_key" : "_ZTIKc",
"name" : "const char",
"referenced_type" : "_ZTIc",
"self_type" : "_ZTIKc",
"size" : 1,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"is_volatile" : true,
"linker_set_key" : "_ZTIV6Struct",
"name" : "volatile Struct",
"referenced_type" : "_ZTI6Struct",
"self_type" : "_ZTIV6Struct",
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"alignment" : 8,
"is_restricted" : true,
"linker_set_key" : "_ZTIrPc",
"name" : "char *__restrict",
"referenced_type" : "_ZTIPc",
"self_type" : "_ZTIrPc",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
}
],
"record_types" : [],
"rvalue_reference_types" :
[
{
"alignment" : 8,
"linker_set_key" : "_ZTIO6Struct",
"name" : "Struct &&",
"referenced_type" : "_ZTI6Struct",
"self_type" : "_ZTIO6Struct",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
},
{
"alignment" : 8,
"linker_set_key" : "_ZTIOV6Struct",
"name" : "volatile Struct &&",
"referenced_type" : "_ZTIV6Struct",
"self_type" : "_ZTIOV6Struct",
"size" : 8,
"source_file" : "development/vndk/tools/header-checker/tests/integration/function_extensions/include/base.h"
}
]
}

View File

@@ -441,6 +441,21 @@ class HeaderCheckerTest(unittest.TestCase):
flags=["-input-format-new", "Json", "-input-format-old", "Json"],
create_old=False, create_new=False)
def test_function_extensions(self):
diff = self.prepare_and_run_abi_diff_all_archs(
"libfunction_extensions", "liballowed_function_extensions", 4,
flags=["-input-format-new", "Json", "-input-format-old", "Json"],
create_old=False, create_new=False)
self.assertEqual(6, diff.count('function_extension_diffs'))
diff = self.prepare_and_run_abi_diff_all_archs(
"liballowed_function_extensions", "libfunction_extensions", 8,
flags=["-input-format-new", "Json", "-input-format-old", "Json"],
create_old=False, create_new=False)
# Adding and removing __restrict__ at the first level are extensions.
self.assertEqual(1, diff.count('function_extension_diffs'))
self.assertEqual(5, diff.count('function_diffs'))
if __name__ == '__main__':
unittest.main()