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>
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 5396cdd..4dac010 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -149,6 +149,10 @@
};
} // 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 @@
/// 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 @@
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_