From 4fda4ff0cce13f649528201e620e4b2c00f7d0de Mon Sep 17 00:00:00 2001 From: Filip Sajdak Date: Wed, 19 Apr 2023 18:37:59 +0200 Subject: [PATCH] Add diagnostics for returning a temporary --- ...ure2-forward-return-diagnostics-error.cpp2 | 53 +++++++++++++++++++ ...rward-return-diagnostics-error.cpp2.output | 24 +++++++++ source/cppfront.cpp | 9 ++++ source/parse.h | 42 +++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 regression-tests/pure2-forward-return-diagnostics-error.cpp2 create mode 100644 regression-tests/test-results/pure2-forward-return-diagnostics-error.cpp2.output diff --git a/regression-tests/pure2-forward-return-diagnostics-error.cpp2 b/regression-tests/pure2-forward-return-diagnostics-error.cpp2 new file mode 100644 index 000000000..762c690d7 --- /dev/null +++ b/regression-tests/pure2-forward-return-diagnostics-error.cpp2 @@ -0,0 +1,53 @@ +fun1: () -> forward _ = { return global / 1; } // error: a 'forward' return type cannot return a temporary variable +fun4: () -> forward _ = { return global << 1; } // error: a 'forward' return type cannot return a temporary variable +fun5: () -> forward _ = { return global <=> 1; } // error: a 'forward' return type cannot return a temporary variable +fun6: () -> forward _ = { return global < 1; } // error: a 'forward' return type cannot return a temporary variable +fun7: () -> forward _ = { return global <= 1; } // error: a 'forward' return type cannot return a temporary variable +fun9: () -> forward _ = { return global >> 1; } // error: a 'forward' return type cannot return a temporary variable +fun10: () -> forward _ = { return global >= 1; } // error: a 'forward' return type cannot return a temporary variable +fun11: () -> forward _ = { return global > 1; } // error: a 'forward' return type cannot return a temporary variable +fun14: () -> forward _ = { return global + 1; } // error: a 'forward' return type cannot return a temporary variable +fun15: () -> forward _ = { return global - 1; } // error: a 'forward' return type cannot return a temporary variable +fun20: () -> forward _ = { return global || 1; } // error: a 'forward' return type cannot return a temporary variable +fun22: () -> forward _ = { return global | 1; } // error: a 'forward' return type cannot return a temporary variable +fun24: () -> forward _ = { return global && 1; } // error: a 'forward' return type cannot return a temporary variable +fun26: () -> forward _ = { return global * 1; } // error: a 'forward' return type cannot return a temporary variable +fun28: () -> forward _ = { return global % 1; } // error: a 'forward' return type cannot return a temporary variable +fun30: () -> forward _ = { return global & 1; } // error: a 'forward' return type cannot return a temporary variable +fun32: () -> forward _ = { return global ^ 1; } // error: a 'forward' return type cannot return a temporary variable +fun35: () -> forward _ = { return global == 1; } // error: a 'forward' return type cannot return a temporary variable +fun37: () -> forward _ = { return global != 1; } // error: a 'forward' return type cannot return a temporary variable +fun38: () -> forward _ = { return !ptr_g; } // error: a 'forward' return type cannot return a temporary variable +fun42: () -> forward _ = { return global&; } // error: a 'forward' return type cannot return a temporary variable +fun43: () -> forward _ = { return ptr_g~; } // error: a 'forward' return type cannot return a temporary variable + +fun2: () -> forward _ = { return global /= 1; } +fun3: () -> forward _ = { return global <<= 1; } +fun8: () -> forward _ = { return global >>= 1; } +fun12: () -> forward _ = { return global++; } +fun13: () -> forward _ = { return global += 1; } +fun16: () -> forward _ = { return global -= 1; } +fun17: () -> forward _ = { return ptr_g*.x; } +fun18: () -> forward _ = { return global--; } +fun21: () -> forward _ = { return global |= 1; } +fun25: () -> forward _ = { return global *= 1; } +fun27: () -> forward _ = { return global %= 1; } +fun29: () -> forward _ = { return global &= 1; } +fun31: () -> forward _ = { return global ^= 1; } +fun36: () -> forward _ = { return global = 1; } +fun39: () -> forward _ = { return g.x; } +fun41: () -> forward _ = { return ptr_g*; } + +// fun19: () -> forward _ = { return global ||= 1; } // not supported +// fun23: () -> forward _ = { return global &&= 1; } // not supported +// fun33: () -> forward _ = { return global ~= 1; } // not supported +// fun34: () -> forward _ = { return global ~ 1; } // not supported +// fun40: () -> forward _ = { return ptr_g ? ptr_g* : g; } // not supported + +global: i32 = 42; +t: type = { + public x : int = 42; +} + +g: t = (); +ptr_g: *t = g&; diff --git a/regression-tests/test-results/pure2-forward-return-diagnostics-error.cpp2.output b/regression-tests/test-results/pure2-forward-return-diagnostics-error.cpp2.output new file mode 100644 index 000000000..d1df1ddcd --- /dev/null +++ b/regression-tests/test-results/pure2-forward-return-diagnostics-error.cpp2.output @@ -0,0 +1,24 @@ +pure2-forward-return-diagnostics-error.cpp2... +pure2-forward-return-diagnostics-error.cpp2(1,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(2,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(3,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(4,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(5,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(6,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(7,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(8,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(9,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(10,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(11,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(12,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(13,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(14,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(15,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(16,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(17,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(18,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(19,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(20,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(21,28): error: a 'forward' return type cannot return a temporary variable +pure2-forward-return-diagnostics-error.cpp2(22,28): error: a 'forward' return type cannot return a temporary variable + diff --git a/source/cppfront.cpp b/source/cppfront.cpp index 2275575bc..94481cccd 100644 --- a/source/cppfront.cpp +++ b/source/cppfront.cpp @@ -2206,6 +2206,15 @@ class cppfront "a 'forward' return type cannot return a local variable" ); return; + } else if ( + is_literal(tok->type()) || n.expression->expr->is_result_a_temporary_variable() + ) + { + errors.emplace_back( + n.position(), + "a 'forward' return type cannot return a temporary variable" + ); + return; } } diff --git a/source/parse.h b/source/parse.h index 936eb38a0..ea2d712c5 100644 --- a/source/parse.h +++ b/source/parse.h @@ -195,6 +195,8 @@ struct prefix_expression_node return expr.get(); } + auto is_result_a_temporary_variable() const -> bool; + auto position() const -> source_position; auto visit(auto& v, int depth) -> void; }; @@ -257,6 +259,20 @@ struct binary_expression_node return { nullptr, nullptr }; } + auto is_result_a_temporary_variable() const -> bool { + if constexpr (std::string_view(Name.value) == "assignment") { + assert(expr); + return expr->is_result_a_temporary_variable(); + } else { + if (terms.empty()) { + assert(expr); + return expr->is_result_a_temporary_variable(); + } else { + return true; + } + } + } + auto position() const -> source_position { @@ -470,6 +486,15 @@ struct postfix_expression_node auto get_first_token_ignoring_this() const -> token const*; + auto is_result_a_temporary_variable() const -> bool { + if (ops.empty()) { + return false; + } else { + return (ops.front().op->type() == lexeme::Ampersand + || ops.front().op->type() == lexeme::Tilde); + } + } + // Internals // auto position() const -> source_position @@ -481,6 +506,14 @@ struct postfix_expression_node auto visit(auto& v, int depth) -> void; }; +auto prefix_expression_node::is_result_a_temporary_variable() const -> bool { + if (ops.empty()) { + return expr->is_result_a_temporary_variable(); + } else { + return true; + } +} + auto expression_node::get_lhs_rhs_if_simple_assignment() const -> assignment_expression_lhs_rhs @@ -807,6 +840,15 @@ struct is_as_expression_node return expr->get_postfix_expression_node(); } + auto is_result_a_temporary_variable() const -> bool { + if (ops.empty()) { + assert(expr); + return expr->is_result_a_temporary_variable(); + } else { + return true; + } + } + auto position() const -> source_position {