resolver: Validate that a call statement has no return value

Also split out validation tests from call_test.cc into call_validation_test.cc.

Bug: tint:886
Change-Id: I1e1dee9b7c348363e89080cdecd3119cc004658f
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/54063
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
Ben Clayton 2021-06-11 13:22:27 +00:00
parent 0f1efe04c3
commit 7fe0106b12
24 changed files with 288 additions and 197 deletions

View File

@ -590,6 +590,7 @@ if(${TINT_BUILD_TESTS})
resolver/block_test.cc resolver/block_test.cc
resolver/builtins_validation_test.cc resolver/builtins_validation_test.cc
resolver/call_test.cc resolver/call_test.cc
resolver/call_validation_test.cc
resolver/control_block_validation_test.cc resolver/control_block_validation_test.cc
resolver/decoration_validation_test.cc resolver/decoration_validation_test.cc
resolver/entry_point_validation_test.cc resolver/entry_point_validation_test.cc

View File

@ -97,7 +97,7 @@ fn f1(p0 : f32, p1 : i32) -> f32 {
[[stage(fragment)]] [[stage(fragment)]]
fn main() { fn main() {
f1(1.0, 2); ignore(f1(1.0, 2));
} }
let declaration_order_check_0 : i32 = 1; let declaration_order_check_0 : i32 = 1;

View File

@ -2755,8 +2755,8 @@ TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam,
Func("ep", ast::VariableList(), ty.void_(), Func("ep", ast::VariableList(), ty.void_(),
ast::StatementList{ ast::StatementList{
create<ast::CallStatement>(Call("textureLoad", "foo_texture", Ignore(Call("textureLoad", "foo_texture", "foo_coords",
"foo_coords", "foo_sample_index")), "foo_sample_index")),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -3013,8 +3013,7 @@ TEST_P(InspectorGetDepthTextureResourceBindingsTestWithParam,
Func("ep", ast::VariableList(), ty.void_(), Func("ep", ast::VariableList(), ty.void_(),
ast::StatementList{ ast::StatementList{
create<ast::CallStatement>( Ignore(Call("textureDimensions", "dt", "dt_level")),
Call("textureDimensions", "dt", "dt_level")),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -3056,7 +3055,7 @@ TEST_F(InspectorGetExternalTextureResourceBindingsTest, Simple) {
Func("ep", ast::VariableList(), ty.void_(), Func("ep", ast::VariableList(), ty.void_(),
ast::StatementList{ ast::StatementList{
create<ast::CallStatement>(Call("textureDimensions", "et")), Ignore(Call("textureDimensions", "et")),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),

View File

@ -123,7 +123,7 @@ ast::Statement* ProgramBuilder::WrapInStatement(ast::Literal* lit) {
ast::Statement* ProgramBuilder::WrapInStatement(ast::Expression* expr) { ast::Statement* ProgramBuilder::WrapInStatement(ast::Expression* expr) {
if (auto* ce = expr->As<ast::CallExpression>()) { if (auto* ce = expr->As<ast::CallExpression>()) {
return create<ast::CallStatement>(ce); return Ignore(ce);
} }
// Create a temporary variable of inferred type from expr. // Create a temporary variable of inferred type from expr.
return Decl(Const(symbols_.New(), nullptr, expr)); return Decl(Const(symbols_.New(), nullptr, expr));

View File

@ -26,6 +26,7 @@
#include "src/ast/bool.h" #include "src/ast/bool.h"
#include "src/ast/bool_literal.h" #include "src/ast/bool_literal.h"
#include "src/ast/call_expression.h" #include "src/ast/call_expression.h"
#include "src/ast/call_statement.h"
#include "src/ast/case_statement.h" #include "src/ast/case_statement.h"
#include "src/ast/depth_texture.h" #include "src/ast/depth_texture.h"
#include "src/ast/external_texture.h" #include "src/ast/external_texture.h"
@ -1426,6 +1427,14 @@ class ProgramBuilder {
ExprList(std::forward<ARGS>(args)...)); ExprList(std::forward<ARGS>(args)...));
} }
/// @param expr the expression to ignore
/// @returns a `ast::CallStatement` that calls the `ignore` intrinsic which is
/// passed the single `expr` argument
template <typename EXPR>
ast::CallStatement* Ignore(EXPR&& expr) {
return create<ast::CallStatement>(Call("ignore", Expr(expr)));
}
/// @param lhs the left hand argument to the addition operation /// @param lhs the left hand argument to the addition operation
/// @param rhs the right hand argument to the addition operation /// @param rhs the right hand argument to the addition operation
/// @returns a `ast::BinaryExpression` summing the arguments `lhs` and `rhs` /// @returns a `ast::BinaryExpression` summing the arguments `lhs` and `rhs`

View File

@ -351,7 +351,7 @@ TEST_P(FloatAllMatching, Scalar) {
params.push_back(Expr(1.0f)); params.push_back(Expr(1.0f));
} }
auto* builtin = Call(name, params); auto* builtin = Call(name, params);
Func("func", {}, ty.void_(), {create<ast::CallStatement>(builtin)}, Func("func", {}, ty.void_(), {Ignore(builtin)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
@ -367,7 +367,7 @@ TEST_P(FloatAllMatching, Vec2) {
params.push_back(vec2<f32>(1.0f, 1.0f)); params.push_back(vec2<f32>(1.0f, 1.0f));
} }
auto* builtin = Call(name, params); auto* builtin = Call(name, params);
Func("func", {}, ty.void_(), {create<ast::CallStatement>(builtin)}, Func("func", {}, ty.void_(), {Ignore(builtin)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
@ -383,7 +383,7 @@ TEST_P(FloatAllMatching, Vec3) {
params.push_back(vec3<f32>(1.0f, 1.0f, 1.0f)); params.push_back(vec3<f32>(1.0f, 1.0f, 1.0f));
} }
auto* builtin = Call(name, params); auto* builtin = Call(name, params);
Func("func", {}, ty.void_(), {create<ast::CallStatement>(builtin)}, Func("func", {}, ty.void_(), {Ignore(builtin)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
@ -399,7 +399,7 @@ TEST_P(FloatAllMatching, Vec4) {
params.push_back(vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f)); params.push_back(vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
} }
auto* builtin = Call(name, params); auto* builtin = Call(name, params);
Func("func", {}, ty.void_(), {create<ast::CallStatement>(builtin)}, Func("func", {}, ty.void_(), {Ignore(builtin)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();

View File

@ -58,56 +58,6 @@ using u32 = builder::u32;
using ResolverCallTest = ResolverTest; using ResolverCallTest = ResolverTest;
TEST_F(ResolverCallTest, Recursive_Invalid) {
// fn main() {main(); }
SetSource(Source::Location{12, 34});
auto* call_expr = Call("main");
ast::VariableList params0;
Func("main", params0, ty.void_(),
ast::StatementList{
create<ast::CallStatement>(call_expr),
},
ast::DecorationList{
Stage(ast::PipelineStage::kVertex),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error v-0004: recursion is not permitted. 'main' attempted "
"to call "
"itself.");
}
TEST_F(ResolverCallTest, Undeclared_Invalid) {
// fn main() {func(); return; }
// fn func() { return; }
SetSource(Source::Location{12, 34});
auto* call_expr = Call("func");
ast::VariableList params0;
Func("main", params0, ty.f32(),
ast::StatementList{
create<ast::CallStatement>(call_expr),
Return(),
},
ast::DecorationList{});
Func("func", params0, ty.f32(),
ast::StatementList{
Return(),
},
ast::DecorationList{});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: v-0006: unable to find called function: func");
}
struct Params { struct Params {
builder::ast_expr_func_ptr create_value; builder::ast_expr_func_ptr create_value;
builder::ast_type_func_ptr create_type; builder::ast_type_func_ptr create_type;
@ -153,42 +103,6 @@ TEST_F(ResolverCallTest, Valid) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
} }
TEST_F(ResolverCallTest, TooFewArgs) {
Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
{Return()});
auto* call = Call(Source{{12, 34}}, "foo", 1);
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
"12:34 error: too few arguments in call to 'foo', expected 2, got 1");
}
TEST_F(ResolverCallTest, TooManyArgs) {
Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
{Return()});
auto* call = Call(Source{{12, 34}}, "foo", 1, 1.0f, 1.0f);
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
"12:34 error: too many arguments in call to 'foo', expected 2, got 3");
}
TEST_F(ResolverCallTest, MismatchedArgs) {
Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
{Return()});
auto* call = Call("foo", Expr(Source{{12, 34}}, true), 1.0f);
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: type mismatch for argument 1 in call to 'foo', "
"expected 'i32', got 'bool'");
}
} // namespace } // namespace
} // namespace resolver } // namespace resolver
} // namespace tint } // namespace tint

View File

@ -0,0 +1,135 @@
// Copyright 2021 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/resolver/resolver.h"
#include "gmock/gmock.h"
#include "src/ast/call_statement.h"
#include "src/resolver/resolver_test_helper.h"
namespace tint {
namespace resolver {
namespace {
using ResolverCallValidationTest = ResolverTest;
TEST_F(ResolverCallValidationTest, Recursive_Invalid) {
// fn main() {main(); }
SetSource(Source::Location{12, 34});
auto* call_expr = Call("main");
ast::VariableList params0;
Func("main", params0, ty.void_(),
ast::StatementList{
create<ast::CallStatement>(call_expr),
},
ast::DecorationList{
Stage(ast::PipelineStage::kVertex),
});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error v-0004: recursion is not permitted. 'main' attempted "
"to call "
"itself.");
}
TEST_F(ResolverCallValidationTest, Undeclared_Invalid) {
// fn main() {func(); return; }
// fn func() { return; }
SetSource(Source::Location{12, 34});
auto* call_expr = Call("func");
ast::VariableList params0;
Func("main", params0, ty.f32(),
ast::StatementList{
create<ast::CallStatement>(call_expr),
Return(),
},
ast::DecorationList{});
Func("func", params0, ty.f32(),
ast::StatementList{
Return(),
},
ast::DecorationList{});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: v-0006: unable to find called function: func");
}
TEST_F(ResolverCallValidationTest, TooFewArgs) {
Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
{Return()});
auto* call = Call(Source{{12, 34}}, "foo", 1);
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
"12:34 error: too few arguments in call to 'foo', expected 2, got 1");
}
TEST_F(ResolverCallValidationTest, TooManyArgs) {
Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
{Return()});
auto* call = Call(Source{{12, 34}}, "foo", 1, 1.0f, 1.0f);
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(
r()->error(),
"12:34 error: too many arguments in call to 'foo', expected 2, got 3");
}
TEST_F(ResolverCallValidationTest, MismatchedArgs) {
Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
{Return()});
auto* call = Call("foo", Expr(Source{{12, 34}}, true), 1.0f);
WrapInFunction(call);
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: type mismatch for argument 1 in call to 'foo', "
"expected 'i32', got 'bool'");
}
TEST_F(ResolverCallValidationTest, UnusedRetval) {
// fn main() {func(); return; }
// fn func() { return; }
Func("func", {}, ty.f32(), {Return(Expr(1.0f))}, {});
Func("main", {}, ty.f32(),
ast::StatementList{
create<ast::CallStatement>(Source{{12, 34}}, Call("func")),
Return(),
},
{});
EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(),
"12:34 error: result of called function was not used. If this was "
"intentional wrap the function call in ignore()");
}
} // namespace
} // namespace resolver
} // namespace tint

View File

@ -55,7 +55,7 @@ TEST_P(ResolverIntrinsicDerivativeTest, Scalar) {
Global("ident", ty.f32(), ast::StorageClass::kInput); Global("ident", ty.f32(), ast::StorageClass::kInput);
auto* expr = Call(name, "ident"); auto* expr = Call(name, "ident");
Func("func", {}, ty.void_(), {create<ast::CallStatement>(expr)}, Func("func", {}, ty.void_(), {Ignore(expr)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
@ -69,7 +69,7 @@ TEST_P(ResolverIntrinsicDerivativeTest, Vector) {
Global("ident", ty.vec4<f32>(), ast::StorageClass::kInput); Global("ident", ty.vec4<f32>(), ast::StorageClass::kInput);
auto* expr = Call(name, "ident"); auto* expr = Call(name, "ident");
Func("func", {}, ty.void_(), {create<ast::CallStatement>(expr)}, Func("func", {}, ty.void_(), {Ignore(expr)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
@ -1938,7 +1938,7 @@ TEST_P(ResolverIntrinsicTest_Texture, Call) {
param.buildSamplerVariable(this); param.buildSamplerVariable(this);
auto* call = Call(param.function, param.args(this)); auto* call = Call(param.function, param.args(this));
Func("func", {}, ty.void_(), {create<ast::CallStatement>(call)}, Func("func", {}, ty.void_(), {Ignore(call)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
ASSERT_TRUE(r()->Resolve()) << r()->error(); ASSERT_TRUE(r()->Resolve()) << r()->error();

View File

@ -53,8 +53,7 @@ TEST_F(ResolverIntrinsicValidationTest, InvalidPipelineStageDirect) {
auto* dpdx = create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"), auto* dpdx = create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"),
ast::ExpressionList{Expr(1.0f)}); ast::ExpressionList{Expr(1.0f)});
Func(Source{{1, 2}}, "func", ast::VariableList{}, ty.void_(), Func(Source{{1, 2}}, "func", ast::VariableList{}, ty.void_(), {Ignore(dpdx)},
{create<ast::CallStatement>(dpdx)},
{Stage(ast::PipelineStage::kCompute)}); {Stage(ast::PipelineStage::kCompute)});
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
@ -70,18 +69,16 @@ TEST_F(ResolverIntrinsicValidationTest, InvalidPipelineStageIndirect) {
auto* dpdx = create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"), auto* dpdx = create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"),
ast::ExpressionList{Expr(1.0f)}); ast::ExpressionList{Expr(1.0f)});
Func(Source{{1, 2}}, "f0", ast::VariableList{}, ty.void_(), Func(Source{{1, 2}}, "f0", ast::VariableList{}, ty.void_(), {Ignore(dpdx)});
{create<ast::CallStatement>(dpdx)});
Func(Source{{3, 4}}, "f1", ast::VariableList{}, ty.void_(), Func(Source{{3, 4}}, "f1", ast::VariableList{}, ty.void_(),
{create<ast::CallStatement>(Call("f0"))}); {Ignore(Call("f0"))});
Func(Source{{5, 6}}, "f2", ast::VariableList{}, ty.void_(), Func(Source{{5, 6}}, "f2", ast::VariableList{}, ty.void_(),
{create<ast::CallStatement>(Call("f1"))}); {Ignore(Call("f1"))});
Func(Source{{7, 8}}, "main", ast::VariableList{}, ty.void_(), Func(Source{{7, 8}}, "main", ast::VariableList{}, ty.void_(),
{create<ast::CallStatement>(Call("f2"))}, {Ignore(Call("f2"))}, {Stage(ast::PipelineStage::kCompute)});
{Stage(ast::PipelineStage::kCompute)});
EXPECT_FALSE(r()->Resolve()); EXPECT_FALSE(r()->Resolve());
EXPECT_EQ(r()->error(), EXPECT_EQ(r()->error(),

View File

@ -1436,7 +1436,13 @@ bool Resolver::Statement(ast::Statement* stmt) {
} }
if (auto* c = stmt->As<ast::CallStatement>()) { if (auto* c = stmt->As<ast::CallStatement>()) {
Mark(c->expr()); Mark(c->expr());
return Expression(c->expr()); if (!Expression(c->expr())) {
return false;
}
if (!ValidateCallStatement(c)) {
return false;
}
return true;
} }
if (auto* c = stmt->As<ast::CaseStatement>()) { if (auto* c = stmt->As<ast::CaseStatement>()) {
return CaseStatement(c); return CaseStatement(c);
@ -1710,6 +1716,40 @@ bool Resolver::Call(ast::CallExpression* call) {
return true; return true;
} }
bool Resolver::ValidateCallStatement(ast::CallStatement* stmt) {
const sem::Type* return_type = nullptr;
// A function call is made to either a user declared function or an intrinsic.
// function_calls_ only maps CallExpression to user declared functions
auto it = function_calls_.find(stmt->expr());
if (it != function_calls_.end()) {
return_type = it->second.function->return_type;
} else {
// Must be an intrinsic call
auto* target = builder_->Sem().Get(stmt->expr())->Target();
if (auto* intrinsic = target->As<sem::Intrinsic>()) {
return_type = intrinsic->ReturnType();
} else {
TINT_ICE(diagnostics_) << "call target was not an intrinsic, but a "
<< intrinsic->TypeInfo().name;
}
}
if (!return_type->Is<sem::Void>()) {
// https://gpuweb.github.io/gpuweb/wgsl/#function-call-statement
// A function call statement executes a function call where the called
// function does not return a value. If the called function returns a value,
// that value must be consumed either through assignment, evaluation in
// another expression or through use of the ignore built-in function (see
// §16.13 Value-steering functions).
diagnostics_.add_error(
"result of called function was not used. If this was intentional wrap "
"the function call in ignore()",
stmt->source());
return false;
}
return true;
}
bool Resolver::IntrinsicCall(ast::CallExpression* call, bool Resolver::IntrinsicCall(ast::CallExpression* call,
sem::IntrinsicType intrinsic_type) { sem::IntrinsicType intrinsic_type) {
std::vector<const sem::Type*> arg_tys; std::vector<const sem::Type*> arg_tys;

View File

@ -39,6 +39,7 @@ class BinaryExpression;
class BitcastExpression; class BitcastExpression;
class CallExpression; class CallExpression;
class CaseStatement; class CaseStatement;
class CallStatement;
class ConstructorExpression; class ConstructorExpression;
class Function; class Function;
class IdentifierExpression; class IdentifierExpression;
@ -255,6 +256,7 @@ class Resolver {
uint32_t el_align, uint32_t el_align,
const Source& source); const Source& source);
bool ValidateAssignment(const ast::AssignmentStatement* a); bool ValidateAssignment(const ast::AssignmentStatement* a);
bool ValidateCallStatement(ast::CallStatement* stmt);
bool ValidateEntryPoint(const ast::Function* func, const FunctionInfo* info); bool ValidateEntryPoint(const ast::Function* func, const FunctionInfo* info);
bool ValidateFunction(const ast::Function* func, const FunctionInfo* info); bool ValidateFunction(const ast::Function* func, const FunctionInfo* info);
bool ValidateGlobalVariable(const VariableInfo* var); bool ValidateGlobalVariable(const VariableInfo* var);

View File

@ -266,7 +266,7 @@ TEST_F(ResolverTest, Stmt_Switch) {
TEST_F(ResolverTest, Stmt_Call) { TEST_F(ResolverTest, Stmt_Call) {
ast::VariableList params; ast::VariableList params;
Func("my_func", params, ty.f32(), {Return(0.0f)}, ast::DecorationList{}); Func("my_func", params, ty.void_(), {Return()}, ast::DecorationList{});
auto* expr = Call("my_func"); auto* expr = Call("my_func");
@ -276,7 +276,7 @@ TEST_F(ResolverTest, Stmt_Call) {
EXPECT_TRUE(r()->Resolve()) << r()->error(); EXPECT_TRUE(r()->Resolve()) << r()->error();
ASSERT_NE(TypeOf(expr), nullptr); ASSERT_NE(TypeOf(expr), nullptr);
EXPECT_TRUE(TypeOf(expr)->Is<sem::F32>()); EXPECT_TRUE(TypeOf(expr)->Is<sem::Void>());
EXPECT_EQ(StmtOf(expr), call); EXPECT_EQ(StmtOf(expr), call);
} }

View File

@ -53,7 +53,7 @@ fn test(vert_idx : u32) -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> {
test(vert_idx); ignore(test(vert_idx));
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -72,7 +72,7 @@ fn test(vert_idx : u32) -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> {
test((vert_idx + tint_symbol_1.first_vertex_index)); ignore(test((vert_idx + tint_symbol_1.first_vertex_index)));
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -100,7 +100,7 @@ fn test(inst_idx : u32) -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry([[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry([[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> {
test(inst_idx); ignore(test(inst_idx));
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -119,7 +119,7 @@ fn test(inst_idx : u32) -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry([[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry([[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> {
test((inst_idx + tint_symbol_1.first_instance_index)); ignore(test((inst_idx + tint_symbol_1.first_instance_index)));
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -152,7 +152,7 @@ struct Inputs {
[[stage(vertex)]] [[stage(vertex)]]
fn entry(inputs : Inputs) -> [[builtin(position)]] vec4<f32> { fn entry(inputs : Inputs) -> [[builtin(position)]] vec4<f32> {
test(inputs.instance_idx, inputs.vert_idx); ignore(test(inputs.instance_idx, inputs.vert_idx));
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -179,7 +179,7 @@ struct Inputs {
[[stage(vertex)]] [[stage(vertex)]]
fn entry(inputs : Inputs) -> [[builtin(position)]] vec4<f32> { fn entry(inputs : Inputs) -> [[builtin(position)]] vec4<f32> {
test((inputs.instance_idx + tint_symbol_1.first_instance_index), (inputs.vert_idx + tint_symbol_1.first_vertex_index)); ignore(test((inputs.instance_idx + tint_symbol_1.first_instance_index), (inputs.vert_idx + tint_symbol_1.first_vertex_index)));
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -211,7 +211,7 @@ fn func2(vert_idx : u32) -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> {
func2(vert_idx); ignore(func2(vert_idx));
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -234,7 +234,7 @@ fn func2(vert_idx : u32) -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> {
func2((vert_idx + tint_symbol_1.first_vertex_index)); ignore(func2((vert_idx + tint_symbol_1.first_vertex_index)));
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -262,19 +262,19 @@ fn func(i : u32) -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry_a([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry_a([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> {
func(vert_idx); ignore(func(vert_idx));
return vec4<f32>(); return vec4<f32>();
} }
[[stage(vertex)]] [[stage(vertex)]]
fn entry_b([[builtin(vertex_index)]] vert_idx : u32, [[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry_b([[builtin(vertex_index)]] vert_idx : u32, [[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> {
func(vert_idx + inst_idx); ignore(func(vert_idx + inst_idx));
return vec4<f32>(); return vec4<f32>();
} }
[[stage(vertex)]] [[stage(vertex)]]
fn entry_c([[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry_c([[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> {
func(inst_idx); ignore(func(inst_idx));
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -294,19 +294,19 @@ fn func(i : u32) -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry_a([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry_a([[builtin(vertex_index)]] vert_idx : u32) -> [[builtin(position)]] vec4<f32> {
func((vert_idx + tint_symbol_1.first_vertex_index)); ignore(func((vert_idx + tint_symbol_1.first_vertex_index)));
return vec4<f32>(); return vec4<f32>();
} }
[[stage(vertex)]] [[stage(vertex)]]
fn entry_b([[builtin(vertex_index)]] vert_idx : u32, [[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry_b([[builtin(vertex_index)]] vert_idx : u32, [[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> {
func(((vert_idx + tint_symbol_1.first_vertex_index) + (inst_idx + tint_symbol_1.first_instance_index))); ignore(func(((vert_idx + tint_symbol_1.first_vertex_index) + (inst_idx + tint_symbol_1.first_instance_index))));
return vec4<f32>(); return vec4<f32>();
} }
[[stage(vertex)]] [[stage(vertex)]]
fn entry_c([[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> { fn entry_c([[builtin(instance_index)]] inst_idx : u32) -> [[builtin(position)]] vec4<f32> {
func((inst_idx + tint_symbol_1.first_instance_index)); ignore(func((inst_idx + tint_symbol_1.first_instance_index)));
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -338,7 +338,7 @@ fn test() -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry() { fn entry() {
test(); ignore(test());
pos = vec4<f32>(); pos = vec4<f32>();
} }
)"; )";
@ -361,7 +361,7 @@ fn test() -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry() { fn entry() {
test(); ignore(test());
pos = vec4<f32>(); pos = vec4<f32>();
} }
)"; )";
@ -393,7 +393,7 @@ fn test() -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry() { fn entry() {
test(); ignore(test());
pos = vec4<f32>(); pos = vec4<f32>();
} }
)"; )";
@ -416,7 +416,7 @@ fn test() -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry() { fn entry() {
test(); ignore(test());
pos = vec4<f32>(); pos = vec4<f32>();
} }
)"; )";
@ -448,7 +448,7 @@ fn test() -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry() { fn entry() {
test(); ignore(test());
pos = vec4<f32>(); pos = vec4<f32>();
} }
)"; )";
@ -474,7 +474,7 @@ fn test() -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry() { fn entry() {
test(); ignore(test());
pos = vec4<f32>(); pos = vec4<f32>();
} }
)"; )";
@ -509,7 +509,7 @@ fn func2() -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry() { fn entry() {
func2(); ignore(func2());
pos = vec4<f32>(); pos = vec4<f32>();
} }
)"; )";
@ -536,7 +536,7 @@ fn func2() -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry() { fn entry() {
func2(); ignore(func2());
pos = vec4<f32>(); pos = vec4<f32>();
} }
)"; )";

View File

@ -50,7 +50,7 @@ fn test() -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn entry() -> [[builtin(position)]] vec4<f32> { fn entry() -> [[builtin(position)]] vec4<f32> {
test(); ignore(test());
return vec4<f32>(); return vec4<f32>();
} }
)"; )";
@ -64,7 +64,7 @@ fn tint_symbol_1() -> u32 {
[[stage(vertex)]] [[stage(vertex)]]
fn tint_symbol_2() -> [[builtin(position)]] vec4<f32> { fn tint_symbol_2() -> [[builtin(position)]] vec4<f32> {
tint_symbol_1(); ignore(tint_symbol_1());
return vec4<f32>(); return vec4<f32>();
} }
)"; )";

View File

@ -166,7 +166,7 @@ TEST_P(HlslIntrinsicTest, Emit) {
auto* call = GenerateCall(param.intrinsic, param.type, this); auto* call = GenerateCall(param.intrinsic, param.type, this);
ASSERT_NE(nullptr, call) << "Unhandled intrinsic"; ASSERT_NE(nullptr, call) << "Unhandled intrinsic";
Func("func", {}, ty.void_(), {create<ast::CallStatement>(call)}, Func("func", {}, ty.void_(), {Ignore(call)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
@ -327,7 +327,7 @@ TEST_F(HlslGeneratorImplTest_Intrinsic, Frexp_Scalar_i32) {
float tint_tmp; float tint_tmp;
float tint_tmp_1 = frexp(1.0f, tint_tmp); float tint_tmp_1 = frexp(1.0f, tint_tmp);
exp = int(tint_tmp); exp = int(tint_tmp);
(void) tint_tmp_1; tint_tmp_1;
)")); )"));
} }
@ -343,7 +343,7 @@ TEST_F(HlslGeneratorImplTest_Intrinsic, Frexp_Vector_i32) {
float3 tint_tmp; float3 tint_tmp;
float3 tint_tmp_1 = frexp(float3(0.0f, 0.0f, 0.0f), tint_tmp); float3 tint_tmp_1 = frexp(float3(0.0f, 0.0f, 0.0f), tint_tmp);
res = int3(tint_tmp); res = int3(tint_tmp);
(void) tint_tmp_1; tint_tmp_1;
)")); )"));
} }

View File

@ -361,7 +361,7 @@ TEST_P(HlslGeneratorIntrinsicTextureTest, Call) {
Func("main", ast::VariableList{}, ty.void_(), Func("main", ast::VariableList{}, ty.void_(),
ast::StatementList{ ast::StatementList{
create<ast::CallStatement>(call), Ignore(call),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),

View File

@ -360,8 +360,7 @@ TEST_P(HlslDepthTexturesTest, Emit) {
create<ast::GroupDecoration>(2), create<ast::GroupDecoration>(2),
}); });
Func("main", {}, ty.void_(), Func("main", {}, ty.void_(), {Ignore(Call("textureDimensions", "tex"))},
{create<ast::CallStatement>(Call("textureDimensions", "tex"))},
{Stage(ast::PipelineStage::kFragment)}); {Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
@ -419,8 +418,7 @@ TEST_P(HlslSampledTexturesTest, Emit) {
create<ast::GroupDecoration>(2), create<ast::GroupDecoration>(2),
}); });
Func("main", {}, ty.void_(), Func("main", {}, ty.void_(), {Ignore(Call("textureDimensions", "tex"))},
{create<ast::CallStatement>(Call("textureDimensions", "tex"))},
{Stage(ast::PipelineStage::kFragment)}); {Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
@ -562,8 +560,7 @@ TEST_P(HlslStorageTexturesTest, Emit) {
create<ast::GroupDecoration>(2), create<ast::GroupDecoration>(2),
}); });
Func("main", {}, ty.void_(), Func("main", {}, ty.void_(), {Ignore(Call("textureDimensions", "tex"))},
{create<ast::CallStatement>(Call("textureDimensions", "tex"))},
{Stage(ast::PipelineStage::kFragment)}); {Stage(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();

View File

@ -180,7 +180,7 @@ TEST_P(MslIntrinsicTest, Emit) {
auto* call = GenerateCall(param.intrinsic, param.type, this); auto* call = GenerateCall(param.intrinsic, param.type, this);
ASSERT_NE(nullptr, call) << "Unhandled intrinsic"; ASSERT_NE(nullptr, call) << "Unhandled intrinsic";
Func("func", {}, ty.void_(), {create<ast::CallStatement>(call)}, Func("func", {}, ty.void_(), {Ignore(call)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();
@ -346,8 +346,7 @@ TEST_F(MslGeneratorImplTest, Ignore) {
Func("f", {Param("a", ty.i32()), Param("b", ty.i32()), Param("c", ty.i32())}, Func("f", {Param("a", ty.i32()), Param("b", ty.i32()), Param("c", ty.i32())},
ty.i32(), {Return(Mul(Add("a", "b"), "c"))}); ty.i32(), {Return(Mul(Add("a", "b"), "c"))});
Func("func", {}, ty.void_(), Func("func", {}, ty.void_(), {Ignore(Call("f", 1, 2, 3))},
{create<ast::CallStatement>(Call("ignore", Call("f", 1, 2, 3)))},
{Stage(ast::PipelineStage::kCompute)}); {Stage(ast::PipelineStage::kCompute)});
GeneratorImpl& gen = Build(); GeneratorImpl& gen = Build();

View File

@ -263,7 +263,7 @@ TEST_P(MslGeneratorIntrinsicTextureTest, Call) {
Func("main", ast::VariableList{}, ty.void_(), Func("main", ast::VariableList{}, ty.void_(),
ast::StatementList{ ast::StatementList{
create<ast::CallStatement>(call), Ignore(call),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),

View File

@ -82,7 +82,7 @@ TEST_F(BuilderTest, Statement_Call) {
auto* func = auto* func =
Func("main", {}, ty.void_(), ast::StatementList{}, ast::DecorationList{}); Func("main", {}, ty.void_(), ast::StatementList{}, ast::DecorationList{});
auto* expr = create<ast::CallStatement>(Call("a_func", 1.f, 1.f)); auto* expr = Ignore(Call("a_func", 1.f, 1.f));
WrapInFunction(expr); WrapInFunction(expr);
@ -100,7 +100,7 @@ OpName %10 "main"
%1 = OpTypeFunction %2 %2 %2 %1 = OpTypeFunction %2 %2 %2
%9 = OpTypeVoid %9 = OpTypeVoid
%8 = OpTypeFunction %9 %8 = OpTypeFunction %9
%13 = OpConstant %2 1 %14 = OpConstant %2 1
%3 = OpFunction %2 None %1 %3 = OpFunction %2 None %1
%4 = OpFunctionParameter %2 %4 = OpFunctionParameter %2
%5 = OpFunctionParameter %2 %5 = OpFunctionParameter %2
@ -110,7 +110,7 @@ OpReturnValue %7
OpFunctionEnd OpFunctionEnd
%10 = OpFunction %9 None %8 %10 = OpFunction %9 None %8
%11 = OpLabel %11 = OpLabel
%12 = OpFunctionCall %2 %3 %13 %13 %13 = OpFunctionCall %2 %3 %14 %14
OpReturn OpReturn
OpFunctionEnd OpFunctionEnd
)"); )");

View File

@ -414,7 +414,7 @@ TEST_P(IntrinsicDeriveTest, Call_Derivative_Scalar) {
auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate); auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate);
auto* expr = Call(param.name, "v"); auto* expr = Call(param.name, "v");
Func("func", {}, ty.void_(), {create<ast::CallStatement>(expr)}, Func("func", {}, ty.void_(), {Ignore(expr)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
spirv::Builder& b = Build(); spirv::Builder& b = Build();
@ -440,7 +440,7 @@ TEST_P(IntrinsicDeriveTest, Call_Derivative_Vector) {
auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate); auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
auto* expr = Call(param.name, "v"); auto* expr = Call(param.name, "v");
Func("func", {}, ty.void_(), {create<ast::CallStatement>(expr)}, Func("func", {}, ty.void_(), {Ignore(expr)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
spirv::Builder& b = Build(); spirv::Builder& b = Build();
@ -538,8 +538,8 @@ TEST_F(IntrinsicBuilderTest, Call_TextureSampleCompare_Twice) {
auto* expr2 = Call("textureSampleCompare", "texture", "sampler", auto* expr2 = Call("textureSampleCompare", "texture", "sampler",
vec2<f32>(1.0f, 2.0f), 2.0f); vec2<f32>(1.0f, 2.0f), 2.0f);
Func("f1", {}, ty.void_(), {create<ast::CallStatement>(expr1)}, {}); Func("f1", {}, ty.void_(), {Ignore(expr1)}, {});
Func("f2", {}, ty.void_(), {create<ast::CallStatement>(expr2)}, {}); Func("f2", {}, ty.void_(), {Ignore(expr2)}, {});
spirv::Builder& b = Build(); spirv::Builder& b = Build();
@ -1414,7 +1414,7 @@ TEST_F(IntrinsicBuilderTest, Call_Modf) {
Func("a_func", ast::VariableList{}, ty.void_(), Func("a_func", ast::VariableList{}, ty.void_(),
ast::StatementList{ ast::StatementList{
Decl(out), Decl(out),
create<ast::CallStatement>(expr), Ignore(expr),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -1425,7 +1425,7 @@ TEST_F(IntrinsicBuilderTest, Call_Modf) {
ASSERT_TRUE(b.Build()) << b.error(); ASSERT_TRUE(b.Build()) << b.error();
auto got = DumpBuilder(b); auto got = DumpBuilder(b);
auto* expect = R"(OpCapability Shader auto* expect = R"(OpCapability Shader
%11 = OpExtInstImport "GLSL.std.450" %12 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450 OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %3 "a_func" OpEntryPoint Fragment %3 "a_func"
OpExecutionMode %3 OriginUpperLeft OpExecutionMode %3 OriginUpperLeft
@ -1437,13 +1437,13 @@ OpName %5 "out"
%7 = OpTypeVector %8 2 %7 = OpTypeVector %8 2
%6 = OpTypePointer Function %7 %6 = OpTypePointer Function %7
%9 = OpConstantNull %7 %9 = OpConstantNull %7
%12 = OpConstant %8 1 %13 = OpConstant %8 1
%13 = OpConstant %8 2 %14 = OpConstant %8 2
%14 = OpConstantComposite %7 %12 %13 %15 = OpConstantComposite %7 %13 %14
%3 = OpFunction %2 None %1 %3 = OpFunction %2 None %1
%4 = OpLabel %4 = OpLabel
%5 = OpVariable %6 Function %9 %5 = OpVariable %6 Function %9
%10 = OpExtInst %7 %11 Modf %14 %5 %11 = OpExtInst %7 %12 Modf %15 %5
OpReturn OpReturn
OpFunctionEnd OpFunctionEnd
)"; )";
@ -1458,7 +1458,7 @@ TEST_F(IntrinsicBuilderTest, Call_Frexp) {
Func("a_func", ast::VariableList{}, ty.void_(), Func("a_func", ast::VariableList{}, ty.void_(),
ast::StatementList{ ast::StatementList{
Decl(out), Decl(out),
create<ast::CallStatement>(expr), Ignore(expr),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -1469,7 +1469,7 @@ TEST_F(IntrinsicBuilderTest, Call_Frexp) {
ASSERT_TRUE(b.Build()) << b.error(); ASSERT_TRUE(b.Build()) << b.error();
auto got = DumpBuilder(b); auto got = DumpBuilder(b);
auto* expect = R"(OpCapability Shader auto* expect = R"(OpCapability Shader
%13 = OpExtInstImport "GLSL.std.450" %14 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450 OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %3 "a_func" OpEntryPoint Fragment %3 "a_func"
OpExecutionMode %3 OriginUpperLeft OpExecutionMode %3 OriginUpperLeft
@ -1481,15 +1481,15 @@ OpName %5 "out"
%7 = OpTypeVector %8 2 %7 = OpTypeVector %8 2
%6 = OpTypePointer Function %7 %6 = OpTypePointer Function %7
%9 = OpConstantNull %7 %9 = OpConstantNull %7
%12 = OpTypeFloat 32 %13 = OpTypeFloat 32
%11 = OpTypeVector %12 2 %12 = OpTypeVector %13 2
%14 = OpConstant %12 1 %15 = OpConstant %13 1
%15 = OpConstant %12 2 %16 = OpConstant %13 2
%16 = OpConstantComposite %11 %14 %15 %17 = OpConstantComposite %12 %15 %16
%3 = OpFunction %2 None %1 %3 = OpFunction %2 None %1
%4 = OpLabel %4 = OpLabel
%5 = OpVariable %6 Function %9 %5 = OpVariable %6 Function %9
%10 = OpExtInst %11 %13 Frexp %16 %5 %11 = OpExtInst %12 %14 Frexp %17 %5
OpReturn OpReturn
OpFunctionEnd OpFunctionEnd
)"; )";
@ -1585,7 +1585,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_DEPRECATED) {
Func("a_func", ast::VariableList{}, ty.void_(), Func("a_func", ast::VariableList{}, ty.void_(),
ast::StatementList{ ast::StatementList{
create<ast::CallStatement>(expr), Ignore(expr),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -1604,12 +1604,12 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_DEPRECATED) {
%1 = OpVariable %2 StorageBuffer %1 = OpVariable %2 StorageBuffer
%7 = OpTypeVoid %7 = OpTypeVoid
%6 = OpTypeFunction %7 %6 = OpTypeFunction %7
%11 = OpTypeInt 32 0 %12 = OpTypeInt 32 0
)"; )";
auto got_types = DumpInstructions(b.types()); auto got_types = DumpInstructions(b.types());
EXPECT_EQ(expected_types, got_types); EXPECT_EQ(expected_types, got_types);
auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0 auto* expected_instructions = R"(%11 = OpArrayLength %12 %1 0
)"; )";
auto got_instructions = DumpInstructions(b.functions()[0].instructions()); auto got_instructions = DumpInstructions(b.functions()[0].instructions());
EXPECT_EQ(expected_instructions, got_instructions); EXPECT_EQ(expected_instructions, got_instructions);
@ -1635,7 +1635,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct_DEPRECATED) {
Func("a_func", ast::VariableList{}, ty.void_(), Func("a_func", ast::VariableList{}, ty.void_(),
ast::StatementList{ ast::StatementList{
create<ast::CallStatement>(expr), Ignore(expr),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -1654,12 +1654,12 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct_DEPRECATED) {
%1 = OpVariable %2 StorageBuffer %1 = OpVariable %2 StorageBuffer
%7 = OpTypeVoid %7 = OpTypeVoid
%6 = OpTypeFunction %7 %6 = OpTypeFunction %7
%11 = OpTypeInt 32 0 %12 = OpTypeInt 32 0
)"; )";
auto got_types = DumpInstructions(b.types()); auto got_types = DumpInstructions(b.types());
EXPECT_EQ(expected_types, got_types); EXPECT_EQ(expected_types, got_types);
auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 1 auto* expected_instructions = R"(%11 = OpArrayLength %12 %1 1
)"; )";
auto got_instructions = DumpInstructions(b.functions()[0].instructions()); auto got_instructions = DumpInstructions(b.functions()[0].instructions());
EXPECT_EQ(expected_instructions, got_instructions); EXPECT_EQ(expected_instructions, got_instructions);
@ -1680,7 +1680,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
Func("a_func", ast::VariableList{}, ty.void_(), Func("a_func", ast::VariableList{}, ty.void_(),
ast::StatementList{ ast::StatementList{
create<ast::CallStatement>(expr), Ignore(expr),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -1699,12 +1699,12 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
%1 = OpVariable %2 StorageBuffer %1 = OpVariable %2 StorageBuffer
%7 = OpTypeVoid %7 = OpTypeVoid
%6 = OpTypeFunction %7 %6 = OpTypeFunction %7
%11 = OpTypeInt 32 0 %12 = OpTypeInt 32 0
)"; )";
auto got_types = DumpInstructions(b.types()); auto got_types = DumpInstructions(b.types());
EXPECT_EQ(expected_types, got_types); EXPECT_EQ(expected_types, got_types);
auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0 auto* expected_instructions = R"(%11 = OpArrayLength %12 %1 0
)"; )";
auto got_instructions = DumpInstructions(b.functions()[0].instructions()); auto got_instructions = DumpInstructions(b.functions()[0].instructions());
EXPECT_EQ(expected_instructions, got_instructions); EXPECT_EQ(expected_instructions, got_instructions);
@ -1729,7 +1729,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
Func("a_func", ast::VariableList{}, ty.void_(), Func("a_func", ast::VariableList{}, ty.void_(),
ast::StatementList{ ast::StatementList{
create<ast::CallStatement>(expr), Ignore(expr),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -1748,12 +1748,12 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
%1 = OpVariable %2 StorageBuffer %1 = OpVariable %2 StorageBuffer
%7 = OpTypeVoid %7 = OpTypeVoid
%6 = OpTypeFunction %7 %6 = OpTypeFunction %7
%11 = OpTypeInt 32 0 %12 = OpTypeInt 32 0
)"; )";
auto got_types = DumpInstructions(b.types()); auto got_types = DumpInstructions(b.types());
EXPECT_EQ(expected_types, got_types); EXPECT_EQ(expected_types, got_types);
auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 1 auto* expected_instructions = R"(%11 = OpArrayLength %12 %1 1
)"; )";
auto got_instructions = DumpInstructions(b.functions()[0].instructions()); auto got_instructions = DumpInstructions(b.functions()[0].instructions());
EXPECT_EQ(expected_instructions, got_instructions); EXPECT_EQ(expected_instructions, got_instructions);
@ -1778,7 +1778,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_ViaLets) {
ast::StatementList{ ast::StatementList{
Decl(p), Decl(p),
Decl(p2), Decl(p2),
create<ast::CallStatement>(expr), Ignore(expr),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -1797,12 +1797,12 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_ViaLets) {
%1 = OpVariable %2 StorageBuffer %1 = OpVariable %2 StorageBuffer
%7 = OpTypeVoid %7 = OpTypeVoid
%6 = OpTypeFunction %7 %6 = OpTypeFunction %7
%11 = OpTypeInt 32 0 %12 = OpTypeInt 32 0
)"; )";
auto got_types = DumpInstructions(b.types()); auto got_types = DumpInstructions(b.types());
EXPECT_EQ(expected_types, got_types); EXPECT_EQ(expected_types, got_types);
auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0 auto* expected_instructions = R"(%11 = OpArrayLength %12 %1 0
)"; )";
auto got_instructions = DumpInstructions(b.functions()[0].instructions()); auto got_instructions = DumpInstructions(b.functions()[0].instructions());
EXPECT_EQ(expected_instructions, got_instructions); EXPECT_EQ(expected_instructions, got_instructions);
@ -1839,7 +1839,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) {
Decl(p), Decl(p),
Decl(p2), Decl(p2),
Decl(p3), Decl(p3),
create<ast::CallStatement>(expr), Ignore(expr),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -1858,12 +1858,12 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) {
%1 = OpVariable %2 StorageBuffer %1 = OpVariable %2 StorageBuffer
%7 = OpTypeVoid %7 = OpTypeVoid
%6 = OpTypeFunction %7 %6 = OpTypeFunction %7
%11 = OpTypeInt 32 0 %12 = OpTypeInt 32 0
)"; )";
auto got_types = DumpInstructions(b.types()); auto got_types = DumpInstructions(b.types());
EXPECT_EQ(expected_types, got_types); EXPECT_EQ(expected_types, got_types);
auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0 auto* expected_instructions = R"(%11 = OpArrayLength %12 %1 0
)"; )";
auto got_instructions = DumpInstructions(b.functions()[0].instructions()); auto got_instructions = DumpInstructions(b.functions()[0].instructions());
EXPECT_EQ(expected_instructions, got_instructions); EXPECT_EQ(expected_instructions, got_instructions);

View File

@ -3460,10 +3460,9 @@ TEST_P(IntrinsicTextureTest, Call) {
auto* texture = param.buildTextureVariable(this); auto* texture = param.buildTextureVariable(this);
auto* sampler = param.buildSamplerVariable(this); auto* sampler = param.buildSamplerVariable(this);
auto* call = auto* call = Call(param.function, param.args(this));
create<ast::CallExpression>(Expr(param.function), param.args(this));
Func("func", {}, ty.void_(), {create<ast::CallStatement>(call)}, Func("func", {}, ty.void_(), {Ignore(call)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
spirv::Builder& b = Build(); spirv::Builder& b = Build();
@ -3488,12 +3487,11 @@ TEST_P(IntrinsicTextureTest, ValidateSPIRV) {
param.buildTextureVariable(this); param.buildTextureVariable(this);
param.buildSamplerVariable(this); param.buildSamplerVariable(this);
auto* call = auto* call = Call(param.function, param.args(this));
create<ast::CallExpression>(Expr(param.function), param.args(this));
Func("main", ast::VariableList{}, ty.void_(), Func("main", ast::VariableList{}, ty.void_(),
ast::StatementList{ ast::StatementList{
create<ast::CallStatement>(call), Ignore(call),
}, },
ast::DecorationList{ ast::DecorationList{
Stage(ast::PipelineStage::kFragment), Stage(ast::PipelineStage::kFragment),
@ -3515,9 +3513,8 @@ TEST_P(IntrinsicTextureTest, OutsideFunction_IsError) {
auto* texture = param.buildTextureVariable(this); auto* texture = param.buildTextureVariable(this);
auto* sampler = param.buildSamplerVariable(this); auto* sampler = param.buildSamplerVariable(this);
auto* call = auto* call = Call(param.function, param.args(this));
create<ast::CallExpression>(Expr(param.function), param.args(this)); Func("func", {}, ty.void_(), {Ignore(call)},
Func("func", {}, ty.void_(), {create<ast::CallStatement>(call)},
{create<ast::StageDecoration>(ast::PipelineStage::kFragment)}); {create<ast::StageDecoration>(ast::PipelineStage::kFragment)});
spirv::Builder& b = Build(); spirv::Builder& b = Build();

View File

@ -226,6 +226,7 @@ tint_unittests_source_set("tint_unittests_core_src") {
"../src/resolver/block_test.cc", "../src/resolver/block_test.cc",
"../src/resolver/builtins_validation_test.cc", "../src/resolver/builtins_validation_test.cc",
"../src/resolver/call_test.cc", "../src/resolver/call_test.cc",
"../src/resolver/call_validation_test.cc",
"../src/resolver/control_block_validation_test.cc", "../src/resolver/control_block_validation_test.cc",
"../src/resolver/decoration_validation_test.cc", "../src/resolver/decoration_validation_test.cc",
"../src/resolver/entry_point_validation_test.cc", "../src/resolver/entry_point_validation_test.cc",