tint: Handle @diagnostic on block statements
Use expect_compound_statement() in all the places that use
compound_statement in the WGSL grammar.
Handle attributes on statements inside Resolver::StatementScope, so
that the logic can be reused for the various places where block
statements are used. This will also make it easier to reuse this logic
when we allow these attributes on other types of statement in the
future.
Add an `EmitBlockHeader()` helper to the WGSL writer to reuse the
logic for emitting attributes on block statements for all the places
that use them.
Bug: tint:1809
Change-Id: Iac3bb01f5031e6134c1798ddafdad080412c8bef
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/118000
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: James Price <jrprice@google.com>
diff --git a/src/tint/ast/block_statement.cc b/src/tint/ast/block_statement.cc
index 430dbba..5d75d27 100644
--- a/src/tint/ast/block_statement.cc
+++ b/src/tint/ast/block_statement.cc
@@ -23,12 +23,17 @@
BlockStatement::BlockStatement(ProgramID pid,
NodeID nid,
const Source& src,
- utils::VectorRef<const Statement*> stmts)
- : Base(pid, nid, src), statements(std::move(stmts)) {
+ utils::VectorRef<const Statement*> stmts,
+ utils::VectorRef<const Attribute*> attrs)
+ : Base(pid, nid, src), statements(std::move(stmts)), attributes(attrs) {
for (auto* stmt : statements) {
TINT_ASSERT(AST, stmt);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, stmt, program_id);
}
+ for (auto* attr : attributes) {
+ TINT_ASSERT(AST, attr);
+ TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
+ }
}
BlockStatement::BlockStatement(BlockStatement&&) = default;
@@ -39,7 +44,8 @@
// Clone arguments outside of create() call to have deterministic ordering
auto src = ctx->Clone(source);
auto stmts = ctx->Clone(statements);
- return ctx->dst->create<BlockStatement>(src, std::move(stmts));
+ auto attrs = ctx->Clone(attributes);
+ return ctx->dst->create<BlockStatement>(src, std::move(stmts), std::move(attrs));
}
} // namespace tint::ast
diff --git a/src/tint/ast/block_statement.h b/src/tint/ast/block_statement.h
index 22d0a65..87989d8 100644
--- a/src/tint/ast/block_statement.h
+++ b/src/tint/ast/block_statement.h
@@ -19,6 +19,11 @@
#include "src/tint/ast/statement.h"
+// Forward declarations
+namespace tint::ast {
+class Attribute;
+} // namespace tint::ast
+
namespace tint::ast {
/// A block statement
@@ -29,10 +34,12 @@
/// @param nid the unique node identifier
/// @param source the block statement source
/// @param statements the statements
+ /// @param attributes the block statement attributes
BlockStatement(ProgramID pid,
NodeID nid,
const Source& source,
- utils::VectorRef<const Statement*> statements);
+ utils::VectorRef<const Statement*> statements,
+ utils::VectorRef<const Attribute*> attributes);
/// Move constructor
BlockStatement(BlockStatement&&);
~BlockStatement() override;
@@ -51,6 +58,9 @@
/// the statement list
const utils::Vector<const Statement*, 8> statements;
+
+ /// the attribute list
+ const utils::Vector<const Attribute*, 4> attributes;
};
} // namespace tint::ast
diff --git a/src/tint/ast/block_statement_test.cc b/src/tint/ast/block_statement_test.cc
index ec92c3f..f88aa4c 100644
--- a/src/tint/ast/block_statement_test.cc
+++ b/src/tint/ast/block_statement_test.cc
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include "gmock/gmock.h"
#include "gtest/gtest-spi.h"
#include "src/tint/ast/discard_statement.h"
#include "src/tint/ast/if_statement.h"
@@ -26,21 +27,35 @@
auto* d = create<DiscardStatement>();
auto* ptr = d;
- auto* b = create<BlockStatement>(utils::Vector{d});
+ auto* b = create<BlockStatement>(utils::Vector{d}, utils::Empty);
ASSERT_EQ(b->statements.Length(), 1u);
EXPECT_EQ(b->statements[0], ptr);
+ EXPECT_EQ(b->attributes.Length(), 0u);
}
TEST_F(BlockStatementTest, Creation_WithSource) {
- auto* b = create<BlockStatement>(Source{Source::Location{20, 2}}, utils::Empty);
+ auto* b = create<BlockStatement>(Source{Source::Location{20, 2}}, utils::Empty, utils::Empty);
auto src = b->source;
EXPECT_EQ(src.range.begin.line, 20u);
EXPECT_EQ(src.range.begin.column, 2u);
}
+TEST_F(BlockStatementTest, Creation_WithAttributes) {
+ auto* d = create<DiscardStatement>();
+ auto* ptr = d;
+
+ auto* attr1 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, Expr("foo"));
+ auto* attr2 = DiagnosticAttribute(ast::DiagnosticSeverity::kOff, Expr("bar"));
+ auto* b = create<BlockStatement>(utils::Vector{d}, utils::Vector{attr1, attr2});
+
+ ASSERT_EQ(b->statements.Length(), 1u);
+ EXPECT_EQ(b->statements[0], ptr);
+ EXPECT_THAT(b->attributes, testing::ElementsAre(attr1, attr2));
+}
+
TEST_F(BlockStatementTest, IsBlock) {
- auto* b = create<BlockStatement>(utils::Empty);
+ auto* b = create<BlockStatement>(utils::Empty, utils::Empty);
EXPECT_TRUE(b->Is<BlockStatement>());
}
@@ -48,7 +63,8 @@
EXPECT_FATAL_FAILURE(
{
ProgramBuilder b;
- b.create<BlockStatement>(utils::Vector<const ast::Statement*, 1>{nullptr});
+ b.create<BlockStatement>(utils::Vector<const ast::Statement*, 1>{nullptr},
+ utils::Empty);
},
"internal compiler error");
}
@@ -58,7 +74,7 @@
{
ProgramBuilder b1;
ProgramBuilder b2;
- b1.create<BlockStatement>(utils::Vector{b2.create<DiscardStatement>()});
+ b1.create<BlockStatement>(utils::Vector{b2.create<DiscardStatement>()}, utils::Empty);
},
"internal compiler error");
}
diff --git a/src/tint/ast/case_statement_test.cc b/src/tint/ast/case_statement_test.cc
index 04b887b..af0fb33 100644
--- a/src/tint/ast/case_statement_test.cc
+++ b/src/tint/ast/case_statement_test.cc
@@ -31,7 +31,7 @@
utils::Vector b{selector};
auto* discard = create<DiscardStatement>();
- auto* body = create<BlockStatement>(utils::Vector{discard});
+ auto* body = create<BlockStatement>(utils::Vector{discard}, utils::Empty);
auto* c = create<CaseStatement>(b, body);
ASSERT_EQ(c->selectors.Length(), 1u);
@@ -45,7 +45,7 @@
utils::Vector b{selector};
auto* discard = create<DiscardStatement>();
- auto* body = create<BlockStatement>(utils::Vector{discard});
+ auto* body = create<BlockStatement>(utils::Vector{discard}, utils::Empty);
auto* c = create<CaseStatement>(b, body);
ASSERT_EQ(c->selectors.Length(), 1u);
@@ -56,22 +56,24 @@
TEST_F(CaseStatementTest, ContainsDefault_WithDefault) {
utils::Vector b{CaseSelector(2_u), DefaultCaseSelector()};
- auto* c = create<CaseStatement>(b, create<BlockStatement>(utils::Empty));
+ auto* c = create<CaseStatement>(b, create<BlockStatement>(utils::Empty, utils::Empty));
EXPECT_TRUE(c->ContainsDefault());
}
TEST_F(CaseStatementTest, ContainsDefault_WithOutDefault) {
utils::Vector b{CaseSelector(2_u), CaseSelector(3_u)};
- auto* c = create<CaseStatement>(b, create<BlockStatement>(utils::Empty));
+ auto* c = create<CaseStatement>(b, create<BlockStatement>(utils::Empty, utils::Empty));
EXPECT_FALSE(c->ContainsDefault());
}
TEST_F(CaseStatementTest, Creation_WithSource) {
utils::Vector b{CaseSelector(2_i)};
- auto* body = create<BlockStatement>(utils::Vector{
- create<DiscardStatement>(),
- });
+ auto* body = create<BlockStatement>(
+ utils::Vector{
+ create<DiscardStatement>(),
+ },
+ utils::Empty);
auto* c = create<CaseStatement>(Source{Source::Location{20, 2}}, b, body);
auto src = c->source;
EXPECT_EQ(src.range.begin.line, 20u);
@@ -80,7 +82,7 @@
TEST_F(CaseStatementTest, IsCase) {
auto* c = create<CaseStatement>(utils::Vector{DefaultCaseSelector()},
- create<BlockStatement>(utils::Empty));
+ create<BlockStatement>(utils::Empty, utils::Empty));
EXPECT_TRUE(c->Is<CaseStatement>());
}
@@ -98,7 +100,7 @@
{
ProgramBuilder b;
b.create<CaseStatement>(utils::Vector<const ast::CaseSelector*, 1>{nullptr},
- b.create<BlockStatement>(utils::Empty));
+ b.create<BlockStatement>(utils::Empty, utils::Empty));
},
"internal compiler error");
}
@@ -109,7 +111,7 @@
ProgramBuilder b1;
ProgramBuilder b2;
b1.create<CaseStatement>(utils::Vector{b1.DefaultCaseSelector()},
- b2.create<BlockStatement>(utils::Empty));
+ b2.create<BlockStatement>(utils::Empty, utils::Empty));
},
"internal compiler error");
}
@@ -120,7 +122,7 @@
ProgramBuilder b1;
ProgramBuilder b2;
b1.create<CaseStatement>(utils::Vector{b2.CaseSelector(b2.Expr(2_i))},
- b1.create<BlockStatement>(utils::Empty));
+ b1.create<BlockStatement>(utils::Empty, utils::Empty));
},
"internal compiler error");
}
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index c05abf9..1c60784 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -2456,7 +2456,8 @@
/// @param type the function return type
/// @param body the function body
/// @param attributes the optional function attributes
- /// @param return_type_attributes the optional function return type
+ /// @param return_type_attributes the optional function return type attributes
+ /// @param body_attributes the optional function body attributes
/// attributes
/// @returns the function pointer
template <typename NAME>
@@ -2467,11 +2468,12 @@
const ast::Type* type,
utils::VectorRef<const ast::Statement*> body,
utils::VectorRef<const ast::Attribute*> attributes = utils::Empty,
- utils::VectorRef<const ast::Attribute*> return_type_attributes = utils::Empty) {
- auto* func =
- create<ast::Function>(source, Sym(std::forward<NAME>(name)), std::move(params), type,
- create<ast::BlockStatement>(std::move(body)),
- std::move(attributes), std::move(return_type_attributes));
+ utils::VectorRef<const ast::Attribute*> return_type_attributes = utils::Empty,
+ utils::VectorRef<const ast::Attribute*> body_attributes = utils::Empty) {
+ auto* func = create<ast::Function>(
+ source, Sym(std::forward<NAME>(name)), std::move(params), type,
+ create<ast::BlockStatement>(std::move(body), std::move(body_attributes)),
+ std::move(attributes), std::move(return_type_attributes));
AST().AddFunction(func);
return func;
}
@@ -2482,7 +2484,8 @@
/// @param type the function return type
/// @param body the function body
/// @param attributes the optional function attributes
- /// @param return_type_attributes the optional function return type
+ /// @param return_type_attributes the optional function return type attributes
+ /// @param body_attributes the optional function body attributes
/// attributes
/// @returns the function pointer
template <typename NAME>
@@ -2492,11 +2495,12 @@
const ast::Type* type,
utils::VectorRef<const ast::Statement*> body,
utils::VectorRef<const ast::Attribute*> attributes = utils::Empty,
- utils::VectorRef<const ast::Attribute*> return_type_attributes = utils::Empty) {
- auto* func =
- create<ast::Function>(Sym(std::forward<NAME>(name)), std::move(params), type,
- create<ast::BlockStatement>(std::move(body)),
- std::move(attributes), std::move(return_type_attributes));
+ utils::VectorRef<const ast::Attribute*> return_type_attributes = utils::Empty,
+ utils::VectorRef<const ast::Attribute*> body_attributes = utils::Empty) {
+ auto* func = create<ast::Function>(
+ Sym(std::forward<NAME>(name)), std::move(params), type,
+ create<ast::BlockStatement>(std::move(body), std::move(body_attributes)),
+ std::move(attributes), std::move(return_type_attributes));
AST().AddFunction(func);
return func;
}
@@ -2676,23 +2680,50 @@
/// @param source the source information for the block
/// @param statements statements of block
/// @returns the block statement pointer
- template <typename... Statements>
- const ast::BlockStatement* Block(const Source& source, Statements&&... statements) {
+ template <typename... STATEMENTS, typename = DisableIfVectorLike<STATEMENTS...>>
+ const ast::BlockStatement* Block(const Source& source, STATEMENTS&&... statements) {
return create<ast::BlockStatement>(
- source, utils::Vector<const ast::Statement*, sizeof...(statements)>{
- std::forward<Statements>(statements)...,
- });
+ source,
+ utils::Vector<const ast::Statement*, sizeof...(statements)>{
+ std::forward<STATEMENTS>(statements)...,
+ },
+ utils::Empty);
}
/// Creates a ast::BlockStatement with input statements
/// @param statements statements of block
/// @returns the block statement pointer
- template <typename... STATEMENTS, typename = DisableIfSource<STATEMENTS...>>
+ template <typename... STATEMENTS,
+ typename = DisableIfSource<STATEMENTS...>,
+ typename = DisableIfVectorLike<STATEMENTS...>>
const ast::BlockStatement* Block(STATEMENTS&&... statements) {
return create<ast::BlockStatement>(
utils::Vector<const ast::Statement*, sizeof...(statements)>{
std::forward<STATEMENTS>(statements)...,
- });
+ },
+ utils::Empty);
+ }
+
+ /// Creates a ast::BlockStatement with input statements and attributes
+ /// @param source the source information for the block
+ /// @param statements statements of block
+ /// @param attributes the attributes
+ /// @returns the block statement pointer
+ const ast::BlockStatement* Block(
+ const Source& source,
+ utils::VectorRef<const ast::Statement*> statements,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ return create<ast::BlockStatement>(source, std::move(statements), std::move(attributes));
+ }
+
+ /// Creates a ast::BlockStatement with input statements and attributes
+ /// @param statements statements of block
+ /// @param attributes the attributes
+ /// @returns the block statement pointer
+ const ast::BlockStatement* Block(
+ utils::VectorRef<const ast::Statement*> statements,
+ utils::VectorRef<const ast::Attribute*> attributes = utils::Empty) {
+ return create<ast::BlockStatement>(std::move(statements), std::move(attributes));
}
/// A wrapper type for the Else statement used to create If statements.
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index 9ea9866..bf4088a 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -882,7 +882,7 @@
auto* builder = AddStatementBuilder<IfStatementBuilder>(cond);
PushNewStatementBlock(top.GetConstruct(), end_id, [=](const StatementList& stmts) {
- builder->body = create<ast::BlockStatement>(Source{}, stmts);
+ builder->body = create<ast::BlockStatement>(Source{}, stmts, utils::Empty);
});
}
@@ -894,7 +894,7 @@
auto* builder = AddStatementBuilder<IfStatementBuilder>(cond);
PushNewStatementBlock(top.GetConstruct(), end_id, [=](const StatementList& stmts) {
- builder->body = create<ast::BlockStatement>(Source{}, stmts);
+ builder->body = create<ast::BlockStatement>(Source{}, stmts, utils::Empty);
});
}
@@ -985,7 +985,7 @@
statements_stack_[0].Finalize(&builder_);
auto& statements = statements_stack_[0].GetStatements();
- auto* body = create<ast::BlockStatement>(Source{}, statements);
+ auto* body = create<ast::BlockStatement>(Source{}, statements, utils::Empty);
// Maintain the invariant by repopulating the one and only element.
statements_stack_.Clear();
@@ -1407,7 +1407,7 @@
}
}
- auto* body = create<ast::BlockStatement>(source, stmts);
+ auto* body = create<ast::BlockStatement>(source, stmts, utils::Empty);
AttributeList fn_attrs;
fn_attrs.Push(create<ast::StageAttribute>(source, ep_info_->stage));
@@ -2938,7 +2938,7 @@
if (!stmts.IsEmpty()) {
// The "else" consists of the statement list from the top of
// statements stack, without an "else if" condition.
- builder->else_stmt = create<ast::BlockStatement>(Source{}, stmts);
+ builder->else_stmt = create<ast::BlockStatement>(Source{}, stmts, utils::Empty);
}
});
if (false_is_break) {
@@ -2985,7 +2985,7 @@
// Push the then clause onto the stack.
PushNewStatementBlock(construct, then_end, [=](const StatementList& stmts) {
- builder->body = create<ast::BlockStatement>(Source{}, stmts);
+ builder->body = create<ast::BlockStatement>(Source{}, stmts, utils::Empty);
});
if (true_is_break) {
AddStatement(create<ast::BreakStatement>(Source{}));
@@ -3098,7 +3098,7 @@
auto case_idx = swch->cases.Length();
swch->cases.Push(nullptr);
PushNewStatementBlock(construct, end_id, [=](const StatementList& stmts) {
- auto* body = create<ast::BlockStatement>(Source{}, stmts);
+ auto* body = create<ast::BlockStatement>(Source{}, stmts, utils::Empty);
swch->cases[case_idx] = create<ast::CaseStatement>(Source{}, selectors, body);
});
@@ -3113,7 +3113,7 @@
bool FunctionEmitter::EmitLoopStart(const Construct* construct) {
auto* builder = AddStatementBuilder<LoopStatementBuilder>();
PushNewStatementBlock(construct, construct->end_id, [=](const StatementList& stmts) {
- builder->body = create<ast::BlockStatement>(Source{}, stmts);
+ builder->body = create<ast::BlockStatement>(Source{}, stmts, utils::Empty);
});
return success();
}
@@ -3128,7 +3128,7 @@
"expected loop on top of stack";
}
PushNewStatementBlock(construct, construct->end_id, [=](const StatementList& stmts) {
- loop->continuing = create<ast::BlockStatement>(Source{}, stmts);
+ loop->continuing = create<ast::BlockStatement>(Source{}, stmts, utils::Empty);
});
return success();
@@ -3354,11 +3354,11 @@
if (then_stmt != nullptr) {
if_stmts.Push(then_stmt);
}
- auto* if_block = create<ast::BlockStatement>(Source{}, if_stmts);
+ auto* if_block = create<ast::BlockStatement>(Source{}, if_stmts, utils::Empty);
const ast::Statement* else_block = nullptr;
if (else_stmt) {
- else_block = create<ast::BlockStatement>(StatementList{else_stmt});
+ else_block = create<ast::BlockStatement>(StatementList{else_stmt}, utils::Empty);
}
auto* if_stmt = create<ast::IfStatement>(Source{}, condition, if_block, else_block);
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index f7aa4b8..5d056ae 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -1500,7 +1500,7 @@
// function body. The AST isn't used as we've already errored, but this
// catches any errors inside the body, and can help keep the parser in
// sync.
- expect_compound_statement();
+ expect_compound_statement("function body");
}
return Failure::kErrored;
}
@@ -1510,7 +1510,7 @@
bool errored = false;
- auto body = expect_compound_statement();
+ auto body = expect_compound_statement("function body");
if (body.errored) {
errored = true;
}
@@ -1666,14 +1666,26 @@
}
// compound_statement
-// : BRACE_LEFT statement* BRACE_RIGHT
-Expect<ast::BlockStatement*> ParserImpl::expect_compound_statement() {
- return expect_brace_block("", [&]() -> Expect<ast::BlockStatement*> {
+// : attribute* BRACE_LEFT statement* BRACE_RIGHT
+Expect<ast::BlockStatement*> ParserImpl::expect_compound_statement(std::string_view use) {
+ auto attrs = attribute_list();
+ if (attrs.errored) {
+ return Failure::kErrored;
+ }
+ return expect_compound_statement(attrs.value, use);
+}
+
+// compound_statement
+// : attribute* BRACE_LEFT statement* BRACE_RIGHT
+Expect<ast::BlockStatement*> ParserImpl::expect_compound_statement(AttributeList& attrs,
+ std::string_view use) {
+ return expect_brace_block(use, [&]() -> Expect<ast::BlockStatement*> {
auto stmts = expect_statements();
if (stmts.errored) {
return Failure::kErrored;
}
- return create<ast::BlockStatement>(Source{}, stmts.value);
+ TINT_DEFER(attrs.Clear());
+ return create<ast::BlockStatement>(Source{}, stmts.value, std::move(attrs));
});
}
@@ -1731,6 +1743,12 @@
// Skip empty statements
}
+ auto attrs = attribute_list();
+ if (attrs.errored) {
+ return Failure::kErrored;
+ }
+ TINT_DEFER(expect_attributes_consumed(attrs.value));
+
// Non-block statements that error can resynchronize on semicolon.
auto stmt = sync(Token::Type::kSemicolon, [&] { return non_block_statement(); });
if (stmt.errored) {
@@ -1781,7 +1799,7 @@
}
if (peek_is(Token::Type::kBraceLeft)) {
- auto body = expect_compound_statement();
+ auto body = expect_compound_statement(attrs.value, "block statement");
if (body.errored) {
return Failure::kErrored;
}
@@ -2023,7 +2041,7 @@
return add_error(peek(), "unable to parse condition expression");
}
- auto body = expect_compound_statement();
+ auto body = expect_compound_statement("if statement");
if (body.errored) {
return Failure::kErrored;
}
@@ -2059,7 +2077,7 @@
}
// If it wasn't an "else if", it must just be an "else".
- auto else_body = expect_compound_statement();
+ auto else_body = expect_compound_statement("else statement");
if (else_body.errored) {
return Failure::kErrored;
}
@@ -2119,8 +2137,8 @@
}
// switch_body
-// : CASE case_selectors COLON? BRACKET_LEFT case_body BRACKET_RIGHT
-// | DEFAULT COLON? BRACKET_LEFT case_body BRACKET_RIGHT
+// : CASE case_selectors COLON? compound_statement
+// | DEFAULT COLON? compound_statement
Maybe<const ast::CaseStatement*> ParserImpl::switch_body() {
if (!peek_is(Token::Type::kCase) && !peek_is(Token::Type::kDefault)) {
return Failure::kNoMatch;
@@ -2145,14 +2163,10 @@
match(Token::Type::kColon);
const char* use = "case statement";
- auto body = expect_brace_block(use, [&] { return case_body(); });
-
+ auto body = expect_compound_statement(use);
if (body.errored) {
return Failure::kErrored;
}
- if (!body.matched) {
- return add_error(body.source, "expected case body");
- }
return create<ast::CaseStatement>(t.source(), selector_list, body.value);
}
@@ -2231,7 +2245,7 @@
stmts.Push(stmt.value);
}
- return create<ast::BlockStatement>(Source{}, stmts);
+ return create<ast::BlockStatement>(Source{}, stmts, utils::Empty);
}
// loop_statement
@@ -2253,7 +2267,7 @@
return Failure::kErrored;
}
- auto* body = create<ast::BlockStatement>(source, stmts.value);
+ auto* body = create<ast::BlockStatement>(source, stmts.value, utils::Empty);
return create<ast::LoopStatement>(source, body, continuing.value);
});
}
@@ -2345,7 +2359,7 @@
}
// for_statement
-// : FOR PAREN_LEFT for_header PAREN_RIGHT BRACE_LEFT statements BRACE_RIGHT
+// : FOR PAREN_LEFT for_header PAREN_RIGHT compound_statement
Maybe<const ast::ForLoopStatement*> ParserImpl::for_statement() {
Source source;
if (!match(Token::Type::kFor, &source)) {
@@ -2357,14 +2371,13 @@
return Failure::kErrored;
}
- auto stmts = expect_brace_block("for loop", [&] { return expect_statements(); });
- if (stmts.errored) {
+ auto body = expect_compound_statement("for loop");
+ if (body.errored) {
return Failure::kErrored;
}
return create<ast::ForLoopStatement>(source, header->initializer, header->condition,
- header->continuing,
- create<ast::BlockStatement>(stmts.value));
+ header->continuing, body.value);
}
// while_statement
@@ -2383,7 +2396,7 @@
return add_error(peek(), "unable to parse while condition expression");
}
- auto body = expect_compound_statement();
+ auto body = expect_compound_statement("while loop");
if (body.errored) {
return Failure::kErrored;
}
@@ -2491,7 +2504,7 @@
stmts.Push(stmt.value);
}
- return create<ast::BlockStatement>(Source{}, stmts);
+ return create<ast::BlockStatement>(Source{}, stmts, utils::Empty);
});
}
@@ -2499,7 +2512,7 @@
// : CONTINUING continuing_compound_statement
Maybe<const ast::BlockStatement*> ParserImpl::continuing_statement() {
if (!match(Token::Type::kContinuing)) {
- return create<ast::BlockStatement>(Source{}, utils::Empty);
+ return create<ast::BlockStatement>(Source{}, utils::Empty, utils::Empty);
}
return continuing_compound_statement();
diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h
index 8101261..0936f6a 100644
--- a/src/tint/reader/wgsl/parser_impl.h
+++ b/src/tint/reader/wgsl/parser_impl.h
@@ -542,8 +542,15 @@
/// @returns the parsed builtin.
Expect<ast::BuiltinValue> expect_builtin();
/// Parses a `compound_statement` grammar element, erroring on parse failure.
+ /// @param use a description of what was being parsed if an error was raised
/// @returns the parsed statements
- Expect<ast::BlockStatement*> expect_compound_statement();
+ Expect<ast::BlockStatement*> expect_compound_statement(std::string_view use);
+ /// Parses a `compound_statement` grammar element, with the attribute list provided as `attrs`.
+ /// @param attrs the list of attributes for the statement
+ /// @param use a description of what was being parsed if an error was raised
+ /// @returns the parsed statements
+ Expect<ast::BlockStatement*> expect_compound_statement(AttributeList& attrs,
+ std::string_view use);
/// Parses a `paren_expression` grammar element, erroring on parse failure.
/// @returns the parsed element or nullptr
Expect<const ast::Expression*> expect_paren_expression();
diff --git a/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc
index 947cb48..f096fd6 100644
--- a/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_compound_stmt_test.cc
@@ -23,7 +23,7 @@
discard;
return 1 + b / 2;
})");
- auto e = p->expect_compound_statement();
+ auto e = p->expect_compound_statement("");
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
ASSERT_EQ(e->statements.Length(), 2u);
@@ -33,7 +33,7 @@
TEST_F(ParserImplTest, CompoundStmt_Empty) {
auto p = parser("{}");
- auto e = p->expect_compound_statement();
+ auto e = p->expect_compound_statement("");
ASSERT_FALSE(p->has_error()) << p->error();
ASSERT_FALSE(e.errored);
EXPECT_EQ(e->statements.Length(), 0u);
@@ -41,7 +41,7 @@
TEST_F(ParserImplTest, CompoundStmt_InvalidStmt) {
auto p = parser("{fn main() {}}");
- auto e = p->expect_compound_statement();
+ auto e = p->expect_compound_statement("");
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:2: expected '}'");
@@ -49,7 +49,7 @@
TEST_F(ParserImplTest, CompoundStmt_MissingRightParen) {
auto p = parser("{return;");
- auto e = p->expect_compound_statement();
+ auto e = p->expect_compound_statement("");
ASSERT_TRUE(p->has_error());
ASSERT_TRUE(e.errored);
EXPECT_EQ(p->error(), "1:9: expected '}'");
diff --git a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
index 5337c3c..9e5d1a7 100644
--- a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
@@ -489,7 +489,7 @@
}
TEST_F(ParserImplErrorTest, FunctionDeclMissingArrow) {
- EXPECT("fn f() f32 {}", R"(test.wgsl:1:8 error: expected '{'
+ EXPECT("fn f() f32 {}", R"(test.wgsl:1:8 error: expected '{' for function body
fn f() f32 {}
^^^
)");
@@ -526,14 +526,14 @@
}
TEST_F(ParserImplErrorTest, FunctionDeclMissingLBrace) {
- EXPECT("fn f() }", R"(test.wgsl:1:8 error: expected '{'
+ EXPECT("fn f() }", R"(test.wgsl:1:8 error: expected '{' for function body
fn f() }
^
)");
}
TEST_F(ParserImplErrorTest, FunctionDeclMissingRBrace) {
- EXPECT("fn f() {", R"(test.wgsl:1:9 error: expected '}'
+ EXPECT("fn f() {", R"(test.wgsl:1:9 error: expected '}' for function body
fn f() {
^
)");
@@ -541,9 +541,9 @@
TEST_F(ParserImplErrorTest, FunctionScopeUnusedDecl) {
EXPECT("fn f(a:i32)->i32{return a;@size(1)}",
- R"(test.wgsl:1:27 error: expected '}'
+ R"(test.wgsl:1:28 error: unexpected attributes
fn f(a:i32)->i32{return a;@size(1)}
- ^
+ ^^^^
)");
}
diff --git a/src/tint/reader/wgsl/parser_impl_function_decl_test.cc b/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
index c9f55cf..a761dde 100644
--- a/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
@@ -305,7 +305,7 @@
EXPECT_FALSE(f.matched);
EXPECT_TRUE(p->has_error());
EXPECT_EQ(f.value, nullptr);
- EXPECT_EQ(p->error(), "1:11: expected '{'");
+ EXPECT_EQ(p->error(), "1:11: expected '{' for function body");
}
} // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc
index 59e5ad3..55effc7 100644
--- a/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc
@@ -85,7 +85,7 @@
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:6: expected '{'");
+ EXPECT_EQ(p->error(), "1:6: expected '{' for if statement");
}
TEST_F(ParserImplTest, IfStmt_MissingCondition) {
@@ -105,7 +105,7 @@
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:8: expected '}'");
+ EXPECT_EQ(p->error(), "1:8: expected '}' for if statement");
}
TEST_F(ParserImplTest, IfStmt_MissingBody) {
@@ -115,7 +115,7 @@
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:5: expected '{'");
+ EXPECT_EQ(p->error(), "1:5: expected '{' for if statement");
}
TEST_F(ParserImplTest, IfStmt_InvalidElseif) {
@@ -125,7 +125,7 @@
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:21: expected '}'");
+ EXPECT_EQ(p->error(), "1:21: expected '}' for if statement");
}
TEST_F(ParserImplTest, IfStmt_InvalidElse) {
@@ -135,7 +135,7 @@
EXPECT_TRUE(e.errored);
EXPECT_EQ(e.value, nullptr);
EXPECT_TRUE(p->has_error());
- EXPECT_EQ(p->error(), "1:16: expected '}'");
+ EXPECT_EQ(p->error(), "1:16: expected '}' for else statement");
}
} // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_statement_test.cc b/src/tint/reader/wgsl/parser_impl_statement_test.cc
index f21a4e7..7371b81 100644
--- a/src/tint/reader/wgsl/parser_impl_statement_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_statement_test.cc
@@ -95,7 +95,7 @@
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:10: expected '}'");
+ EXPECT_EQ(p->error(), "1:10: expected '}' for if statement");
}
TEST_F(ParserImplTest, Statement_Variable) {
@@ -269,7 +269,7 @@
EXPECT_TRUE(e.errored);
EXPECT_FALSE(e.matched);
EXPECT_EQ(e.value, nullptr);
- EXPECT_EQ(p->error(), "1:3: expected '}'");
+ EXPECT_EQ(p->error(), "1:3: expected '}' for block statement");
}
TEST_F(ParserImplTest, Statement_ConstAssert_WithParen) {
@@ -358,5 +358,15 @@
EXPECT_EQ(sa->condition->source.range.end.column, 20u);
}
+TEST_F(ParserImplTest, Statement_UnexpectedAttributes) {
+ auto p = parser("@diagnostic(off, derivative_uniformity) return;");
+ auto e = p->statement();
+ EXPECT_TRUE(p->has_error());
+ EXPECT_FALSE(e.errored);
+ EXPECT_TRUE(e.matched);
+ EXPECT_NE(e.value, nullptr);
+ EXPECT_EQ(p->error(), "1:2: unexpected attributes");
+}
+
} // namespace
} // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc
index e516267..5cc168d 100644
--- a/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_while_stmt_test.cc
@@ -118,7 +118,7 @@
// Test a while loop with missing left brace is invalid.
TEST_F(WhileStmtErrorTest, MissingLeftBrace) {
std::string while_str = "while (true) }";
- std::string error_str = "1:14: expected '{'";
+ std::string error_str = "1:14: expected '{' for while loop";
TestWhileWithError(while_str, error_str);
}
@@ -126,7 +126,7 @@
// Test a for loop with missing right brace is invalid.
TEST_F(WhileStmtErrorTest, MissingRightBrace) {
std::string while_str = "while (true) {";
- std::string error_str = "1:15: expected '}'";
+ std::string error_str = "1:15: expected '}' for while loop";
TestWhileWithError(while_str, error_str);
}
@@ -159,7 +159,7 @@
// Test a for loop with a body not matching statements
TEST_F(WhileStmtErrorTest, InvalidBodyMatch) {
std::string while_str = "while (true) { fn main() {} }";
- std::string error_str = "1:16: expected '}'";
+ std::string error_str = "1:16: expected '}' for while loop";
TestWhileWithError(while_str, error_str);
}
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index 18200d4..a504068 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -1030,6 +1030,104 @@
12:34 note: first attribute declared here)");
}
+namespace BlockStatementTests {
+class BlockStatementTest : public TestWithParams {
+ protected:
+ void Check() {
+ if (GetParam().should_pass) {
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ } else {
+ EXPECT_FALSE(r()->Resolve());
+ EXPECT_EQ(r()->error(), "error: attribute is not valid for block statements");
+ }
+ }
+};
+TEST_P(BlockStatementTest, CompoundStatement) {
+ Func("foo", utils::Empty, ty.void_(),
+ utils::Vector{
+ Block(utils::Vector{Return()}, createAttributes({}, *this, GetParam().kind)),
+ });
+ Check();
+}
+TEST_P(BlockStatementTest, FunctionBody) {
+ Func("foo", utils::Empty, ty.void_(),
+ utils::Vector{
+ Block(utils::Vector{Return()}),
+ },
+ utils::Empty, utils::Empty, createAttributes({}, *this, GetParam().kind));
+ Check();
+}
+TEST_P(BlockStatementTest, IfStatementBody) {
+ Func("foo", utils::Empty, ty.void_(),
+ utils::Vector{
+ If(Expr(true),
+ Block(utils::Vector{Return()}, createAttributes({}, *this, GetParam().kind))),
+ });
+ Check();
+}
+TEST_P(BlockStatementTest, ElseStatementBody) {
+ Func("foo", utils::Empty, ty.void_(),
+ utils::Vector{
+ If(Expr(true), Block(utils::Vector{Return()}),
+ Else(Block(utils::Vector{Return()}, createAttributes({}, *this, GetParam().kind)))),
+ });
+ Check();
+}
+TEST_P(BlockStatementTest, ForStatementBody) {
+ Func("foo", utils::Empty, ty.void_(),
+ utils::Vector{
+ For(nullptr, Expr(true), nullptr,
+ Block(utils::Vector{Break()}, createAttributes({}, *this, GetParam().kind))),
+ });
+ Check();
+}
+TEST_P(BlockStatementTest, WhileStatementBody) {
+ Func("foo", utils::Empty, ty.void_(),
+ utils::Vector{
+ While(Expr(true),
+ Block(utils::Vector{Break()}, createAttributes({}, *this, GetParam().kind))),
+ });
+ Check();
+}
+TEST_P(BlockStatementTest, CaseStatementBody) {
+ Func("foo", utils::Empty, ty.void_(),
+ utils::Vector{
+ Switch(1_a,
+ Case(CaseSelector(1_a), Block(utils::Vector{Break()},
+ createAttributes({}, *this, GetParam().kind))),
+ DefaultCase(Block({}))),
+ });
+ Check();
+}
+TEST_P(BlockStatementTest, DefaultStatementBody) {
+ Func("foo", utils::Empty, ty.void_(),
+ utils::Vector{
+ Switch(1_a, Case(CaseSelector(1_a), Block()),
+ DefaultCase(Block(utils::Vector{Break()},
+ createAttributes({}, *this, GetParam().kind)))),
+ });
+ Check();
+}
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+ BlockStatementTest,
+ testing::Values(TestParams{AttributeKind::kAlign, false},
+ TestParams{AttributeKind::kBinding, false},
+ TestParams{AttributeKind::kBuiltin, false},
+ TestParams{AttributeKind::kDiagnostic, true},
+ TestParams{AttributeKind::kGroup, false},
+ TestParams{AttributeKind::kId, false},
+ TestParams{AttributeKind::kInterpolate, false},
+ TestParams{AttributeKind::kInvariant, false},
+ TestParams{AttributeKind::kLocation, false},
+ TestParams{AttributeKind::kOffset, false},
+ TestParams{AttributeKind::kSize, false},
+ TestParams{AttributeKind::kStage, false},
+ TestParams{AttributeKind::kStride, false},
+ TestParams{AttributeKind::kWorkgroup, false},
+ TestParams{AttributeKind::kBindingAndGroup, false}));
+
+} // namespace BlockStatementTests
+
} // namespace
} // namespace AttributeTests
diff --git a/src/tint/resolver/diagnostic_control_test.cc b/src/tint/resolver/diagnostic_control_test.cc
index 568dc23..4cf2b47 100644
--- a/src/tint/resolver/diagnostic_control_test.cc
+++ b/src/tint/resolver/diagnostic_control_test.cc
@@ -181,6 +181,66 @@
89:10 note: code is unreachable)");
}
+TEST_F(ResolverDiagnosticControlTest, BlockAttributeScope) {
+ // fn foo() @diagnostic(off, chromium_unreachable_code) {
+ // {
+ // return;
+ // return; // Should not produce a diagnostic
+ // }
+ // @diagnostic(warning, chromium_unreachable_code) {
+ // if (true) @diagnostic(info, chromium_unreachable_code) {
+ // return;
+ // return; // Should produce an info
+ // } else {
+ // while (true) @diagnostic(off, chromium_unreachable_code) {
+ // return;
+ // return; // Should not produce a diagnostic
+ // }
+ // return;
+ // return; // Should produce an warning
+ // }
+ // }
+ // }
+
+ auto attr = [&](auto severity) {
+ return utils::Vector{DiagnosticAttribute(severity, Expr("chromium_unreachable_code"))};
+ };
+ Func("foo", {}, ty.void_(),
+ utils::Vector{
+ Return(),
+ Return(Source{{12, 21}}),
+ Block(utils::Vector{
+ Block(
+ utils::Vector{
+ If(Expr(true),
+ Block(
+ utils::Vector{
+ Return(),
+ Return(Source{{34, 43}}),
+ },
+ attr(ast::DiagnosticSeverity::kInfo)),
+ Else(Block(utils::Vector{
+ While(
+ Expr(true), Block(
+ utils::Vector{
+ Return(),
+ Return(Source{{56, 65}}),
+ },
+ attr(ast::DiagnosticSeverity::kOff))),
+ Return(),
+ Return(Source{{78, 87}}),
+ }))),
+ },
+ attr(ast::DiagnosticSeverity::kWarning)),
+ }),
+ },
+ attr(ast::DiagnosticSeverity::kOff));
+
+ EXPECT_TRUE(r()->Resolve()) << r()->error();
+ EXPECT_EQ(r()->error(), R"(34:43 note: code is unreachable
+78:87 warning: code is unreachable)");
+}
+
TEST_F(ResolverDiagnosticControlTest, UnrecognizedRuleName_Directive) {
DiagnosticDirective(ast::DiagnosticSeverity::kError,
Expr(Source{{12, 34}}, "chromium_unreachable_cod"));
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 9c592fc..ac45aac 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -3845,6 +3845,43 @@
auto* as_compound = As<sem::CompoundStatement, CastFlags::kDontErrorOnImpossibleCast>(sem);
+ // Helper to handle attributes that are supported on certain types of statement.
+ auto handle_attributes = [&](auto* stmt, sem::Statement* sem_stmt, const char* use) {
+ for (auto* attr : stmt->attributes) {
+ Mark(attr);
+ if (auto* dc = attr->template As<ast::DiagnosticAttribute>()) {
+ Mark(dc->control);
+ if (!DiagnosticControl(dc->control)) {
+ return false;
+ }
+ } else {
+ std::ostringstream ss;
+ ss << "attribute is not valid for " << use;
+ AddError(ss.str(), attr->source);
+ return false;
+ }
+ }
+ if (!validator_.NoDuplicateAttributes(stmt->attributes)) {
+ return false;
+ }
+ ApplyDiagnosticSeverities(sem_stmt);
+ return true;
+ };
+
+ // Handle attributes, if necessary.
+ // Some statements can take diagnostic filtering attributes, so push a new diagnostic filter
+ // scope to capture them.
+ validator_.DiagnosticFilters().Push();
+ TINT_DEFER(validator_.DiagnosticFilters().Pop());
+ if (!Switch(
+ ast, //
+ [&](const ast::BlockStatement* block) {
+ return handle_attributes(block, sem, "block statements");
+ },
+ [&](Default) { return true; })) {
+ return nullptr;
+ }
+
TINT_SCOPED_ASSIGNMENT(current_statement_, sem);
TINT_SCOPED_ASSIGNMENT(current_compound_statement_,
as_compound ? as_compound : current_compound_statement_);
diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc
index 274287a..59e42df 100644
--- a/src/tint/resolver/uniformity_test.cc
+++ b/src/tint/resolver/uniformity_test.cc
@@ -7942,6 +7942,32 @@
}
}
+TEST_P(UniformityAnalysisDiagnosticFilterTest, AttributeOnBlock) {
+ auto& param = GetParam();
+ std::ostringstream ss;
+ ss << R"(
+@group(0) @binding(0) var<storage, read_write> non_uniform : i32;
+@group(0) @binding(1) var t : texture_2d<f32>;
+@group(0) @binding(2) var s : sampler;
+fn foo() {
+ if (non_uniform == 42))"
+ << "@diagnostic(" << param << ", derivative_uniformity)"
+ << R"({
+ let color = textureSample(t, s, vec2(0, 0));
+ }
+}
+)";
+
+ RunTest(ss.str(), param != ast::DiagnosticSeverity::kError);
+ if (param == ast::DiagnosticSeverity::kOff) {
+ EXPECT_TRUE(error_.empty());
+ } else {
+ std::ostringstream err;
+ err << ToStr(param) << ": 'textureSample' must only be called";
+ EXPECT_THAT(error_, ::testing::HasSubstr(err.str()));
+ }
+}
+
INSTANTIATE_TEST_SUITE_P(UniformityAnalysisTest,
UniformityAnalysisDiagnosticFilterTest,
::testing::Values(ast::DiagnosticSeverity::kError,
diff --git a/src/tint/sem/diagnostic_severity_test.cc b/src/tint/sem/diagnostic_severity_test.cc
index 7ede2bc..cbb37b6 100644
--- a/src/tint/sem/diagnostic_severity_test.cc
+++ b/src/tint/sem/diagnostic_severity_test.cc
@@ -30,26 +30,44 @@
void Run(ast::DiagnosticSeverity global_severity) {
// @diagnostic(off, chromium_unreachable_code)
// fn foo() {
- // return;
+ // @diagnostic(info, chromium_unreachable_code) {
+ // if (true) @diagnostic(warning, chromium_unreachable_code) {
+ // return;
+ // }
+ // }
// }
//
// fn bar() {
- // return;
+ // {
+ // if (true) {
+ // return;
+ // }
+ // }
// }
auto rule = ast::DiagnosticRule::kChromiumUnreachableCode;
auto func_severity = ast::DiagnosticSeverity::kOff;
+ auto block_severity = ast::DiagnosticSeverity::kInfo;
+ auto if_severity = ast::DiagnosticSeverity::kInfo;
+ auto attr = [&](auto severity) {
+ return utils::Vector{DiagnosticAttribute(severity, Expr("chromium_unreachable_code"))};
+ };
auto* return_1 = Return();
- auto* return_2 = Return();
+ auto* if_1 = If(Expr(true), Block(utils::Vector{return_1}, attr(if_severity)));
+ auto* block_1 = Block(utils::Vector{if_1}, attr(block_severity));
auto* func_attr = DiagnosticAttribute(func_severity, Expr("chromium_unreachable_code"));
- auto* foo = Func("foo", {}, ty.void_(), utils::Vector{return_1}, utils::Vector{func_attr});
+ auto* foo = Func("foo", {}, ty.void_(), utils::Vector{block_1}, utils::Vector{func_attr});
+
+ auto* return_2 = Return();
auto* bar = Func("bar", {}, ty.void_(), utils::Vector{return_2});
auto p = Build();
EXPECT_TRUE(p.IsValid()) << p.Diagnostics().str();
EXPECT_EQ(p.Sem().DiagnosticSeverity(foo, rule), func_severity);
- EXPECT_EQ(p.Sem().DiagnosticSeverity(return_1, rule), func_severity);
+ EXPECT_EQ(p.Sem().DiagnosticSeverity(block_1, rule), block_severity);
+ EXPECT_EQ(p.Sem().DiagnosticSeverity(if_1, rule), block_severity);
+ EXPECT_EQ(p.Sem().DiagnosticSeverity(return_1, rule), if_severity);
EXPECT_EQ(p.Sem().DiagnosticSeverity(bar, rule), global_severity);
EXPECT_EQ(p.Sem().DiagnosticSeverity(return_2, rule), global_severity);
}
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index bb91d93..4b9d512 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -353,7 +353,10 @@
}
if (func->body) {
- out << " {";
+ out << " ";
+ if (!EmitBlockHeader(out, func->body)) {
+ return false;
+ }
}
}
@@ -979,7 +982,12 @@
}
bool GeneratorImpl::EmitBlock(const ast::BlockStatement* stmt) {
- line() << "{";
+ {
+ auto out = line();
+ if (!EmitBlockHeader(out, stmt)) {
+ return false;
+ }
+ }
if (!EmitStatementsWithIndent(stmt->statements)) {
return false;
}
@@ -988,6 +996,17 @@
return true;
}
+bool GeneratorImpl::EmitBlockHeader(std::ostream& out, const ast::BlockStatement* stmt) {
+ if (!stmt->attributes.IsEmpty()) {
+ if (!EmitAttributes(out, stmt->attributes)) {
+ return false;
+ }
+ out << " ";
+ }
+ out << "{";
+ return true;
+}
+
bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
return Switch(
stmt, //
@@ -1072,7 +1091,11 @@
bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
if (stmt->selectors.Length() == 1 && stmt->ContainsDefault()) {
- line() << "default: {";
+ auto out = line();
+ out << "default: ";
+ if (!EmitBlockHeader(out, stmt->body)) {
+ return false;
+ }
} else {
auto out = line();
out << "case ";
@@ -1091,7 +1114,10 @@
return false;
}
}
- out << ": {";
+ out << ": ";
+ if (!EmitBlockHeader(out, stmt->body)) {
+ return false;
+ }
}
if (!EmitStatementsWithIndent(stmt->body->statements)) {
return false;
@@ -1135,7 +1161,10 @@
if (!EmitExpression(out, stmt->condition)) {
return false;
}
- out << ") {";
+ out << ") ";
+ if (!EmitBlockHeader(out, stmt->body)) {
+ return false;
+ }
}
if (!EmitStatementsWithIndent(stmt->body->statements)) {
@@ -1151,15 +1180,25 @@
if (!EmitExpression(out, elseif->condition)) {
return false;
}
- out << ") {";
+ out << ") ";
+ if (!EmitBlockHeader(out, elseif->body)) {
+ return false;
+ }
}
if (!EmitStatementsWithIndent(elseif->body->statements)) {
return false;
}
e = elseif->else_statement;
} else {
- line() << "} else {";
- if (!EmitStatementsWithIndent(e->As<ast::BlockStatement>()->statements)) {
+ auto* body = e->As<ast::BlockStatement>();
+ {
+ auto out = line();
+ out << "} else ";
+ if (!EmitBlockHeader(out, body)) {
+ return false;
+ }
+ }
+ if (!EmitStatementsWithIndent(body->statements)) {
return false;
}
break;
@@ -1270,7 +1309,10 @@
break;
}
}
- out << " {";
+ out << " ";
+ if (!EmitBlockHeader(out, stmt->body)) {
+ return false;
+ }
}
if (!EmitStatementsWithIndent(stmt->body->statements)) {
@@ -1294,7 +1336,10 @@
return false;
}
}
- out << " {";
+ out << " ";
+ if (!EmitBlockHeader(out, stmt->body)) {
+ return false;
+ }
}
if (!EmitStatementsWithIndent(stmt->body->statements)) {
diff --git a/src/tint/writer/wgsl/generator_impl.h b/src/tint/writer/wgsl/generator_impl.h
index 87a1b54..7a74d1e 100644
--- a/src/tint/writer/wgsl/generator_impl.h
+++ b/src/tint/writer/wgsl/generator_impl.h
@@ -93,6 +93,11 @@
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
bool EmitBlock(const ast::BlockStatement* stmt);
+ /// Handles emitting the start of a block statement (including attributes)
+ /// @param out the output stream to write the header to
+ /// @param stmt the block statement to emit the header for
+ /// @returns true if the statement was emitted successfully
+ bool EmitBlockHeader(std::ostream& out, const ast::BlockStatement* stmt);
/// Handles a break statement
/// @param stmt the statement to emit
/// @returns true if the statement was emitted successfully
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl
new file mode 100644
index 0000000..2d059b0
--- /dev/null
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl
@@ -0,0 +1,13 @@
+@group(0) @binding(1) var t : texture_2d<f32>;
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ switch (i32(x)) {
+ case 0 @diagnostic(warning, derivative_uniformity) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+ default {
+ }
+ }
+}
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..bd6e103
--- /dev/null
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.dxc.hlsl
@@ -0,0 +1,34 @@
+diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ switch(int(x)) {
+ case 0: {
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..bd6e103
--- /dev/null
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.fxc.hlsl
@@ -0,0 +1,34 @@
+diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ switch(int(x)) {
+ case 0: {
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl
new file mode 100644
index 0000000..2bf3fa9
--- /dev/null
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.glsl
@@ -0,0 +1,31 @@
+diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+#version 310 es
+precision mediump float;
+
+layout(location = 0) in float x_1;
+void tint_symbol(float x) {
+ switch(int(x)) {
+ case 0: {
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+void main() {
+ tint_symbol(x_1);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl
new file mode 100644
index 0000000..eba0e35
--- /dev/null
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.msl
@@ -0,0 +1,35 @@
+diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_2 {
+ float x [[user(locn0)]];
+};
+
+void tint_symbol_inner(float x) {
+ switch(int(x)) {
+ case 0: {
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+}
+
+fragment void tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ tint_symbol_inner(tint_symbol_1.x);
+ return;
+}
+
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.spvasm
new file mode 100644
index 0000000..391ad2e
--- /dev/null
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.spvasm
@@ -0,0 +1,64 @@
+diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %x_1
+ OpExecutionMode %main OriginUpperLeft
+ OpName %x_1 "x_1"
+ OpName %t "t"
+ OpName %s "s"
+ OpName %main_inner "main_inner"
+ OpName %x "x"
+ OpName %main "main"
+ OpDecorate %x_1 Location 0
+ OpDecorate %t DescriptorSet 0
+ OpDecorate %t Binding 1
+ OpDecorate %s DescriptorSet 0
+ OpDecorate %s Binding 2
+ %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+ %x_1 = OpVariable %_ptr_Input_float Input
+ %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
+ %t = OpVariable %_ptr_UniformConstant_6 UniformConstant
+ %9 = OpTypeSampler
+%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
+ %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void %float
+ %int = OpTypeInt 32 1
+ %20 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %10
+ %x = OpFunctionParameter %float
+ %14 = OpLabel
+ %16 = OpConvertFToS %int %x
+ OpSelectionMerge %15 None
+ OpSwitch %16 %18 0 %19
+ %19 = OpLabel
+ OpBranch %15
+ %18 = OpLabel
+ OpBranch %15
+ %15 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %20
+ %22 = OpLabel
+ %24 = OpLoad %float %x_1
+ %23 = OpFunctionCall %void %main_inner %24
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.wgsl
new file mode 100644
index 0000000..25abad6
--- /dev/null
+++ b/test/tint/diagnostic_filtering/case_body_attribute.wgsl.expected.wgsl
@@ -0,0 +1,26 @@
+diagnostic_filtering/case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ switch(i32(x)) {
+ case 0: @diagnostic(warning, derivative_uniformity) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+ default: {
+ }
+ }
+}
diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl
new file mode 100644
index 0000000..63f5db4
--- /dev/null
+++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(1) var t : texture_2d<f32>;
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ @diagnostic(warning, derivative_uniformity) {
+ if (x > 0) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+ }
+}
diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..cc4ebfb
--- /dev/null
+++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.dxc.hlsl
@@ -0,0 +1,30 @@
+diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ {
+ if ((x > 0.0f)) {
+ }
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..cc4ebfb
--- /dev/null
+++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.fxc.hlsl
@@ -0,0 +1,30 @@
+diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ {
+ if ((x > 0.0f)) {
+ }
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.glsl
new file mode 100644
index 0000000..38aa2a0
--- /dev/null
+++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.glsl
@@ -0,0 +1,27 @@
+diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+#version 310 es
+precision mediump float;
+
+layout(location = 0) in float x_1;
+void tint_symbol(float x) {
+ {
+ if ((x > 0.0f)) {
+ }
+ }
+}
+
+void main() {
+ tint_symbol(x_1);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.msl
new file mode 100644
index 0000000..00f0483
--- /dev/null
+++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.msl
@@ -0,0 +1,31 @@
+diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_2 {
+ float x [[user(locn0)]];
+};
+
+void tint_symbol_inner(float x) {
+ {
+ if ((x > 0.0f)) {
+ }
+ }
+}
+
+fragment void tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ tint_symbol_inner(tint_symbol_1.x);
+ return;
+}
+
diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.spvasm
new file mode 100644
index 0000000..acad3a0
--- /dev/null
+++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.spvasm
@@ -0,0 +1,63 @@
+diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %x_1
+ OpExecutionMode %main OriginUpperLeft
+ OpName %x_1 "x_1"
+ OpName %t "t"
+ OpName %s "s"
+ OpName %main_inner "main_inner"
+ OpName %x "x"
+ OpName %main "main"
+ OpDecorate %x_1 Location 0
+ OpDecorate %t DescriptorSet 0
+ OpDecorate %t Binding 1
+ OpDecorate %s DescriptorSet 0
+ OpDecorate %s Binding 2
+ %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+ %x_1 = OpVariable %_ptr_Input_float Input
+ %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
+ %t = OpVariable %_ptr_UniformConstant_6 UniformConstant
+ %9 = OpTypeSampler
+%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
+ %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void %float
+ %15 = OpConstantNull %float
+ %bool = OpTypeBool
+ %20 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %10
+ %x = OpFunctionParameter %float
+ %14 = OpLabel
+ %16 = OpFOrdGreaterThan %bool %x %15
+ OpSelectionMerge %18 None
+ OpBranchConditional %16 %19 %18
+ %19 = OpLabel
+ OpBranch %18
+ %18 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %20
+ %22 = OpLabel
+ %24 = OpLoad %float %x_1
+ %23 = OpFunctionCall %void %main_inner %24
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.wgsl
new file mode 100644
index 0000000..f1bf9d3
--- /dev/null
+++ b/test/tint/diagnostic_filtering/compound_statement_attribute.wgsl.expected.wgsl
@@ -0,0 +1,24 @@
+diagnostic_filtering/compound_statement_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:5 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/compound_statement_attribute.wgsl:7:9 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ @diagnostic(warning, derivative_uniformity) {
+ if ((x > 0)) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+ }
+}
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl
new file mode 100644
index 0000000..14942c6
--- /dev/null
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl
@@ -0,0 +1,11 @@
+@group(0) @binding(1) var t : texture_2d<f32>;
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ switch (i32(x)) {
+ default @diagnostic(warning, derivative_uniformity) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+ }
+}
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..6e6406f
--- /dev/null
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ do {
+ } while (false);
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..6e6406f
--- /dev/null
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ do {
+ } while (false);
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl
new file mode 100644
index 0000000..915923b
--- /dev/null
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+#version 310 es
+precision mediump float;
+
+layout(location = 0) in float x_1;
+void tint_symbol(float x) {
+ switch(int(x)) {
+ default: {
+ break;
+ }
+ }
+}
+
+void main() {
+ tint_symbol(x_1);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl
new file mode 100644
index 0000000..b49fa2a
--- /dev/null
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.msl
@@ -0,0 +1,32 @@
+diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_2 {
+ float x [[user(locn0)]];
+};
+
+void tint_symbol_inner(float x) {
+ switch(int(x)) {
+ default: {
+ break;
+ }
+ }
+}
+
+fragment void tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ tint_symbol_inner(tint_symbol_1.x);
+ return;
+}
+
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.spvasm
new file mode 100644
index 0000000..5364ca2
--- /dev/null
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.spvasm
@@ -0,0 +1,62 @@
+diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 24
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %x_1
+ OpExecutionMode %main OriginUpperLeft
+ OpName %x_1 "x_1"
+ OpName %t "t"
+ OpName %s "s"
+ OpName %main_inner "main_inner"
+ OpName %x "x"
+ OpName %main "main"
+ OpDecorate %x_1 Location 0
+ OpDecorate %t DescriptorSet 0
+ OpDecorate %t Binding 1
+ OpDecorate %s DescriptorSet 0
+ OpDecorate %s Binding 2
+ %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+ %x_1 = OpVariable %_ptr_Input_float Input
+ %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
+ %t = OpVariable %_ptr_UniformConstant_6 UniformConstant
+ %9 = OpTypeSampler
+%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
+ %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void %float
+ %int = OpTypeInt 32 1
+ %19 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %10
+ %x = OpFunctionParameter %float
+ %14 = OpLabel
+ %16 = OpConvertFToS %int %x
+ OpSelectionMerge %15 None
+ OpSwitch %16 %18
+ %18 = OpLabel
+ OpBranch %15
+ %15 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %19
+ %21 = OpLabel
+ %23 = OpLoad %float %x_1
+ %22 = OpFunctionCall %void %main_inner %23
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.wgsl
new file mode 100644
index 0000000..eceadbd
--- /dev/null
+++ b/test/tint/diagnostic_filtering/default_case_body_attribute.wgsl.expected.wgsl
@@ -0,0 +1,24 @@
+diagnostic_filtering/default_case_body_attribute.wgsl:8:11 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ switch (i32(x)) {
+ ^^^^^^
+
+diagnostic_filtering/default_case_body_attribute.wgsl:6:15 note: user-defined input 'x' of 'main' may be non-uniform
+ switch (i32(x)) {
+ ^
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ switch(i32(x)) {
+ default: @diagnostic(warning, derivative_uniformity) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+ }
+}
diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl
new file mode 100644
index 0000000..7f482ac
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(1) var t : texture_2d<f32>;
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ if (x > 0) {
+ } else @diagnostic(warning, derivative_uniformity) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..9b566ce
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.dxc.hlsl
@@ -0,0 +1,29 @@
+diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ if ((x > 0.0f)) {
+ } else {
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..9b566ce
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.fxc.hlsl
@@ -0,0 +1,29 @@
+diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ if ((x > 0.0f)) {
+ } else {
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.glsl
new file mode 100644
index 0000000..cd89cc0
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.glsl
@@ -0,0 +1,26 @@
+diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+#version 310 es
+precision mediump float;
+
+layout(location = 0) in float x_1;
+void tint_symbol(float x) {
+ if ((x > 0.0f)) {
+ } else {
+ }
+}
+
+void main() {
+ tint_symbol(x_1);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.msl
new file mode 100644
index 0000000..7374a36
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.msl
@@ -0,0 +1,30 @@
+diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_2 {
+ float x [[user(locn0)]];
+};
+
+void tint_symbol_inner(float x) {
+ if ((x > 0.0f)) {
+ } else {
+ }
+}
+
+fragment void tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ tint_symbol_inner(tint_symbol_1.x);
+ return;
+}
+
diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.spvasm
new file mode 100644
index 0000000..961e1ad
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.spvasm
@@ -0,0 +1,65 @@
+diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 26
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %x_1
+ OpExecutionMode %main OriginUpperLeft
+ OpName %x_1 "x_1"
+ OpName %t "t"
+ OpName %s "s"
+ OpName %main_inner "main_inner"
+ OpName %x "x"
+ OpName %main "main"
+ OpDecorate %x_1 Location 0
+ OpDecorate %t DescriptorSet 0
+ OpDecorate %t Binding 1
+ OpDecorate %s DescriptorSet 0
+ OpDecorate %s Binding 2
+ %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+ %x_1 = OpVariable %_ptr_Input_float Input
+ %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
+ %t = OpVariable %_ptr_UniformConstant_6 UniformConstant
+ %9 = OpTypeSampler
+%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
+ %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void %float
+ %15 = OpConstantNull %float
+ %bool = OpTypeBool
+ %21 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %10
+ %x = OpFunctionParameter %float
+ %14 = OpLabel
+ %16 = OpFOrdGreaterThan %bool %x %15
+ OpSelectionMerge %18 None
+ OpBranchConditional %16 %19 %20
+ %19 = OpLabel
+ OpBranch %18
+ %20 = OpLabel
+ OpBranch %18
+ %18 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %21
+ %23 = OpLabel
+ %25 = OpLoad %float %x_1
+ %24 = OpFunctionCall %void %main_inner %25
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.wgsl
new file mode 100644
index 0000000..47b37b6
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_body_attribute.wgsl.expected.wgsl
@@ -0,0 +1,23 @@
+diagnostic_filtering/else_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ if ((x > 0)) {
+ } else @diagnostic(warning, derivative_uniformity) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl
new file mode 100644
index 0000000..68fd217
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(1) var t : texture_2d<f32>;
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ if (x > 0) {
+ } else if (x < 0) @diagnostic(warning, derivative_uniformity) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2f00281
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.dxc.hlsl
@@ -0,0 +1,31 @@
+diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ if ((x > 0.0f)) {
+ } else {
+ if ((x < 0.0f)) {
+ }
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2f00281
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.fxc.hlsl
@@ -0,0 +1,31 @@
+diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ if ((x > 0.0f)) {
+ } else {
+ if ((x < 0.0f)) {
+ }
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.glsl
new file mode 100644
index 0000000..6e4bec0
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.glsl
@@ -0,0 +1,28 @@
+diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+#version 310 es
+precision mediump float;
+
+layout(location = 0) in float x_1;
+void tint_symbol(float x) {
+ if ((x > 0.0f)) {
+ } else {
+ if ((x < 0.0f)) {
+ }
+ }
+}
+
+void main() {
+ tint_symbol(x_1);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.msl
new file mode 100644
index 0000000..2c579f6
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.msl
@@ -0,0 +1,32 @@
+diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_2 {
+ float x [[user(locn0)]];
+};
+
+void tint_symbol_inner(float x) {
+ if ((x > 0.0f)) {
+ } else {
+ if ((x < 0.0f)) {
+ }
+ }
+}
+
+fragment void tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ tint_symbol_inner(tint_symbol_1.x);
+ return;
+}
+
diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.spvasm
new file mode 100644
index 0000000..5877822
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.spvasm
@@ -0,0 +1,71 @@
+diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 29
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %x_1
+ OpExecutionMode %main OriginUpperLeft
+ OpName %x_1 "x_1"
+ OpName %t "t"
+ OpName %s "s"
+ OpName %main_inner "main_inner"
+ OpName %x "x"
+ OpName %main "main"
+ OpDecorate %x_1 Location 0
+ OpDecorate %t DescriptorSet 0
+ OpDecorate %t Binding 1
+ OpDecorate %s DescriptorSet 0
+ OpDecorate %s Binding 2
+ %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+ %x_1 = OpVariable %_ptr_Input_float Input
+ %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
+ %t = OpVariable %_ptr_UniformConstant_6 UniformConstant
+ %9 = OpTypeSampler
+%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
+ %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void %float
+ %15 = OpConstantNull %float
+ %bool = OpTypeBool
+ %24 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %10
+ %x = OpFunctionParameter %float
+ %14 = OpLabel
+ %16 = OpFOrdGreaterThan %bool %x %15
+ OpSelectionMerge %18 None
+ OpBranchConditional %16 %19 %20
+ %19 = OpLabel
+ OpBranch %18
+ %20 = OpLabel
+ %21 = OpFOrdLessThan %bool %x %15
+ OpSelectionMerge %22 None
+ OpBranchConditional %21 %23 %22
+ %23 = OpLabel
+ OpBranch %22
+ %22 = OpLabel
+ OpBranch %18
+ %18 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %24
+ %26 = OpLabel
+ %28 = OpLoad %float %x_1
+ %27 = OpFunctionCall %void %main_inner %28
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.wgsl
new file mode 100644
index 0000000..bde4aa6
--- /dev/null
+++ b/test/tint/diagnostic_filtering/else_if_body_attribute.wgsl.expected.wgsl
@@ -0,0 +1,23 @@
+diagnostic_filtering/else_if_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/else_if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ if ((x > 0)) {
+ } else if ((x < 0)) @diagnostic(warning, derivative_uniformity) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl
new file mode 100644
index 0000000..14db324
--- /dev/null
+++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(1) var t : texture_2d<f32>;
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ var v = vec4<f32>(0);
+ for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) {
+ v = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..4498899
--- /dev/null
+++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.dxc.hlsl
@@ -0,0 +1,32 @@
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) {
+ ^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ float4 v = (0.0f).xxxx;
+ {
+ for(; (x > v.x); ) {
+ v = t.Sample(s, (0.0f).xx);
+ }
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..7754653
--- /dev/null
+++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.fxc.hlsl
@@ -0,0 +1,34 @@
+SKIP: FXC rejects non-uniform texture sample operation in output
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) {
+ ^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ float4 v = (0.0f).xxxx;
+ {
+ for(; (x > v.x); ) {
+ v = t.Sample(s, (0.0f).xx);
+ }
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.glsl
new file mode 100644
index 0000000..ad2f026
--- /dev/null
+++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.glsl
@@ -0,0 +1,31 @@
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) {
+ ^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+#version 310 es
+precision mediump float;
+
+layout(location = 0) in float x_1;
+uniform highp sampler2D t_s;
+
+void tint_symbol(float x) {
+ vec4 v = vec4(0.0f);
+ {
+ for(; (x > v.x); ) {
+ v = texture(t_s, vec2(0.0f));
+ }
+ }
+}
+
+void main() {
+ tint_symbol(x_1);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.msl
new file mode 100644
index 0000000..e7bb2ff
--- /dev/null
+++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.msl
@@ -0,0 +1,31 @@
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) {
+ ^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_2 {
+ float x [[user(locn0)]];
+};
+
+void tint_symbol_inner(float x, texture2d<float, access::sample> tint_symbol_3, sampler tint_symbol_4) {
+ float4 v = float4(0.0f);
+ for(; (x > v[0]); ) {
+ v = tint_symbol_3.sample(tint_symbol_4, float2(0.0f));
+ }
+}
+
+fragment void tint_symbol(texture2d<float, access::sample> tint_symbol_5 [[texture(0)]], sampler tint_symbol_6 [[sampler(0)]], tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ tint_symbol_inner(tint_symbol_1.x, tint_symbol_5, tint_symbol_6);
+ return;
+}
+
diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.spvasm
new file mode 100644
index 0000000..ac9e7c3
--- /dev/null
+++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.spvasm
@@ -0,0 +1,91 @@
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) {
+ ^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 45
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %x_1
+ OpExecutionMode %main OriginUpperLeft
+ OpName %x_1 "x_1"
+ OpName %t "t"
+ OpName %s "s"
+ OpName %main_inner "main_inner"
+ OpName %x "x"
+ OpName %v "v"
+ OpName %main "main"
+ OpDecorate %x_1 Location 0
+ OpDecorate %t DescriptorSet 0
+ OpDecorate %t Binding 1
+ OpDecorate %s DescriptorSet 0
+ OpDecorate %s Binding 2
+ %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+ %x_1 = OpVariable %_ptr_Input_float Input
+ %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
+ %t = OpVariable %_ptr_UniformConstant_6 UniformConstant
+ %9 = OpTypeSampler
+%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
+ %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void %float
+ %v4float = OpTypeVector %float 4
+ %16 = OpConstantNull %v4float
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Function_float = OpTypePointer Function %float
+ %bool = OpTypeBool
+ %36 = OpTypeSampledImage %6
+ %v2float = OpTypeVector %float 2
+ %39 = OpConstantNull %v2float
+ %40 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %10
+ %x = OpFunctionParameter %float
+ %14 = OpLabel
+ %v = OpVariable %_ptr_Function_v4float Function %16
+ OpStore %v %16
+ OpBranch %19
+ %19 = OpLabel
+ OpLoopMerge %20 %21 None
+ OpBranch %22
+ %22 = OpLabel
+ %27 = OpAccessChain %_ptr_Function_float %v %uint_0
+ %28 = OpLoad %float %27
+ %29 = OpFOrdGreaterThan %bool %x %28
+ %23 = OpLogicalNot %bool %29
+ OpSelectionMerge %31 None
+ OpBranchConditional %23 %32 %31
+ %32 = OpLabel
+ OpBranch %20
+ %31 = OpLabel
+ %34 = OpLoad %9 %s
+ %35 = OpLoad %6 %t
+ %37 = OpSampledImage %36 %35 %34
+ %33 = OpImageSampleImplicitLod %v4float %37 %39
+ OpStore %v %33
+ OpBranch %21
+ %21 = OpLabel
+ OpBranch %19
+ %20 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %40
+ %42 = OpLabel
+ %44 = OpLoad %float %x_1
+ %43 = OpFunctionCall %void %main_inner %44
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.wgsl
new file mode 100644
index 0000000..4b78886
--- /dev/null
+++ b/test/tint/diagnostic_filtering/for_loop_body_attribute.wgsl.expected.wgsl
@@ -0,0 +1,23 @@
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ for (; x > v.x; ) @diagnostic(warning, derivative_uniformity) {
+ ^^^
+
+diagnostic_filtering/for_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ var v = vec4<f32>(0);
+ for(; (x > v.x); ) @diagnostic(warning, derivative_uniformity) {
+ v = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl
new file mode 100644
index 0000000..2eb2517
--- /dev/null
+++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl
@@ -0,0 +1,9 @@
+@group(0) @binding(1) var t : texture_2d<f32>;
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) @diagnostic(warning, derivative_uniformity) {
+ if (x > 0) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..2bc81b8
--- /dev/null
+++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ if ((x > 0.0f)) {
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..2bc81b8
--- /dev/null
+++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ if ((x > 0.0f)) {
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.glsl
new file mode 100644
index 0000000..8c6f30f
--- /dev/null
+++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+#version 310 es
+precision mediump float;
+
+layout(location = 0) in float x_1;
+void tint_symbol(float x) {
+ if ((x > 0.0f)) {
+ }
+}
+
+void main() {
+ tint_symbol(x_1);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.msl
new file mode 100644
index 0000000..582d57b
--- /dev/null
+++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.msl
@@ -0,0 +1,29 @@
+diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_2 {
+ float x [[user(locn0)]];
+};
+
+void tint_symbol_inner(float x) {
+ if ((x > 0.0f)) {
+ }
+}
+
+fragment void tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ tint_symbol_inner(tint_symbol_1.x);
+ return;
+}
+
diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.spvasm
new file mode 100644
index 0000000..247e66c
--- /dev/null
+++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.spvasm
@@ -0,0 +1,63 @@
+diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %x_1
+ OpExecutionMode %main OriginUpperLeft
+ OpName %x_1 "x_1"
+ OpName %t "t"
+ OpName %s "s"
+ OpName %main_inner "main_inner"
+ OpName %x "x"
+ OpName %main "main"
+ OpDecorate %x_1 Location 0
+ OpDecorate %t DescriptorSet 0
+ OpDecorate %t Binding 1
+ OpDecorate %s DescriptorSet 0
+ OpDecorate %s Binding 2
+ %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+ %x_1 = OpVariable %_ptr_Input_float Input
+ %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
+ %t = OpVariable %_ptr_UniformConstant_6 UniformConstant
+ %9 = OpTypeSampler
+%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
+ %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void %float
+ %15 = OpConstantNull %float
+ %bool = OpTypeBool
+ %20 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %10
+ %x = OpFunctionParameter %float
+ %14 = OpLabel
+ %16 = OpFOrdGreaterThan %bool %x %15
+ OpSelectionMerge %18 None
+ OpBranchConditional %16 %19 %18
+ %19 = OpLabel
+ OpBranch %18
+ %18 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %20
+ %22 = OpLabel
+ %24 = OpLoad %float %x_1
+ %23 = OpFunctionCall %void %main_inner %24
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.wgsl
new file mode 100644
index 0000000..0887fe6
--- /dev/null
+++ b/test/tint/diagnostic_filtering/function_body_attribute.wgsl.expected.wgsl
@@ -0,0 +1,22 @@
+diagnostic_filtering/function_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) {
+ ^^
+
+diagnostic_filtering/function_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) {
+ ^
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) @diagnostic(warning, derivative_uniformity) {
+ if ((x > 0)) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl
new file mode 100644
index 0000000..7f4ef9d
--- /dev/null
+++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl
@@ -0,0 +1,9 @@
+@group(0) @binding(1) var t : texture_2d<f32>;
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..36bf7b9
--- /dev/null
+++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.dxc.hlsl
@@ -0,0 +1,28 @@
+diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ if ((x > 0.0f)) {
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..36bf7b9
--- /dev/null
+++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.fxc.hlsl
@@ -0,0 +1,28 @@
+diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ if ((x > 0.0f)) {
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.glsl
new file mode 100644
index 0000000..b7d37e1
--- /dev/null
+++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.glsl
@@ -0,0 +1,25 @@
+diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^
+
+#version 310 es
+precision mediump float;
+
+layout(location = 0) in float x_1;
+void tint_symbol(float x) {
+ if ((x > 0.0f)) {
+ }
+}
+
+void main() {
+ tint_symbol(x_1);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.msl
new file mode 100644
index 0000000..ad671d2
--- /dev/null
+++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.msl
@@ -0,0 +1,29 @@
+diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^
+
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_2 {
+ float x [[user(locn0)]];
+};
+
+void tint_symbol_inner(float x) {
+ if ((x > 0.0f)) {
+ }
+}
+
+fragment void tint_symbol(tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ tint_symbol_inner(tint_symbol_1.x);
+ return;
+}
+
diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.spvasm
new file mode 100644
index 0000000..61847a2
--- /dev/null
+++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.spvasm
@@ -0,0 +1,63 @@
+diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 25
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %x_1
+ OpExecutionMode %main OriginUpperLeft
+ OpName %x_1 "x_1"
+ OpName %t "t"
+ OpName %s "s"
+ OpName %main_inner "main_inner"
+ OpName %x "x"
+ OpName %main "main"
+ OpDecorate %x_1 Location 0
+ OpDecorate %t DescriptorSet 0
+ OpDecorate %t Binding 1
+ OpDecorate %s DescriptorSet 0
+ OpDecorate %s Binding 2
+ %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+ %x_1 = OpVariable %_ptr_Input_float Input
+ %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
+ %t = OpVariable %_ptr_UniformConstant_6 UniformConstant
+ %9 = OpTypeSampler
+%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
+ %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void %float
+ %15 = OpConstantNull %float
+ %bool = OpTypeBool
+ %20 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %10
+ %x = OpFunctionParameter %float
+ %14 = OpLabel
+ %16 = OpFOrdGreaterThan %bool %x %15
+ OpSelectionMerge %18 None
+ OpBranchConditional %16 %19 %18
+ %19 = OpLabel
+ OpBranch %18
+ %18 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %20
+ %22 = OpLabel
+ %24 = OpLoad %float %x_1
+ %23 = OpFunctionCall %void %main_inner %24
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.wgsl
new file mode 100644
index 0000000..4cd063c
--- /dev/null
+++ b/test/tint/diagnostic_filtering/if_body_attribute.wgsl.expected.wgsl
@@ -0,0 +1,22 @@
+diagnostic_filtering/if_body_attribute.wgsl:7:9 warning: 'textureSample' must only be called from uniform control flow
+ _ = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:3 note: control flow depends on possibly non-uniform value
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^^
+
+diagnostic_filtering/if_body_attribute.wgsl:6:7 note: user-defined input 'x' of 'main' may be non-uniform
+ if (x > 0) @diagnostic(warning, derivative_uniformity) {
+ ^
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ if ((x > 0)) @diagnostic(warning, derivative_uniformity) {
+ _ = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl
new file mode 100644
index 0000000..1928333
--- /dev/null
+++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl
@@ -0,0 +1,10 @@
+@group(0) @binding(1) var t : texture_2d<f32>;
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ var v = vec4<f32>(0);
+ while (x > v.x) @diagnostic(warning, derivative_uniformity) {
+ v = textureSample(t, s, vec2(0, 0));
+ }
+}
diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.dxc.hlsl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.dxc.hlsl
new file mode 100644
index 0000000..8a6d04b
--- /dev/null
+++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.dxc.hlsl
@@ -0,0 +1,30 @@
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ while (x > v.x) @diagnostic(warning, derivative_uniformity) {
+ ^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ float4 v = (0.0f).xxxx;
+ while((x > v.x)) {
+ v = t.Sample(s, (0.0f).xx);
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.fxc.hlsl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.fxc.hlsl
new file mode 100644
index 0000000..0f012af
--- /dev/null
+++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.fxc.hlsl
@@ -0,0 +1,32 @@
+SKIP: FXC rejects non-uniform texture sample operation in output
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ while (x > v.x) @diagnostic(warning, derivative_uniformity) {
+ ^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+Texture2D<float4> t : register(t1, space0);
+SamplerState s : register(s2, space0);
+
+struct tint_symbol_1 {
+ float x : TEXCOORD0;
+};
+
+void main_inner(float x) {
+ float4 v = (0.0f).xxxx;
+ while((x > v.x)) {
+ v = t.Sample(s, (0.0f).xx);
+ }
+}
+
+void main(tint_symbol_1 tint_symbol) {
+ main_inner(tint_symbol.x);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.glsl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.glsl
new file mode 100644
index 0000000..9b9957d
--- /dev/null
+++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.glsl
@@ -0,0 +1,29 @@
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ while (x > v.x) @diagnostic(warning, derivative_uniformity) {
+ ^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+#version 310 es
+precision mediump float;
+
+layout(location = 0) in float x_1;
+uniform highp sampler2D t_s;
+
+void tint_symbol(float x) {
+ vec4 v = vec4(0.0f);
+ while((x > v.x)) {
+ v = texture(t_s, vec2(0.0f));
+ }
+}
+
+void main() {
+ tint_symbol(x_1);
+ return;
+}
diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.msl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.msl
new file mode 100644
index 0000000..73a56be
--- /dev/null
+++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.msl
@@ -0,0 +1,31 @@
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ while (x > v.x) @diagnostic(warning, derivative_uniformity) {
+ ^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+#include <metal_stdlib>
+
+using namespace metal;
+struct tint_symbol_2 {
+ float x [[user(locn0)]];
+};
+
+void tint_symbol_inner(float x, texture2d<float, access::sample> tint_symbol_3, sampler tint_symbol_4) {
+ float4 v = float4(0.0f);
+ while((x > v[0])) {
+ v = tint_symbol_3.sample(tint_symbol_4, float2(0.0f));
+ }
+}
+
+fragment void tint_symbol(texture2d<float, access::sample> tint_symbol_5 [[texture(0)]], sampler tint_symbol_6 [[sampler(0)]], tint_symbol_2 tint_symbol_1 [[stage_in]]) {
+ tint_symbol_inner(tint_symbol_1.x, tint_symbol_5, tint_symbol_6);
+ return;
+}
+
diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.spvasm b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.spvasm
new file mode 100644
index 0000000..f172769
--- /dev/null
+++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.spvasm
@@ -0,0 +1,91 @@
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ while (x > v.x) @diagnostic(warning, derivative_uniformity) {
+ ^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 45
+; Schema: 0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %x_1
+ OpExecutionMode %main OriginUpperLeft
+ OpName %x_1 "x_1"
+ OpName %t "t"
+ OpName %s "s"
+ OpName %main_inner "main_inner"
+ OpName %x "x"
+ OpName %v "v"
+ OpName %main "main"
+ OpDecorate %x_1 Location 0
+ OpDecorate %t DescriptorSet 0
+ OpDecorate %t Binding 1
+ OpDecorate %s DescriptorSet 0
+ OpDecorate %s Binding 2
+ %float = OpTypeFloat 32
+%_ptr_Input_float = OpTypePointer Input %float
+ %x_1 = OpVariable %_ptr_Input_float Input
+ %6 = OpTypeImage %float 2D 0 0 0 1 Unknown
+%_ptr_UniformConstant_6 = OpTypePointer UniformConstant %6
+ %t = OpVariable %_ptr_UniformConstant_6 UniformConstant
+ %9 = OpTypeSampler
+%_ptr_UniformConstant_9 = OpTypePointer UniformConstant %9
+ %s = OpVariable %_ptr_UniformConstant_9 UniformConstant
+ %void = OpTypeVoid
+ %10 = OpTypeFunction %void %float
+ %v4float = OpTypeVector %float 4
+ %16 = OpConstantNull %v4float
+%_ptr_Function_v4float = OpTypePointer Function %v4float
+ %uint = OpTypeInt 32 0
+ %uint_0 = OpConstant %uint 0
+%_ptr_Function_float = OpTypePointer Function %float
+ %bool = OpTypeBool
+ %36 = OpTypeSampledImage %6
+ %v2float = OpTypeVector %float 2
+ %39 = OpConstantNull %v2float
+ %40 = OpTypeFunction %void
+ %main_inner = OpFunction %void None %10
+ %x = OpFunctionParameter %float
+ %14 = OpLabel
+ %v = OpVariable %_ptr_Function_v4float Function %16
+ OpStore %v %16
+ OpBranch %19
+ %19 = OpLabel
+ OpLoopMerge %20 %21 None
+ OpBranch %22
+ %22 = OpLabel
+ %27 = OpAccessChain %_ptr_Function_float %v %uint_0
+ %28 = OpLoad %float %27
+ %29 = OpFOrdGreaterThan %bool %x %28
+ %23 = OpLogicalNot %bool %29
+ OpSelectionMerge %31 None
+ OpBranchConditional %23 %32 %31
+ %32 = OpLabel
+ OpBranch %20
+ %31 = OpLabel
+ %34 = OpLoad %9 %s
+ %35 = OpLoad %6 %t
+ %37 = OpSampledImage %36 %35 %34
+ %33 = OpImageSampleImplicitLod %v4float %37 %39
+ OpStore %v %33
+ OpBranch %21
+ %21 = OpLabel
+ OpBranch %19
+ %20 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ %main = OpFunction %void None %40
+ %42 = OpLabel
+ %44 = OpLoad %float %x_1
+ %43 = OpFunctionCall %void %main_inner %44
+ OpReturn
+ OpFunctionEnd
diff --git a/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.wgsl b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.wgsl
new file mode 100644
index 0000000..b2238a1
--- /dev/null
+++ b/test/tint/diagnostic_filtering/while_loop_body_attribute.wgsl.expected.wgsl
@@ -0,0 +1,23 @@
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 warning: 'textureSample' must only be called from uniform control flow
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:7:3 note: control flow depends on possibly non-uniform value
+ while (x > v.x) @diagnostic(warning, derivative_uniformity) {
+ ^^^^^
+
+diagnostic_filtering/while_loop_body_attribute.wgsl:8:9 note: return value of 'textureSample' may be non-uniform
+ v = textureSample(t, s, vec2(0, 0));
+ ^^^^^^^^^^^^^
+
+@group(0) @binding(1) var t : texture_2d<f32>;
+
+@group(0) @binding(2) var s : sampler;
+
+@fragment
+fn main(@location(0) x : f32) {
+ var v = vec4<f32>(0);
+ while((x > v.x)) @diagnostic(warning, derivative_uniformity) {
+ v = textureSample(t, s, vec2(0, 0));
+ }
+}