From 934a6e81b13aea403285a841bec6e4d29fbdfcfc Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Wed, 7 Feb 2024 20:05:06 +1300 Subject: [PATCH] Implict cast fix - Allow implicit casts from serializable enums to their underlying type in action calls --- bootstrap.sh | 2 +- frontends/p4/typeChecking/typeChecker.cpp | 4 ++- frontends/p4/typeChecking/typeConstraints.cpp | 6 ++++ frontends/p4/typeChecking/typeConstraints.h | 2 ++ frontends/p4/typeChecking/typeUnification.cpp | 2 ++ testdata/p4_16_errors/serEnumImplCast.p4 | 22 +++++++++++++ .../p4_16_errors_outputs/serEnumImplCast.p4 | 32 +++++++++++++++++++ .../serEnumImplCast.p4-stderr | 6 ++++ testdata/p4_16_samples/serEnumImplCast.p4 | 22 +++++++++++++ .../serEnumImplCast-first.p4 | 32 +++++++++++++++++++ .../serEnumImplCast-frontend.p4 | 7 ++++ .../p4_16_samples_outputs/serEnumImplCast.p4 | 32 +++++++++++++++++++ .../serEnumImplCast.p4-stderr | 1 + 13 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 testdata/p4_16_errors/serEnumImplCast.p4 create mode 100644 testdata/p4_16_errors_outputs/serEnumImplCast.p4 create mode 100644 testdata/p4_16_errors_outputs/serEnumImplCast.p4-stderr create mode 100644 testdata/p4_16_samples/serEnumImplCast.p4 create mode 100644 testdata/p4_16_samples_outputs/serEnumImplCast-first.p4 create mode 100644 testdata/p4_16_samples_outputs/serEnumImplCast-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/serEnumImplCast.p4 create mode 100644 testdata/p4_16_samples_outputs/serEnumImplCast.p4-stderr diff --git a/bootstrap.sh b/bootstrap.sh index 2496eef0f72..9bad99d3a63 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -111,4 +111,4 @@ make_relative_link () make_relative_link "${mydir}/.gdbinit" "backends/bmv2/p4c-bm2-psa-gdb.gdb" make_relative_link "${mydir}/.gdbinit" "backends/bmv2/p4c-bm2-ss-gdb.gdb" make_relative_link "${mydir}/.gdbinit" "backends/dpdk/p4c-dpdk-gdb.gdb" -make_relative_link "${mydir}/.gdbinit" "backends/dpdk/p4test-gdb.gdb" +make_relative_link "${mydir}/.gdbinit" "backends/p4test/p4test-gdb.gdb" diff --git a/frontends/p4/typeChecking/typeChecker.cpp b/frontends/p4/typeChecking/typeChecker.cpp index f06f33bd084..40d83eb4d74 100644 --- a/frontends/p4/typeChecking/typeChecker.cpp +++ b/frontends/p4/typeChecking/typeChecker.cpp @@ -3496,7 +3496,7 @@ const IR::Expression *TypeInference::actionCall(bool inActionList, if (paramType == nullptr || argType == nullptr) // type checking failed before return actionCall; - constraints.addEqualityConstraint(actionCall, paramType, argType); + constraints.addImplicitCastConstraint(actionCall, paramType, argType); if (param->direction == IR::Direction::None) { if (inActionList) { typeError("%1%: parameter %2% cannot be bound: it is set by the control plane", arg, @@ -3512,6 +3512,8 @@ const IR::Expression *TypeInference::actionCall(bool inActionList, typeError("%1%: action argument must be a compile-time constant", arg->expression); } + // This is like an assignment; may make additional conversions. + newExpr = assignment(arg, param->type, arg->expression); } else if (param->direction == IR::Direction::Out || param->direction == IR::Direction::InOut) { if (!isLeftValue(arg->expression)) diff --git a/frontends/p4/typeChecking/typeConstraints.cpp b/frontends/p4/typeChecking/typeConstraints.cpp index 27050e6c851..417fe280bed 100644 --- a/frontends/p4/typeChecking/typeConstraints.cpp +++ b/frontends/p4/typeChecking/typeConstraints.cpp @@ -28,6 +28,12 @@ void TypeConstraints::addEqualityConstraint(const IR::Node *source, const IR::Ty add(c); } +void TypeConstraints::addImplicitCastConstraint(const IR::Node *source, const IR::Type *left, + const IR::Type *right) { + auto c = new CanBeImplicitlyCastConstraint(left, right, source); + add(c); +} + TypeVariableSubstitution *TypeConstraints::solve() { LOG3("Solving constraints:\n" << *this); currentSubstitution = new TypeVariableSubstitution(); diff --git a/frontends/p4/typeChecking/typeConstraints.h b/frontends/p4/typeChecking/typeConstraints.h index d98db8baf10..d3a75302205 100644 --- a/frontends/p4/typeChecking/typeConstraints.h +++ b/frontends/p4/typeChecking/typeConstraints.h @@ -280,6 +280,8 @@ class TypeConstraints final : public IHasDbPrint { constraints.push_back(constraint); } void addEqualityConstraint(const IR::Node *source, const IR::Type *left, const IR::Type *right); + void addImplicitCastConstraint(const IR::Node *source, const IR::Type *left, + const IR::Type *right); /* * Solve the specified constraint. * @param subst Variable substitution which is updated with new constraints. diff --git a/frontends/p4/typeChecking/typeUnification.cpp b/frontends/p4/typeChecking/typeUnification.cpp index 2ea76ffd06b..741137dcb88 100644 --- a/frontends/p4/typeChecking/typeUnification.cpp +++ b/frontends/p4/typeChecking/typeUnification.cpp @@ -444,10 +444,12 @@ bool TypeUnification::unify(const BinaryConstraint *constraint) { if (!success) return constraint->reportError(constraints->getCurrentSubstitution()); return true; } else if (auto se = dest->to()) { +#if 1 if (constraint->is()) { constraints->add(constraint->create(se->type, src)); return true; } +#endif return constraint->reportError(constraints->getCurrentSubstitution()); } else if (dest->is() && src->is()) { if (dest->to()->name != src->to()->name) diff --git a/testdata/p4_16_errors/serEnumImplCast.p4 b/testdata/p4_16_errors/serEnumImplCast.p4 new file mode 100644 index 00000000000..49e793a81fb --- /dev/null +++ b/testdata/p4_16_errors/serEnumImplCast.p4 @@ -0,0 +1,22 @@ +#include + +enum bit<2> foo_t { A = 0, B = 1, C = 2, D = 3 } + +struct meta_t { + bit<2> x; + bit<6> y; +} + +control c(inout meta_t m) { + action set_x(foo_t v) { m.x = v; } + + table t { + key = { m.y : exact; } + actions = { set_x; } + default_action = set_x(2w0); // not allowed to implicitly cast to serenum + } + + apply { + t.apply(); + } +} diff --git a/testdata/p4_16_errors_outputs/serEnumImplCast.p4 b/testdata/p4_16_errors_outputs/serEnumImplCast.p4 new file mode 100644 index 00000000000..cf5c706e185 --- /dev/null +++ b/testdata/p4_16_errors_outputs/serEnumImplCast.p4 @@ -0,0 +1,32 @@ +#include + +enum bit<2> foo_t { + A = 0, + B = 1, + C = 2, + D = 3 +} + +struct meta_t { + bit<2> x; + bit<6> y; +} + +control c(inout meta_t m) { + action set_x(foo_t v) { + m.x = v; + } + table t { + key = { + m.y: exact; + } + actions = { + set_x; + } + default_action = set_x(2w0); + } + apply { + t.apply(); + } +} + diff --git a/testdata/p4_16_errors_outputs/serEnumImplCast.p4-stderr b/testdata/p4_16_errors_outputs/serEnumImplCast.p4-stderr new file mode 100644 index 00000000000..ca221d13b06 --- /dev/null +++ b/testdata/p4_16_errors_outputs/serEnumImplCast.p4-stderr @@ -0,0 +1,6 @@ +serEnumImplCast.p4(16): [--Werror=type-error] error: '2w0': values of type 'bit<2>' cannot be implicitly cast to type 'foo_t' + default_action = set_x(2w0); // not allowed to implicitly cast to serenum + ^^^ +serEnumImplCast.p4(3) +enum bit<2> foo_t { A = 0, B = 1, C = 2, D = 3 } + ^^^^^ diff --git a/testdata/p4_16_samples/serEnumImplCast.p4 b/testdata/p4_16_samples/serEnumImplCast.p4 new file mode 100644 index 00000000000..cc284ff052b --- /dev/null +++ b/testdata/p4_16_samples/serEnumImplCast.p4 @@ -0,0 +1,22 @@ +#include + +enum bit<2> foo_t { A = 0, B = 1, C = 2, D = 3 } + +struct meta_t { + bit<2> x; + bit<6> y; +} + +control c(inout meta_t m) { + action set_x(bit<2> v) { m.x = v; } + + table t { + key = { m.y : exact; } + actions = { set_x; } + default_action = set_x(foo_t.A); + } + + apply { + t.apply(); + } +} diff --git a/testdata/p4_16_samples_outputs/serEnumImplCast-first.p4 b/testdata/p4_16_samples_outputs/serEnumImplCast-first.p4 new file mode 100644 index 00000000000..ba98141e72d --- /dev/null +++ b/testdata/p4_16_samples_outputs/serEnumImplCast-first.p4 @@ -0,0 +1,32 @@ +#include + +enum bit<2> foo_t { + A = 2w0, + B = 2w1, + C = 2w2, + D = 2w3 +} + +struct meta_t { + bit<2> x; + bit<6> y; +} + +control c(inout meta_t m) { + action set_x(bit<2> v) { + m.x = v; + } + table t { + key = { + m.y: exact @name("m.y"); + } + actions = { + set_x(); + } + default_action = set_x(foo_t.A); + } + apply { + t.apply(); + } +} + diff --git a/testdata/p4_16_samples_outputs/serEnumImplCast-frontend.p4 b/testdata/p4_16_samples_outputs/serEnumImplCast-frontend.p4 new file mode 100644 index 00000000000..e0975ff56f7 --- /dev/null +++ b/testdata/p4_16_samples_outputs/serEnumImplCast-frontend.p4 @@ -0,0 +1,7 @@ +#include + +struct meta_t { + bit<2> x; + bit<6> y; +} + diff --git a/testdata/p4_16_samples_outputs/serEnumImplCast.p4 b/testdata/p4_16_samples_outputs/serEnumImplCast.p4 new file mode 100644 index 00000000000..f6a3bfc86e6 --- /dev/null +++ b/testdata/p4_16_samples_outputs/serEnumImplCast.p4 @@ -0,0 +1,32 @@ +#include + +enum bit<2> foo_t { + A = 0, + B = 1, + C = 2, + D = 3 +} + +struct meta_t { + bit<2> x; + bit<6> y; +} + +control c(inout meta_t m) { + action set_x(bit<2> v) { + m.x = v; + } + table t { + key = { + m.y: exact; + } + actions = { + set_x; + } + default_action = set_x(foo_t.A); + } + apply { + t.apply(); + } +} + diff --git a/testdata/p4_16_samples_outputs/serEnumImplCast.p4-stderr b/testdata/p4_16_samples_outputs/serEnumImplCast.p4-stderr new file mode 100644 index 00000000000..7e57a518ffd --- /dev/null +++ b/testdata/p4_16_samples_outputs/serEnumImplCast.p4-stderr @@ -0,0 +1 @@ +[--Wwarn=missing] warning: Program does not contain a `main' module