Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions test/unit/analyzer_module_unit_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2521,6 +2521,9 @@ namespace
}
return parameters;
};
// The arguments' bindings, in order. An expected entry written "?name: binding" is the
// parameter of an argument that only some ABIs pass: absent, or at that place with that
// binding, its IR name the parameter's or derived from it (tag.coerce).
const auto check = [&](const LoadedModule& loaded, const char* symbol,
const std::vector<std::string>& expected)
{
Expand All @@ -2529,7 +2532,28 @@ namespace
std::string text;
for (const std::string& parameter : actual)
text += " [" + parameter + "]";
report.expect(actual == expected,
const auto passes = [](const std::string& parameter, const std::string& optional)
{
const std::size_t colon = optional.find(':');
const std::string name = optional.substr(1, colon - 1);
return parameter == optional.substr(1) ||
(parameter.starts_with(name + ".") &&
parameter.substr(parameter.find(':')) == optional.substr(colon));
};
std::size_t next = 0;
bool matches = true;
for (const std::string& entry : expected)
{
if (entry.starts_with("?"))
{
if (next < actual.size() && passes(actual[next], entry))
++next;
continue;
}
matches = matches && next < actual.size() && actual[next] == entry;
++next;
}
report.expect(matches && next == actual.size(),
std::string("ParameterDebugBinding: ") + symbol + text);
};
const auto load =
Expand Down Expand Up @@ -2574,7 +2598,8 @@ namespace
{".block_descriptor: artificial, source none", "x: int *, source 0",
"y: double *, source 1"});
// A variadic function's debug type ends with a null entry for `...`, which no parameter
// takes; an empty parameter takes no IR argument, but keeps its debug declaration.
// takes; an empty parameter keeps its debug declaration, and takes an IR argument only on
// some ABIs (an i8 under AAPCS64 on Linux, none on x86-64 or Apple arm64).
check(itanium, "_ZN7VarargsC2EPiPdz",
{"this: artificial, source none", "vtt: artificial, source none",
"x: int *, source 0", "y: double *, source 1"});
Expand All @@ -2583,7 +2608,7 @@ namespace
"x: int *, source 0", "y: double *, source 1"});
check(itanium, "_ZN6TaggedC2EPi3Tag",
{"this: artificial, source none", "vtt: artificial, source none",
"x: int *, source 0"});
"x: int *, source 0", "?tag: Tag, source 1"});
check(itanium, "_Z8make_bigPiz",
{"agg.result: artificial, source none", "p: int *, source 0"});

Expand All @@ -2598,7 +2623,7 @@ namespace
// The empty parameter comes first: x is the second parameter the source declares.
check(itanium, "_ZN8TagFirstC2E3TagPi",
{"this: artificial, source none", "vtt: artificial, source none",
"x: int *, source 1"});
"?tag: Tag, source 0", "x: int *, source 1"});

// Optimized code spills nothing: each argument is bound through its own debug records.
check(optimized, "_ZN8VariadicC2EPiPdz",
Expand Down
3 changes: 2 additions & 1 deletion test/unit/parameter_binding_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ Varargs::Varargs(int* x, double* y, ...)
seed = *x + static_cast<int>(*y);
}

// An empty parameter takes no IR argument, but keeps its debug declaration and its number.
// An empty parameter keeps its debug declaration and its number; whether it takes an IR argument
// depends on the ABI: none on x86-64 or Apple arm64, an i8 under AAPCS64 on Linux.
struct Tag
{
};
Expand Down
Loading