diff --git a/Lib/test/test_metaclass.py b/Lib/test/test_metaclass.py index e6fe20a107c..6edd899b0d2 100644 --- a/Lib/test/test_metaclass.py +++ b/Lib/test/test_metaclass.py @@ -128,7 +128,7 @@ Check for duplicate keywords. ... Traceback (most recent call last): [...] - SyntaxError: keyword argument repeated + SyntaxError: keyword argument repeated: metaclass >>> Another way. diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py index 128c4da1438..a7e7e2c9e6f 100644 --- a/Lib/test/test_syntax.py +++ b/Lib/test/test_syntax.py @@ -588,7 +588,7 @@ Make sure that the old "raise X, Y[, Z]" form is gone: >>> f(a=23, a=234) Traceback (most recent call last): ... -SyntaxError: keyword argument repeated +SyntaxError: keyword argument repeated: a >>> {1, 2, 3} = 42 Traceback (most recent call last): diff --git a/Python/ast.c b/Python/ast.c index 550ee03b1ac..6ba62fb479f 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -3048,8 +3048,7 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func, else { /* a keyword argument */ keyword_ty kw; - identifier key, tmp; - int k; + identifier key; // To remain LL(1), the grammar accepts any test (basically, any // expression) in the keyword slot of a call site. So, we need @@ -3093,14 +3092,6 @@ ast_for_call(struct compiling *c, const node *n, expr_ty func, if (forbidden_name(c, key, chch, 1)) { return NULL; } - for (k = 0; k < nkeywords; k++) { - tmp = ((keyword_ty)asdl_seq_GET(keywords, k))->arg; - if (tmp && !PyUnicode_Compare(tmp, key)) { - ast_error(c, chch, - "keyword argument repeated"); - return NULL; - } - } e = ast_for_expr(c, CHILD(ch, 2)); if (!e) return NULL; diff --git a/Python/compile.c b/Python/compile.c index 01700e0e78c..b1c1982fd2c 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4049,6 +4049,31 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e) return 1; } +static int +validate_keywords(struct compiler *c, asdl_seq* keywords) { + int nkeywords = asdl_seq_LEN(keywords); + for (int i = 0; i < nkeywords; i++) { + keyword_ty key = ((keyword_ty)asdl_seq_GET(keywords, i)); + if (key->arg == NULL) { + continue; + } + for (int j = i+1; j < nkeywords; j++) { + keyword_ty other = ((keyword_ty)asdl_seq_GET(keywords, j)); + if (other->arg && !PyUnicode_Compare(key->arg, other->arg)) { + PyObject *msg = PyUnicode_FromFormat("keyword argument repeated: %U", key->arg); + if (msg == NULL) { + return -1; + } + c->u->u_col_offset = other->col_offset; + compiler_error(c, PyUnicode_AsUTF8(msg)); + Py_DECREF(msg); + return -1; + } + } + } + return 0; +} + static int compiler_call(struct compiler *c, expr_ty e) { @@ -4165,6 +4190,10 @@ compiler_call_helper(struct compiler *c, { Py_ssize_t i, nseen, nelts, nkwelts; + if (validate_keywords(c, keywords) == -1) { + return 0; + } + nelts = asdl_seq_LEN(args); nkwelts = asdl_seq_LEN(keywords);