Add `SuggestAlternatives` to attributes.
This CL adds an `attribute` enum into intrinsics.def and updates the WGSL parser to use the enum parser and SuggestAlternatives. Bug: tint:1831 Change-Id: I33b3e6bbf092282d9b1f86a1080e69940f55ff68 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/121280 Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Dan Sinclair <dsinclair@chromium.org> Kokoro: Kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
9386f73446
commit
077d97a387
|
@ -701,6 +701,8 @@ libtint_source_set("libtint_builtins_src") {
|
||||||
"builtin/access.h",
|
"builtin/access.h",
|
||||||
"builtin/address_space.cc",
|
"builtin/address_space.cc",
|
||||||
"builtin/address_space.h",
|
"builtin/address_space.h",
|
||||||
|
"builtin/attribute.cc",
|
||||||
|
"builtin/attribute.h",
|
||||||
"builtin/builtin.cc",
|
"builtin/builtin.cc",
|
||||||
"builtin/builtin.h",
|
"builtin/builtin.h",
|
||||||
"builtin/builtin_value.cc",
|
"builtin/builtin_value.cc",
|
||||||
|
@ -1311,6 +1313,7 @@ if (tint_build_unittests) {
|
||||||
sources = [
|
sources = [
|
||||||
"builtin/access_test.cc",
|
"builtin/access_test.cc",
|
||||||
"builtin/address_space_test.cc",
|
"builtin/address_space_test.cc",
|
||||||
|
"builtin/attribute_test.cc",
|
||||||
"builtin/builtin_test.cc",
|
"builtin/builtin_test.cc",
|
||||||
"builtin/builtin_value_test.cc",
|
"builtin/builtin_value_test.cc",
|
||||||
"builtin/diagnostic_rule_test.cc",
|
"builtin/diagnostic_rule_test.cc",
|
||||||
|
|
|
@ -555,6 +555,7 @@ list(APPEND TINT_LIB_SRCS
|
||||||
|
|
||||||
tint_generated(builtin/access BENCH TEST)
|
tint_generated(builtin/access BENCH TEST)
|
||||||
tint_generated(builtin/address_space BENCH TEST)
|
tint_generated(builtin/address_space BENCH TEST)
|
||||||
|
tint_generated(builtin/attribute BENCH TEST)
|
||||||
tint_generated(builtin/builtin BENCH TEST)
|
tint_generated(builtin/builtin BENCH TEST)
|
||||||
tint_generated(builtin/builtin_value BENCH TEST)
|
tint_generated(builtin/builtin_value BENCH TEST)
|
||||||
tint_generated(builtin/diagnostic_rule BENCH TEST)
|
tint_generated(builtin/diagnostic_rule BENCH TEST)
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
// Copyright 2023 The Tint Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// File generated by tools/src/cmd/gen
|
||||||
|
// using the template:
|
||||||
|
// src/tint/builtin/attribute.cc.tmpl
|
||||||
|
//
|
||||||
|
// Do not modify this file directly
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "src/tint/builtin/attribute.h"
|
||||||
|
|
||||||
|
namespace tint::builtin {
|
||||||
|
|
||||||
|
/// ParseAttribute parses a Attribute from a string.
|
||||||
|
/// @param str the string to parse
|
||||||
|
/// @returns the parsed enum, or Attribute::kUndefined if the string could not be parsed.
|
||||||
|
Attribute ParseAttribute(std::string_view str) {
|
||||||
|
if (str == "align") {
|
||||||
|
return Attribute::kAlign;
|
||||||
|
}
|
||||||
|
if (str == "binding") {
|
||||||
|
return Attribute::kBinding;
|
||||||
|
}
|
||||||
|
if (str == "builtin") {
|
||||||
|
return Attribute::kBuiltin;
|
||||||
|
}
|
||||||
|
if (str == "compute") {
|
||||||
|
return Attribute::kCompute;
|
||||||
|
}
|
||||||
|
if (str == "diagnostic") {
|
||||||
|
return Attribute::kDiagnostic;
|
||||||
|
}
|
||||||
|
if (str == "fragment") {
|
||||||
|
return Attribute::kFragment;
|
||||||
|
}
|
||||||
|
if (str == "group") {
|
||||||
|
return Attribute::kGroup;
|
||||||
|
}
|
||||||
|
if (str == "id") {
|
||||||
|
return Attribute::kId;
|
||||||
|
}
|
||||||
|
if (str == "interpolate") {
|
||||||
|
return Attribute::kInterpolate;
|
||||||
|
}
|
||||||
|
if (str == "invariant") {
|
||||||
|
return Attribute::kInvariant;
|
||||||
|
}
|
||||||
|
if (str == "location") {
|
||||||
|
return Attribute::kLocation;
|
||||||
|
}
|
||||||
|
if (str == "must_use") {
|
||||||
|
return Attribute::kMustUse;
|
||||||
|
}
|
||||||
|
if (str == "size") {
|
||||||
|
return Attribute::kSize;
|
||||||
|
}
|
||||||
|
if (str == "vertex") {
|
||||||
|
return Attribute::kVertex;
|
||||||
|
}
|
||||||
|
if (str == "workgroup_size") {
|
||||||
|
return Attribute::kWorkgroupSize;
|
||||||
|
}
|
||||||
|
return Attribute::kUndefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Attribute value) {
|
||||||
|
switch (value) {
|
||||||
|
case Attribute::kUndefined:
|
||||||
|
return out << "undefined";
|
||||||
|
case Attribute::kAlign:
|
||||||
|
return out << "align";
|
||||||
|
case Attribute::kBinding:
|
||||||
|
return out << "binding";
|
||||||
|
case Attribute::kBuiltin:
|
||||||
|
return out << "builtin";
|
||||||
|
case Attribute::kCompute:
|
||||||
|
return out << "compute";
|
||||||
|
case Attribute::kDiagnostic:
|
||||||
|
return out << "diagnostic";
|
||||||
|
case Attribute::kFragment:
|
||||||
|
return out << "fragment";
|
||||||
|
case Attribute::kGroup:
|
||||||
|
return out << "group";
|
||||||
|
case Attribute::kId:
|
||||||
|
return out << "id";
|
||||||
|
case Attribute::kInterpolate:
|
||||||
|
return out << "interpolate";
|
||||||
|
case Attribute::kInvariant:
|
||||||
|
return out << "invariant";
|
||||||
|
case Attribute::kLocation:
|
||||||
|
return out << "location";
|
||||||
|
case Attribute::kMustUse:
|
||||||
|
return out << "must_use";
|
||||||
|
case Attribute::kSize:
|
||||||
|
return out << "size";
|
||||||
|
case Attribute::kVertex:
|
||||||
|
return out << "vertex";
|
||||||
|
case Attribute::kWorkgroupSize:
|
||||||
|
return out << "workgroup_size";
|
||||||
|
}
|
||||||
|
return out << "<unknown>";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tint::builtin
|
|
@ -0,0 +1,25 @@
|
||||||
|
{{- /*
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Template file for use with tools/src/cmd/gen to generate attribute.cc
|
||||||
|
|
||||||
|
To update the generated file, run:
|
||||||
|
./tools/run gen
|
||||||
|
|
||||||
|
See:
|
||||||
|
* tools/src/cmd/gen for structures used by this template
|
||||||
|
* https://golang.org/pkg/text/template/ for documentation on the template syntax
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
*/ -}}
|
||||||
|
|
||||||
|
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||||
|
{{- $enum := (Sem.Enum "attribute") -}}
|
||||||
|
|
||||||
|
#include "src/tint/builtin/attribute.h"
|
||||||
|
|
||||||
|
namespace tint::builtin {
|
||||||
|
|
||||||
|
{{ Eval "ParseEnum" $enum}}
|
||||||
|
|
||||||
|
{{ Eval "EnumOStream" $enum}}
|
||||||
|
|
||||||
|
} // namespace tint::builtin
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright 2023 The Tint Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// File generated by tools/src/cmd/gen
|
||||||
|
// using the template:
|
||||||
|
// src/tint/builtin/attribute.h.tmpl
|
||||||
|
//
|
||||||
|
// Do not modify this file directly
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef SRC_TINT_BUILTIN_ATTRIBUTE_H_
|
||||||
|
#define SRC_TINT_BUILTIN_ATTRIBUTE_H_
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
/// \cond DO_NOT_DOCUMENT
|
||||||
|
/// There is a bug in doxygen where this enum conflicts with the ast::Attribute
|
||||||
|
/// and generates invalid documentation errors.
|
||||||
|
namespace tint::builtin {
|
||||||
|
|
||||||
|
/// Address space of a given pointer.
|
||||||
|
enum class Attribute {
|
||||||
|
kUndefined,
|
||||||
|
kAlign,
|
||||||
|
kBinding,
|
||||||
|
kBuiltin,
|
||||||
|
kCompute,
|
||||||
|
kDiagnostic,
|
||||||
|
kFragment,
|
||||||
|
kGroup,
|
||||||
|
kId,
|
||||||
|
kInterpolate,
|
||||||
|
kInvariant,
|
||||||
|
kLocation,
|
||||||
|
kMustUse,
|
||||||
|
kSize,
|
||||||
|
kVertex,
|
||||||
|
kWorkgroupSize,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @param out the std::ostream to write to
|
||||||
|
/// @param value the Attribute
|
||||||
|
/// @returns `out` so calls can be chained
|
||||||
|
std::ostream& operator<<(std::ostream& out, Attribute value);
|
||||||
|
|
||||||
|
/// ParseAttribute parses a Attribute from a string.
|
||||||
|
/// @param str the string to parse
|
||||||
|
/// @returns the parsed enum, or Attribute::kUndefined if the string could not be parsed.
|
||||||
|
Attribute ParseAttribute(std::string_view str);
|
||||||
|
|
||||||
|
constexpr const char* kAttributeStrings[] = {
|
||||||
|
"align", "binding", "builtin", "compute", "diagnostic",
|
||||||
|
"fragment", "group", "id", "interpolate", "invariant",
|
||||||
|
"location", "must_use", "size", "vertex", "workgroup_size",
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace tint::builtin
|
||||||
|
/// \endcond
|
||||||
|
|
||||||
|
#endif // SRC_TINT_BUILTIN_ATTRIBUTE_H_
|
|
@ -0,0 +1,33 @@
|
||||||
|
{{- /*
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Template file for use with tools/src/cmd/gen to generate attribute.h
|
||||||
|
|
||||||
|
To update the generated file, run:
|
||||||
|
./tools/run gen
|
||||||
|
|
||||||
|
See:
|
||||||
|
* tools/src/cmd/gen for structures used by this template
|
||||||
|
* https://golang.org/pkg/text/template/ for documentation on the template syntax
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
*/ -}}
|
||||||
|
|
||||||
|
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||||
|
{{- $enum := (Sem.Enum "attribute") -}}
|
||||||
|
|
||||||
|
#ifndef SRC_TINT_BUILTIN_ATTRIBUTE_H_
|
||||||
|
#define SRC_TINT_BUILTIN_ATTRIBUTE_H_
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
/// \cond DO_NOT_DOCUMENT
|
||||||
|
/// There is a bug in doxygen where this enum conflicts with the ast::Attribute
|
||||||
|
/// and generates invalid documentation errors.
|
||||||
|
namespace tint::builtin {
|
||||||
|
|
||||||
|
/// Address space of a given pointer.
|
||||||
|
{{ Eval "DeclareEnum" $enum}}
|
||||||
|
|
||||||
|
} // namespace tint::builtin
|
||||||
|
/// \endcond
|
||||||
|
|
||||||
|
#endif // SRC_TINT_BUILTIN_ATTRIBUTE_H_
|
|
@ -0,0 +1,151 @@
|
||||||
|
// Copyright 2023 The Tint Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// File generated by tools/src/cmd/gen
|
||||||
|
// using the template:
|
||||||
|
// src/tint/builtin/attribute_bench.cc.tmpl
|
||||||
|
//
|
||||||
|
// Do not modify this file directly
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "src/tint/builtin/attribute.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "benchmark/benchmark.h"
|
||||||
|
|
||||||
|
namespace tint::builtin {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void AttributeParser(::benchmark::State& state) {
|
||||||
|
const char* kStrings[] = {
|
||||||
|
"alccn",
|
||||||
|
"3g",
|
||||||
|
"aVign",
|
||||||
|
"align",
|
||||||
|
"alig1",
|
||||||
|
"qqlJn",
|
||||||
|
"alill7n",
|
||||||
|
"ppqqndnHH",
|
||||||
|
"bicv",
|
||||||
|
"bndiGg",
|
||||||
|
"binding",
|
||||||
|
"bindiivg",
|
||||||
|
"8WWnding",
|
||||||
|
"bxxding",
|
||||||
|
"bXltigg",
|
||||||
|
"ultXn",
|
||||||
|
"buil3in",
|
||||||
|
"builtin",
|
||||||
|
"Euiltin",
|
||||||
|
"bPTTltin",
|
||||||
|
"builtdxx",
|
||||||
|
"c44mpute",
|
||||||
|
"coSSpuVVe",
|
||||||
|
"RomR22e",
|
||||||
|
"compute",
|
||||||
|
"cFpu9e",
|
||||||
|
"comute",
|
||||||
|
"VOORRHte",
|
||||||
|
"dyagnstic",
|
||||||
|
"d77agnnnsllrrc",
|
||||||
|
"dia400ostic",
|
||||||
|
"diagnostic",
|
||||||
|
"danstooc",
|
||||||
|
"dignszzic",
|
||||||
|
"d11ansppiic",
|
||||||
|
"XXragment",
|
||||||
|
"fIIa9955nnnt",
|
||||||
|
"aarHHgmenYSS",
|
||||||
|
"fragment",
|
||||||
|
"fkkaet",
|
||||||
|
"gjamRRn",
|
||||||
|
"fabmnt",
|
||||||
|
"gjoup",
|
||||||
|
"goup",
|
||||||
|
"goq",
|
||||||
|
"group",
|
||||||
|
"Nroup",
|
||||||
|
"govv",
|
||||||
|
"gruQQ",
|
||||||
|
"r",
|
||||||
|
"jd",
|
||||||
|
"NNw",
|
||||||
|
"id",
|
||||||
|
"i",
|
||||||
|
"rrd",
|
||||||
|
"iG",
|
||||||
|
"FFnterpolate",
|
||||||
|
"iEtrplat",
|
||||||
|
"inerporrate",
|
||||||
|
"interpolate",
|
||||||
|
"inteplate",
|
||||||
|
"XterJJoDate",
|
||||||
|
"inepol8t",
|
||||||
|
"nvark1n",
|
||||||
|
"invriant",
|
||||||
|
"Jnvarant",
|
||||||
|
"invariant",
|
||||||
|
"invaricnt",
|
||||||
|
"invariaOt",
|
||||||
|
"invttKK_ianvv",
|
||||||
|
"lxxcati8",
|
||||||
|
"Focqq__o",
|
||||||
|
"locaiqqn",
|
||||||
|
"location",
|
||||||
|
"loc33tio6",
|
||||||
|
"ltto6at9QQn",
|
||||||
|
"loc66tio",
|
||||||
|
"mOxt_u6zz",
|
||||||
|
"musyy_use",
|
||||||
|
"mHH_use",
|
||||||
|
"must_use",
|
||||||
|
"qWW4st_se",
|
||||||
|
"musOO_se",
|
||||||
|
"ust_uYe",
|
||||||
|
"i",
|
||||||
|
"Fie",
|
||||||
|
"siw",
|
||||||
|
"size",
|
||||||
|
"zff",
|
||||||
|
"sizqK",
|
||||||
|
"s3zmm",
|
||||||
|
"ertex",
|
||||||
|
"vereq",
|
||||||
|
"vbtbbx",
|
||||||
|
"vertex",
|
||||||
|
"irtex",
|
||||||
|
"vOOteq",
|
||||||
|
"vertTvvx",
|
||||||
|
"woFFkgroup_size",
|
||||||
|
"wfr00grPupsiQe",
|
||||||
|
"workgrouP_size",
|
||||||
|
"workgroup_size",
|
||||||
|
"workgroup77sise",
|
||||||
|
"RRobbkgroupCsize",
|
||||||
|
"wXXrkgroup_size",
|
||||||
|
};
|
||||||
|
for (auto _ : state) {
|
||||||
|
for (auto* str : kStrings) {
|
||||||
|
auto result = ParseAttribute(str);
|
||||||
|
benchmark::DoNotOptimize(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK(AttributeParser);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace tint::builtin
|
|
@ -0,0 +1,29 @@
|
||||||
|
{{- /*
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Template file for use with tools/src/cmd/gen to generate attribute_bench.cc
|
||||||
|
|
||||||
|
To update the generated file, run:
|
||||||
|
./tools/run gen
|
||||||
|
|
||||||
|
See:
|
||||||
|
* tools/src/cmd/gen for structures used by this template
|
||||||
|
* https://golang.org/pkg/text/template/ for documentation on the template syntax
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
*/ -}}
|
||||||
|
|
||||||
|
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||||
|
{{- $enum := (Sem.Enum "attribute") -}}
|
||||||
|
|
||||||
|
#include "src/tint/builtin/attribute.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "benchmark/benchmark.h"
|
||||||
|
|
||||||
|
namespace tint::builtin {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
{{ Eval "BenchmarkParseEnum" $enum }}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace tint::builtin
|
|
@ -0,0 +1,135 @@
|
||||||
|
// Copyright 2023 The Tint Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// File generated by tools/src/cmd/gen
|
||||||
|
// using the template:
|
||||||
|
// src/tint/builtin/attribute_test.cc.tmpl
|
||||||
|
//
|
||||||
|
// Do not modify this file directly
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "src/tint/builtin/attribute.h"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "src/tint/utils/string.h"
|
||||||
|
|
||||||
|
namespace tint::builtin {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
namespace parse_print_tests {
|
||||||
|
|
||||||
|
struct Case {
|
||||||
|
const char* string;
|
||||||
|
Attribute value;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& out, Case c) {
|
||||||
|
return out << "'" << std::string(c.string) << "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr Case kValidCases[] = {
|
||||||
|
{"align", Attribute::kAlign},
|
||||||
|
{"binding", Attribute::kBinding},
|
||||||
|
{"builtin", Attribute::kBuiltin},
|
||||||
|
{"compute", Attribute::kCompute},
|
||||||
|
{"diagnostic", Attribute::kDiagnostic},
|
||||||
|
{"fragment", Attribute::kFragment},
|
||||||
|
{"group", Attribute::kGroup},
|
||||||
|
{"id", Attribute::kId},
|
||||||
|
{"interpolate", Attribute::kInterpolate},
|
||||||
|
{"invariant", Attribute::kInvariant},
|
||||||
|
{"location", Attribute::kLocation},
|
||||||
|
{"must_use", Attribute::kMustUse},
|
||||||
|
{"size", Attribute::kSize},
|
||||||
|
{"vertex", Attribute::kVertex},
|
||||||
|
{"workgroup_size", Attribute::kWorkgroupSize},
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr Case kInvalidCases[] = {
|
||||||
|
{"alccn", Attribute::kUndefined},
|
||||||
|
{"3g", Attribute::kUndefined},
|
||||||
|
{"aVign", Attribute::kUndefined},
|
||||||
|
{"bind1ng", Attribute::kUndefined},
|
||||||
|
{"bqnJing", Attribute::kUndefined},
|
||||||
|
{"bindin7ll", Attribute::kUndefined},
|
||||||
|
{"ppqqiliHH", Attribute::kUndefined},
|
||||||
|
{"bucv", Attribute::kUndefined},
|
||||||
|
{"biltGn", Attribute::kUndefined},
|
||||||
|
{"compiive", Attribute::kUndefined},
|
||||||
|
{"8WWmpute", Attribute::kUndefined},
|
||||||
|
{"cxxpute", Attribute::kUndefined},
|
||||||
|
{"dXagnosigg", Attribute::kUndefined},
|
||||||
|
{"dagnXuVc", Attribute::kUndefined},
|
||||||
|
{"diagnosti3", Attribute::kUndefined},
|
||||||
|
{"fraEment", Attribute::kUndefined},
|
||||||
|
{"PPagTTent", Attribute::kUndefined},
|
||||||
|
{"xxragddnt", Attribute::kUndefined},
|
||||||
|
{"g44oup", Attribute::kUndefined},
|
||||||
|
{"grVVSSp", Attribute::kUndefined},
|
||||||
|
{"22RRp", Attribute::kUndefined},
|
||||||
|
{"d", Attribute::kUndefined},
|
||||||
|
{"i", Attribute::kUndefined},
|
||||||
|
{"OVd", Attribute::kUndefined},
|
||||||
|
{"inyerpolae", Attribute::kUndefined},
|
||||||
|
{"rrnterpolll77Ge", Attribute::kUndefined},
|
||||||
|
{"inte4pol00te", Attribute::kUndefined},
|
||||||
|
{"inoornt", Attribute::kUndefined},
|
||||||
|
{"inzzriat", Attribute::kUndefined},
|
||||||
|
{"n11pariiin", Attribute::kUndefined},
|
||||||
|
{"XXocation", Attribute::kUndefined},
|
||||||
|
{"lIIc9955nnon", Attribute::kUndefined},
|
||||||
|
{"aaoHHatioYSS", Attribute::kUndefined},
|
||||||
|
{"mkksue", Attribute::kUndefined},
|
||||||
|
{"gjs_RRs", Attribute::kUndefined},
|
||||||
|
{"msb_se", Attribute::kUndefined},
|
||||||
|
{"jize", Attribute::kUndefined},
|
||||||
|
{"sze", Attribute::kUndefined},
|
||||||
|
{"qz", Attribute::kUndefined},
|
||||||
|
{"vNNtex", Attribute::kUndefined},
|
||||||
|
{"vevvx", Attribute::kUndefined},
|
||||||
|
{"veQQex", Attribute::kUndefined},
|
||||||
|
{"workgrrupffie", Attribute::kUndefined},
|
||||||
|
{"workgroup_sije", Attribute::kUndefined},
|
||||||
|
{"workgoupNNwsiz8", Attribute::kUndefined},
|
||||||
|
};
|
||||||
|
|
||||||
|
using AttributeParseTest = testing::TestWithParam<Case>;
|
||||||
|
|
||||||
|
TEST_P(AttributeParseTest, Parse) {
|
||||||
|
const char* string = GetParam().string;
|
||||||
|
Attribute expect = GetParam().value;
|
||||||
|
EXPECT_EQ(expect, ParseAttribute(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(ValidCases, AttributeParseTest, testing::ValuesIn(kValidCases));
|
||||||
|
INSTANTIATE_TEST_SUITE_P(InvalidCases, AttributeParseTest, testing::ValuesIn(kInvalidCases));
|
||||||
|
|
||||||
|
using AttributePrintTest = testing::TestWithParam<Case>;
|
||||||
|
|
||||||
|
TEST_P(AttributePrintTest, Print) {
|
||||||
|
Attribute value = GetParam().value;
|
||||||
|
const char* expect = GetParam().string;
|
||||||
|
EXPECT_EQ(expect, utils::ToString(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(ValidCases, AttributePrintTest, testing::ValuesIn(kValidCases));
|
||||||
|
|
||||||
|
} // namespace parse_print_tests
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace tint::builtin
|
|
@ -0,0 +1,31 @@
|
||||||
|
{{- /*
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Template file for use with tools/src/cmd/gen to generate attribute_test.cc
|
||||||
|
|
||||||
|
To update the generated file, run:
|
||||||
|
./tools/run gen
|
||||||
|
|
||||||
|
See:
|
||||||
|
* tools/src/cmd/gen for structures used by this template
|
||||||
|
* https://golang.org/pkg/text/template/ for documentation on the template syntax
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
*/ -}}
|
||||||
|
|
||||||
|
{{- Import "src/tint/templates/enums.tmpl.inc" -}}
|
||||||
|
{{- $enum := (Sem.Enum "attribute") -}}
|
||||||
|
|
||||||
|
#include "src/tint/builtin/attribute.h"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "src/tint/utils/string.h"
|
||||||
|
|
||||||
|
namespace tint::builtin {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
{{ Eval "TestParsePrintEnum" $enum}}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace tint::builtin
|
|
@ -211,6 +211,29 @@ enum builtin_type {
|
||||||
texture_external
|
texture_external
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://gpuweb.github.io/gpuweb/wgsl/#attributes
|
||||||
|
// Notes:
|
||||||
|
// * `diagnostic` is listed, even though it is a keyword, so it appears in suggested alternatives
|
||||||
|
// * `const` is not listed here as it can not be written in user programs and should not show up
|
||||||
|
// in error messages
|
||||||
|
enum attribute {
|
||||||
|
align
|
||||||
|
binding
|
||||||
|
builtin
|
||||||
|
compute
|
||||||
|
diagnostic
|
||||||
|
fragment
|
||||||
|
group
|
||||||
|
id
|
||||||
|
interpolate
|
||||||
|
invariant
|
||||||
|
location
|
||||||
|
must_use
|
||||||
|
size
|
||||||
|
vertex
|
||||||
|
workgroup_size
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// WGSL primitive types //
|
// WGSL primitive types //
|
||||||
// Types may be decorated with @precedence(N) to prioritize which type //
|
// Types may be decorated with @precedence(N) to prioritize which type //
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "src/tint/ast/unary_op_expression.h"
|
#include "src/tint/ast/unary_op_expression.h"
|
||||||
#include "src/tint/ast/variable_decl_statement.h"
|
#include "src/tint/ast/variable_decl_statement.h"
|
||||||
#include "src/tint/ast/workgroup_attribute.h"
|
#include "src/tint/ast/workgroup_attribute.h"
|
||||||
|
#include "src/tint/builtin/attribute.h"
|
||||||
#include "src/tint/reader/wgsl/classify_template_args.h"
|
#include "src/tint/reader/wgsl/classify_template_args.h"
|
||||||
#include "src/tint/reader/wgsl/lexer.h"
|
#include "src/tint/reader/wgsl/lexer.h"
|
||||||
#include "src/tint/type/depth_texture.h"
|
#include "src/tint/type/depth_texture.h"
|
||||||
|
@ -2988,9 +2989,12 @@ Expect<const ast::Attribute*> ParserImpl::expect_attribute() {
|
||||||
Maybe<const ast::Attribute*> ParserImpl::attribute() {
|
Maybe<const ast::Attribute*> ParserImpl::attribute() {
|
||||||
// Note, the ATTR is matched by the called `attribute_list` in this case, so it is not matched
|
// Note, the ATTR is matched by the called `attribute_list` in this case, so it is not matched
|
||||||
// here and this has to be an attribute.
|
// here and this has to be an attribute.
|
||||||
auto& t = next();
|
auto& t = peek();
|
||||||
|
|
||||||
if (t.Is(Token::Type::kDiagnostic)) {
|
if (match(Token::Type::kConst)) {
|
||||||
|
return add_error(t.source(), "const attribute may not appear in shaders");
|
||||||
|
}
|
||||||
|
if (match(Token::Type::kDiagnostic)) {
|
||||||
auto control = expect_diagnostic_control();
|
auto control = expect_diagnostic_control();
|
||||||
if (control.errored) {
|
if (control.errored) {
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
|
@ -2998,21 +3002,41 @@ Maybe<const ast::Attribute*> ParserImpl::attribute() {
|
||||||
return create<ast::DiagnosticAttribute>(t.source(), std::move(control.value));
|
return create<ast::DiagnosticAttribute>(t.source(), std::move(control.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!t.IsIdentifier()) {
|
auto attr = expect_enum("attribute", builtin::ParseAttribute, builtin::kAttributeStrings);
|
||||||
return Failure::kNoMatch;
|
if (attr.errored) {
|
||||||
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
utils::Vector<const ast::Expression*, 2> exprs;
|
uint32_t min = 1;
|
||||||
auto parse = [&](uint32_t min, uint32_t max) -> Maybe<bool> {
|
uint32_t max = 1;
|
||||||
// Handle no parameter items which should have no parens
|
switch (attr.value) {
|
||||||
if (min == 0) {
|
case builtin::Attribute::kCompute:
|
||||||
auto& p = peek();
|
case builtin::Attribute::kFragment:
|
||||||
if (p.Is(Token::Type::kParenLeft)) {
|
case builtin::Attribute::kInvariant:
|
||||||
return add_error(p.source(), t.to_str() + " attribute doesn't take parenthesis");
|
case builtin::Attribute::kMustUse:
|
||||||
}
|
case builtin::Attribute::kVertex:
|
||||||
return true;
|
min = 0;
|
||||||
}
|
max = 0;
|
||||||
|
break;
|
||||||
|
case builtin::Attribute::kInterpolate:
|
||||||
|
max = 2;
|
||||||
|
break;
|
||||||
|
case builtin::Attribute::kWorkgroupSize:
|
||||||
|
max = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::Vector<const ast::Expression*, 2> args;
|
||||||
|
|
||||||
|
// Handle no parameter items which should have no parens
|
||||||
|
if (min == 0) {
|
||||||
|
auto& t2 = peek();
|
||||||
|
if (match(Token::Type::kParenLeft)) {
|
||||||
|
return add_error(t2.source(), t.to_str() + " attribute doesn't take parenthesis");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
auto res = expect_paren_block(t.to_str() + " attribute", [&]() -> Expect<bool> {
|
auto res = expect_paren_block(t.to_str() + " attribute", [&]() -> Expect<bool> {
|
||||||
while (continue_parsing()) {
|
while (continue_parsing()) {
|
||||||
if (peek().Is(Token::Type::kParenRight)) {
|
if (peek().Is(Token::Type::kParenRight)) {
|
||||||
|
@ -3023,7 +3047,7 @@ Maybe<const ast::Attribute*> ParserImpl::attribute() {
|
||||||
if (expr.errored) {
|
if (expr.errored) {
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
exprs.Push(expr.value);
|
args.Push(expr.value);
|
||||||
|
|
||||||
if (!match(Token::Type::kComma)) {
|
if (!match(Token::Type::kComma)) {
|
||||||
break;
|
break;
|
||||||
|
@ -3035,138 +3059,54 @@ Maybe<const ast::Attribute*> ParserImpl::attribute() {
|
||||||
return Failure::kErrored;
|
return Failure::kErrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exprs.IsEmpty() || exprs.Length() < min) {
|
if (args.IsEmpty() || args.Length() < min) {
|
||||||
return add_error(t.source(),
|
return add_error(t.source(),
|
||||||
t.to_str() + " expects" + (min != max ? " at least " : " ") +
|
t.to_str() + " expects" + (min != max ? " at least " : " ") +
|
||||||
std::to_string(min) + " argument" + (min > 1 ? "s" : ""));
|
std::to_string(min) + " argument" + (min != 1 ? "s" : ""));
|
||||||
}
|
}
|
||||||
|
if (args.Length() > max) {
|
||||||
if (exprs.Length() > max) {
|
|
||||||
return add_error(t.source(),
|
return add_error(t.source(),
|
||||||
t.to_str() + " expects" + (min != max ? " at most " : " ") +
|
t.to_str() + " expects" + (min != max ? " at most " : " ") +
|
||||||
std::to_string(max) + " argument" + (max > 1 ? "s" : "") +
|
std::to_string(max) + " argument" + (max != 1 ? "s" : "") +
|
||||||
", got " + std::to_string(exprs.Length()));
|
", got " + std::to_string(args.Length()));
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (t == "align") {
|
|
||||||
auto res = parse(1, 1);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::StructMemberAlignAttribute>(t.source(), exprs[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t == "binding") {
|
switch (attr.value) {
|
||||||
auto res = parse(1, 1);
|
case builtin::Attribute::kAlign:
|
||||||
if (res.errored) {
|
return create<ast::StructMemberAlignAttribute>(t.source(), args[0]);
|
||||||
return Failure::kErrored;
|
case builtin::Attribute::kBinding:
|
||||||
}
|
return create<ast::BindingAttribute>(t.source(), args[0]);
|
||||||
return create<ast::BindingAttribute>(t.source(), exprs[0]);
|
case builtin::Attribute::kBuiltin:
|
||||||
|
return create<ast::BuiltinAttribute>(t.source(), args[0]);
|
||||||
|
case builtin::Attribute::kCompute:
|
||||||
|
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kCompute);
|
||||||
|
case builtin::Attribute::kFragment:
|
||||||
|
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kFragment);
|
||||||
|
case builtin::Attribute::kGroup:
|
||||||
|
return create<ast::GroupAttribute>(t.source(), args[0]);
|
||||||
|
case builtin::Attribute::kId:
|
||||||
|
return create<ast::IdAttribute>(t.source(), args[0]);
|
||||||
|
case builtin::Attribute::kInterpolate:
|
||||||
|
return create<ast::InterpolateAttribute>(t.source(), args[0],
|
||||||
|
args.Length() == 2 ? args[1] : nullptr);
|
||||||
|
case builtin::Attribute::kInvariant:
|
||||||
|
return create<ast::InvariantAttribute>(t.source());
|
||||||
|
case builtin::Attribute::kLocation:
|
||||||
|
return builder_.Location(t.source(), args[0]);
|
||||||
|
case builtin::Attribute::kMustUse:
|
||||||
|
return create<ast::MustUseAttribute>(t.source());
|
||||||
|
case builtin::Attribute::kSize:
|
||||||
|
return builder_.MemberSize(t.source(), args[0]);
|
||||||
|
case builtin::Attribute::kVertex:
|
||||||
|
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kVertex);
|
||||||
|
case builtin::Attribute::kWorkgroupSize:
|
||||||
|
return create<ast::WorkgroupAttribute>(t.source(), args[0],
|
||||||
|
args.Length() > 1 ? args[1] : nullptr,
|
||||||
|
args.Length() > 2 ? args[2] : nullptr);
|
||||||
|
default:
|
||||||
|
return Failure::kNoMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t == "builtin") {
|
|
||||||
auto res = parse(1, 1);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::BuiltinAttribute>(t.source(), exprs[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == "compute") {
|
|
||||||
auto res = parse(0, 0);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kCompute);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note, `const` is not valid in a WGSL source file, it's internal only
|
|
||||||
|
|
||||||
if (t == "fragment") {
|
|
||||||
auto res = parse(0, 0);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kFragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == "group") {
|
|
||||||
auto res = parse(1, 1);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::GroupAttribute>(t.source(), exprs[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == "id") {
|
|
||||||
auto res = parse(1, 1);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::IdAttribute>(t.source(), exprs[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == "interpolate") {
|
|
||||||
auto res = parse(1, 2);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::InterpolateAttribute>(t.source(), exprs[0],
|
|
||||||
exprs.Length() == 2 ? exprs[1] : nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == "invariant") {
|
|
||||||
auto res = parse(0, 0);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::InvariantAttribute>(t.source());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == "location") {
|
|
||||||
auto res = parse(1, 1);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return builder_.Location(t.source(), exprs[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == "must_use") {
|
|
||||||
auto res = parse(0, 0);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::MustUseAttribute>(t.source());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == "size") {
|
|
||||||
auto res = parse(1, 1);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return builder_.MemberSize(t.source(), exprs[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == "vertex") {
|
|
||||||
auto res = parse(0, 0);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::StageAttribute>(t.source(), ast::PipelineStage::kVertex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t == "workgroup_size") {
|
|
||||||
auto res = parse(1, 3);
|
|
||||||
if (res.errored) {
|
|
||||||
return Failure::kErrored;
|
|
||||||
}
|
|
||||||
return create<ast::WorkgroupAttribute>(t.source(), exprs[0],
|
|
||||||
exprs.Length() > 1 ? exprs[1] : nullptr,
|
|
||||||
exprs.Length() > 2 ? exprs[2] : nullptr);
|
|
||||||
}
|
|
||||||
return Failure::kNoMatch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ParserImpl::expect_attributes_consumed(utils::VectorRef<const ast::Attribute*> in) {
|
bool ParserImpl::expect_attributes_consumed(utils::VectorRef<const ast::Attribute*> in) {
|
||||||
|
|
|
@ -59,6 +59,14 @@ TEST_F(ParserImplErrorTest, AliasDeclInvalidAttribute) {
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ParserImplErrorTest, ConstAttributeInvalid) {
|
||||||
|
EXPECT("@const fn main() { }",
|
||||||
|
R"(test.wgsl:1:2 error: const attribute may not appear in shaders
|
||||||
|
@const fn main() { }
|
||||||
|
^^^^^
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ParserImplErrorTest, IndexExprInvalidExpr) {
|
TEST_F(ParserImplErrorTest, IndexExprInvalidExpr) {
|
||||||
EXPECT("fn f() { x = y[^]; }",
|
EXPECT("fn f() { x = y[^]; }",
|
||||||
R"(test.wgsl:1:16 error: unable to parse expression inside []
|
R"(test.wgsl:1:16 error: unable to parse expression inside []
|
||||||
|
|
|
@ -54,12 +54,9 @@ fn x(.) {}
|
||||||
^
|
^
|
||||||
|
|
||||||
test.wgsl:4:2 error: expected attribute
|
test.wgsl:4:2 error: expected attribute
|
||||||
|
Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size'
|
||||||
@_ fn -> {}
|
@_ fn -> {}
|
||||||
^
|
^
|
||||||
|
|
||||||
test.wgsl:4:7 error: expected identifier for function declaration
|
|
||||||
@_ fn -> {}
|
|
||||||
^^
|
|
||||||
)");
|
)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +122,7 @@ test.wgsl:5:10 error: expected ':' for struct member
|
||||||
^^^^
|
^^^^
|
||||||
|
|
||||||
test.wgsl:7:6 error: expected attribute
|
test.wgsl:7:6 error: expected attribute
|
||||||
|
Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size'
|
||||||
@- x : i32,
|
@- x : i32,
|
||||||
^
|
^
|
||||||
)");
|
)");
|
||||||
|
|
|
@ -51,7 +51,9 @@ TEST_F(ParserImplTest, AttributeList_Invalid) {
|
||||||
EXPECT_TRUE(attrs.errored);
|
EXPECT_TRUE(attrs.errored);
|
||||||
EXPECT_FALSE(attrs.matched);
|
EXPECT_FALSE(attrs.matched);
|
||||||
EXPECT_TRUE(attrs.value.IsEmpty());
|
EXPECT_TRUE(attrs.value.IsEmpty());
|
||||||
EXPECT_EQ(p->error(), "1:2: expected attribute");
|
EXPECT_EQ(p->error(), R"(1:2: expected attribute
|
||||||
|
Did you mean 'invariant'?
|
||||||
|
Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size')");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -50,7 +50,9 @@ TEST_F(ParserImplTest, AttributeList_Invalid) {
|
||||||
EXPECT_TRUE(attrs.errored);
|
EXPECT_TRUE(attrs.errored);
|
||||||
EXPECT_FALSE(attrs.matched);
|
EXPECT_FALSE(attrs.matched);
|
||||||
EXPECT_TRUE(attrs.value.IsEmpty());
|
EXPECT_TRUE(attrs.value.IsEmpty());
|
||||||
EXPECT_EQ(p->error(), R"(1:2: expected attribute)");
|
EXPECT_EQ(p->error(), R"(1:2: expected attribute
|
||||||
|
Did you mean 'invariant'?
|
||||||
|
Possible values: 'align', 'binding', 'builtin', 'compute', 'diagnostic', 'fragment', 'group', 'id', 'interpolate', 'invariant', 'location', 'must_use', 'size', 'vertex', 'workgroup_size')");
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue