tint: Fix ProgramBuilder::WrapInFunction overload not being picked up

Before this change, the variadic function template version of
WrapInFunction would be selected when passing a utils::VectorRef<const
ast::Statement*>, even though an overload exists for that type. The
reason is that during type deduction, the compiler will select templates
over non-templates in its overload set. The only way around this was to
avoid type-deduction by explicitly casting the argument to
utils::VectorRef<const ast::Statement*>.

This CL adds a CanWrapInStatement metafunction that evaluates to true if
the arg type is one that could be passed to
ProgramBuilder::WrapInStatement. This is used to SFINAE in the variadic
args version of WrapInFunction.

Change-Id: I8aa3d69e2ce7324fd60b1b2a5906a51d51b549a3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/115502
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Antonio Maiorano <amaiorano@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
Antonio Maiorano 2022-12-23 17:56:56 +00:00 committed by Dawn LUCI CQ
parent 16024a982d
commit dfa92a9cb6
1 changed files with 18 additions and 2 deletions

View File

@ -149,6 +149,10 @@ struct IsVectorLike<utils::VectorRef<T>> {
};
} // namespace detail
// Forward declare metafunction that evaluates to true iff T can be wrapped in a statement.
template <typename T, typename = void>
struct CanWrapInStatement;
/// ProgramBuilder is a mutable builder for a Program.
/// To construct a Program, populate the builder and then `std::move` it to a
/// Program.
@ -3326,12 +3330,13 @@ class ProgramBuilder {
/// by the Resolver.
/// @param args a mix of ast::Expression, ast::Statement, ast::Variables.
/// @returns the function
template <typename... ARGS>
template <typename... ARGS,
typename = traits::EnableIf<(CanWrapInStatement<ARGS>::value && ...)>>
const ast::Function* WrapInFunction(ARGS&&... args) {
utils::Vector stmts{
WrapInStatement(std::forward<ARGS>(args))...,
};
return WrapInFunction(utils::VectorRef<const ast::Statement*>{std::move(stmts)});
return WrapInFunction(std::move(stmts));
}
/// @param stmts a list of ast::Statement that will be wrapped by a function,
/// so that each statement is reachable by the Resolver.
@ -3411,6 +3416,17 @@ inline ProgramID ProgramIDOf(const ProgramBuilder* builder) {
return builder->ID();
}
// Primary template for metafunction that evaluates to true iff T can be wrapped in a statement.
template <typename T, typename /* = void */>
struct CanWrapInStatement : std::false_type {};
// Specialization of CanWrapInStatement
template <typename T>
struct CanWrapInStatement<
T,
std::void_t<decltype(std::declval<ProgramBuilder>().WrapInStatement(std::declval<T>()))>>
: std::true_type {};
} // namespace tint
#endif // SRC_TINT_PROGRAM_BUILDER_H_