From 15b2bfcb612b073ee87ffbce275059bada45b603 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 11 May 2017 15:00:44 -0400 Subject: [PATCH 5/5] FIXME: start generalizing to C (seems to break cc1plus, with GTY issues) --- gcc/ast.c | 5 ++ gcc/ast.def | 2 + gcc/c-family/c.opt | 4 +- gcc/c/c-decl.c | 13 ++- gcc/c/c-parser.c | 128 ++++++++++++++++++++++++++++- gcc/c/c-tree.h | 4 +- gcc/c/c-typeck.c | 58 ++++++++++--- gcc/testsuite/gcc.dg/param-type-mismatch.c | 55 +++++++++++++ 8 files changed, 251 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/param-type-mismatch.c diff --git a/gcc/ast.c b/gcc/ast.c index 07201ce..7f0217c 100644 --- a/gcc/ast.c +++ b/gcc/ast.c @@ -123,7 +123,12 @@ ast_node::dump (pretty_printer *pp, const char *prefix, if (m_tree) // FIXME: format code: +#if 1 + pp_printf (pp, " tree: %p", (void *)m_tree); +#else + // seems to work for C++: pp_printf (pp, " tree: %p %qE", (void *)m_tree, m_tree); +#endif /* Show source code. */ if (m_start != parent_start_loc || m_finish != parent_finish_loc) diff --git a/gcc/ast.def b/gcc/ast.def index be6bd25..eba2cf7 100644 --- a/gcc/ast.def +++ b/gcc/ast.def @@ -31,6 +31,7 @@ DEF_AST_NODE (AST_DECL_SPECIFIER_SEQ, "decl-specifier-seq") DEF_AST_NODE (AST_DIRECT_DECLARATOR, "direct-declarator") DEF_AST_NODE (AST_EXCEPTION_DECLARATION, "exception-declaration") DEF_AST_NODE (AST_EXPRESSION_LIST, "expression-list") +DEF_AST_NODE (AST_EXTERNAL_DECLARATION, "external-declaration") DEF_AST_NODE (AST_FUNCTION_TRY_BLOCK, "function-try-block") DEF_AST_NODE (AST_HANDLER, "handler") DEF_AST_NODE (AST_HANDLER_SEQ, "handler-seq") @@ -40,6 +41,7 @@ DEF_AST_NODE (AST_MEMBER_DECLARATION, "member-declaration") DEF_AST_NODE (AST_PARAMETER_DECLARATION, "parameter-declaration") DEF_AST_NODE (AST_PARAMETER_DECLARATION_CLAUSE, "parameter-declaration-clause") DEF_AST_NODE (AST_PARAMETER_DECLARATION_LIST, "parameter-declaration-list") +DEF_AST_NODE (AST_PARAMETER_LIST, "parameter-list") DEF_AST_NODE (AST_POSTFIX_EXPRESSION, "postfix-expression") DEF_AST_NODE (AST_PRIMARY_EXPRESSION, "primary-expression") DEF_AST_NODE (AST_SIMPLE_DECLARATION, "simple-declaration") diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 08b5655..09be6a5 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1205,7 +1205,7 @@ C ObjC C++ ObjC++ Where shorter, use canonicalized paths to systems headers. fcapture-ast -C++ ObjC++ Var(flag_capture_ast) +C ObjC C++ ObjC++ Var(flag_capture_ast) Capture the AST. fcheck-pointer-bounds @@ -1363,7 +1363,7 @@ C ObjC C++ ObjC++ RejectNegative Var(flag_dump_ada_spec_slim) Write all declarations as Ada code for the given file only. fdump-ast -C++ ObjC++ Var(flag_dump_ast) +C ObjC C++ ObjC++ Var(flag_dump_ast) Dump the AST. felide-constructors diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 64a1107..cdbf28f 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -53,6 +53,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "spellcheck-tree.h" #include "gcc-rich-location.h" +#include "ast.h" /* In grokdeclarator, distinguish syntactic contexts of declarators. */ enum decl_context @@ -4523,6 +4524,7 @@ build_array_declarator (location_t loc, } current_scope->had_vla_unspec = true; } + declarator->asnode = NULL; return declarator; } @@ -4647,6 +4649,8 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs, deprecated_state); if (!decl || decl == error_mark_node) return NULL_TREE; + if (declarator->asnode) + declarator->asnode->set_tree (decl); if (expr) add_stmt (fold_convert (void_type_node, expr)); @@ -8542,6 +8546,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator, decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL, &attributes, NULL, NULL, DEPRECATED_NORMAL); + if (declarator->asnode) + declarator->asnode->set_tree (decl1); invoke_plugin_callbacks (PLUGIN_START_PARSE_FUNCTION, decl1); /* If the declarator is not suitable for a function definition, @@ -9659,6 +9665,7 @@ build_attrs_declarator (tree attrs, struct c_declarator *target) ret->kind = cdk_attrs; ret->declarator = target; ret->u.attrs = attrs; + ret->asnode = NULL; return ret; } @@ -9667,12 +9674,14 @@ build_attrs_declarator (tree attrs, struct c_declarator *target) struct c_declarator * build_function_declarator (struct c_arg_info *args, - struct c_declarator *target) + struct c_declarator *target, + ast_node *asnode) { struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator); ret->kind = cdk_function; ret->declarator = target; ret->u.arg_info = args; + ret->asnode = asnode; return ret; } @@ -9688,6 +9697,7 @@ build_id_declarator (tree ident) ret->u.id = ident; /* Default value - may get reset to a more precise location. */ ret->id_loc = input_location; + ret->asnode = NULL; return ret; } @@ -9714,6 +9724,7 @@ make_pointer_declarator (struct c_declspecs *type_quals_attrs, ret->kind = cdk_pointer; ret->declarator = itarget; ret->u.pointer_quals = quals; + ret->asnode = NULL; return ret; } diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 9398652..707f965 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -65,6 +65,7 @@ along with GCC; see the file COPYING3. If not see #include "read-rtl-function.h" #include "run-rtl-passes.h" #include "intl.h" +#include "ast.h" /* We need to walk over decls with incomplete struct/union/enum types after parsing the whole translation unit. @@ -206,8 +207,112 @@ struct GTY(()) c_parser { /* Buffer to hold all the tokens from parsing the vector attribute for the SIMD-enabled functions (formerly known as elemental functions). */ vec *cilk_simd_fn_tokens; + + location_t last_token_location; + ast_node * GTY((skip)) ast_root_node; + ast_node * GTY((skip)) ast_current_node; }; +/* FIXME. */ +// RAII-style highlighting of the AST. + +/* FIXME. */ + +class auto_ast_node +{ +public: + auto_ast_node (c_parser* parser, enum ast_kind kind); + ~auto_ast_node (); + + void set_tree (tree node); + +private: + c_parser *m_parser; +}; + +/* FIXME. */ + +#define AUTO_AST_NODE(PARSER, KIND) \ + auto_ast_node tmp_ast_node ((PARSER), (KIND)) + +#define CURRENT_AST_NODE (parser->ast_current_node) + +#define AST_ADD_NEXT_TOKEN(PARSER) \ + add_next_token (PARSER) + +#define AST_SET_TREE(TREE_NODE) \ + tmp_ast_node.set_tree (TREE_NODE); + +#if 0 +static void +add_next_token (c_parser *parser) +{ + if (!flag_capture_ast) + return; + + c_token *token = c_parser_peek_token (parser); + ast_node *parent = parser->ast_current_node; + ast_node *node = new ast_node (AST_TOKEN, token->location); + parent->add_child (node); + // FIXME: get a meaningful string for the token + node->set_finish (token->location); +} +#endif + +/* FIXME. */ + +auto_ast_node::auto_ast_node (c_parser *parser, enum ast_kind kind) +: m_parser (parser) +{ + if (!flag_capture_ast) + return; + + c_token *first_token = c_parser_peek_token (parser); + ast_node *parent = parser->ast_current_node; + ast_node *node = new ast_node (kind, first_token->location); + parser->ast_current_node = node; + if (parent) + parent->add_child (node); + else + parser->ast_root_node = node; +} + +/* FIXME. */ + +auto_ast_node::~auto_ast_node () +{ + if (!flag_capture_ast) + return; + + ast_node *node = m_parser->ast_current_node; + node->set_finish (m_parser->last_token_location); + + if (0) + { + location_t start = node->get_start (); + location_t finish = node->get_finish (); + location_t range = make_location (start, start, finish); + inform (range, "%qs", node->get_name ()); + } + +#if 0 + if (m_expr_ptr) + node->set_tree (m_expr_ptr->get_value ()); +#endif + + m_parser->ast_current_node = node->get_parent (); +} + +void +auto_ast_node::set_tree (tree tree_node) +{ + if (!flag_capture_ast) + return; + + ast_node *node = m_parser->ast_current_node; + node->set_tree (tree_node); +} + /* Return a pointer to the Nth token in PARSERs tokens_buf. */ c_token * @@ -770,6 +875,7 @@ c_parser_consume_token (c_parser *parser) gcc_assert (parser->tokens[0].type != CPP_EOF); gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL); gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA); + parser->last_token_location = parser->tokens[0].location; if (parser->tokens != &parser->tokens_buf[0]) parser->tokens++; else if (parser->tokens_avail == 2) @@ -1334,6 +1440,8 @@ static void c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass); static void c_parser_translation_unit (c_parser *parser) { + AUTO_AST_NODE (parser, AST_TRANSLATION_UNIT); + if (c_parser_next_token_is (parser, CPP_EOF)) { pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic, @@ -1386,6 +1494,8 @@ c_parser_translation_unit (c_parser *parser) static void c_parser_external_declaration (c_parser *parser) { + AUTO_AST_NODE (parser, AST_EXTERNAL_DECLARATION); + int ext; switch (c_parser_peek_token (parser)->type) { @@ -3391,6 +3501,8 @@ struct c_declarator * c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, bool *seen_id) { + AUTO_AST_NODE (parser, AST_DECLARATOR); + /* Parse any initial pointer part. */ if (c_parser_next_token_is (parser, CPP_MULT)) { @@ -3417,6 +3529,8 @@ static struct c_declarator * c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, bool *seen_id) { + AUTO_AST_NODE (parser, AST_DIRECT_DECLARATOR); + /* The direct declarator must start with an identifier (possibly omitted) or a parenthesized declarator (possibly abstract). In an ordinary declarator, initial parentheses must start a @@ -3460,6 +3574,7 @@ c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, { struct c_declarator *inner = build_id_declarator (c_parser_peek_token (parser)->value); + inner->asnode = CURRENT_AST_NODE; *seen_id = true; inner->id_loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); @@ -3496,7 +3611,8 @@ c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind, { inner = build_function_declarator (args, - build_id_declarator (NULL_TREE)); + build_id_declarator (NULL_TREE), + CURRENT_AST_NODE); return c_parser_direct_declarator_inner (parser, *seen_id, inner); } @@ -3644,7 +3760,7 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present, return NULL; else { - inner = build_function_declarator (args, inner); + inner = build_function_declarator (args, inner, CURRENT_AST_NODE); return c_parser_direct_declarator_inner (parser, id_present, inner); } } @@ -3659,6 +3775,8 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present, static struct c_arg_info * c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs) { + AUTO_AST_NODE (parser, AST_PARAMETER_LIST); + push_scope (); declare_parm_level (); /* If the list starts with an identifier, it is an identifier list. @@ -3830,6 +3948,8 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr) static struct c_parm * c_parser_parameter_declaration (c_parser *parser, tree attrs) { + AUTO_AST_NODE (parser, AST_PARAMETER_DECLARATION); + struct c_declspecs *specs; struct c_declarator *declarator; tree prefix_attrs; @@ -18179,6 +18299,10 @@ c_parse_file (void) using_eh_for_cleanups (); c_parser_translation_unit (the_parser); + + if (flag_capture_ast && flag_dump_ast) + the_parser->ast_root_node->dump (stderr); + the_parser = NULL; } diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 5fa32a4..471b729 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -447,6 +447,7 @@ struct c_declarator { /* For attributes. */ tree attrs; } u; + ast_node *asnode; }; /* A type name. */ @@ -572,7 +573,8 @@ extern struct c_parm *build_c_parm (struct c_declspecs *, tree, extern struct c_declarator *build_attrs_declarator (tree, struct c_declarator *); extern struct c_declarator *build_function_declarator (struct c_arg_info *, - struct c_declarator *); + struct c_declarator *, + ast_node *); extern struct c_declarator *build_id_declarator (tree); extern struct c_declarator *make_pointer_declarator (struct c_declspecs *, struct c_declarator *); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 00a6577..79453f4 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see #include "gomp-constants.h" #include "spellcheck-tree.h" #include "gcc-rich-location.h" +#include "ast.h" /* Possible cases of implicit bad conversions. Used to select diagnostic messages in convert_for_assignment. */ @@ -6107,6 +6108,48 @@ maybe_warn_string_init (location_t loc, tree type, struct c_expr expr) "array initialized from parenthesized string constant"); } +/* FIXME. */ + +static location_t +get_fndecl_argument_location (tree fundecl, int argnum, location_t loc) +{ + ast_node *node = ast_get_node_for_tree (fundecl); + if (!node) + return loc; + + if (node->get_kind () != AST_DIRECT_DECLARATOR) + return loc; + + /* We expect a parameter-list containing parameter-declaration. */ + node = node->get_first_child_of_kind (AST_PARAMETER_LIST); + if (!node) + return loc; + + auto_vec params; + node->get_children_of_kind (params, AST_PARAMETER_DECLARATION); + + if (argnum >= (int)params.length ()) + return loc; + + ast_node *param = params[argnum]; + return param->get_range (); +} + +/* FIXME. */ + +static void +inform_for_arg (tree fundecl, location_t ploc, int parmnum, + tree expected_type, tree actual_type) +{ + location_t loc = (fundecl && !DECL_IS_BUILTIN (fundecl) + ? DECL_SOURCE_LOCATION (fundecl) : ploc); + loc = get_fndecl_argument_location (fundecl, parmnum - 1, loc); + + inform (loc, + "expected %qT but argument is of type %qT", + expected_type, actual_type); +} + /* Convert value RHS to type TYPE as preparation for an assignment to an lvalue of type TYPE. If ORIGTYPE is not NULL_TREE, it is the original type of RHS; this differs from TREE_TYPE (RHS) for enum @@ -6178,10 +6221,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, { \ case ic_argpass: \ if (pedwarn (PLOC, OPT, AR, parmnum, rname)) \ - inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \ - ? DECL_SOURCE_LOCATION (fundecl) : PLOC, \ - "expected %qT but argument is of type %qT", \ - type, rhstype); \ + inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ break; \ case ic_assign: \ pedwarn (LOCATION, OPT, AS); \ @@ -6207,10 +6247,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, { \ case ic_argpass: \ if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS)) \ - inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \ - ? DECL_SOURCE_LOCATION (fundecl) : PLOC, \ - "expected %qT but argument is of type %qT", \ - type, rhstype); \ + inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ break; \ case ic_assign: \ pedwarn (LOCATION, OPT, AS, QUALS); \ @@ -6236,10 +6273,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, { \ case ic_argpass: \ if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS)) \ - inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \ - ? DECL_SOURCE_LOCATION (fundecl) : PLOC, \ - "expected %qT but argument is of type %qT", \ - type, rhstype); \ + inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \ break; \ case ic_assign: \ warning_at (LOCATION, OPT, AS, QUALS); \ diff --git a/gcc/testsuite/gcc.dg/param-type-mismatch.c b/gcc/testsuite/gcc.dg/param-type-mismatch.c new file mode 100644 index 0000000..487978a --- /dev/null +++ b/gcc/testsuite/gcc.dg/param-type-mismatch.c @@ -0,0 +1,55 @@ +/* { dg-options "-fdiagnostics-show-caret -fcapture-ast" } */ + +/* decl, with argname. */ + +extern int callee_1 (int one, const char *two, float three); /* { dg-message "expected 'const char \\*' but argument is of type 'int'" } */ +/* { dg-begin-multiline-output "" } + extern int callee_1 (int one, const char *two, float three); + ^~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + +int test_1 (int first, int second, float third) +{ + return callee_1 (first, second, third); /* { dg-warning "passing argument 2 of 'callee_1' makes pointer from integer without a cast" } */ + /* { dg-begin-multiline-output "" } + return callee_1 (first, second, third); + ^~~~~~ + { dg-end-multiline-output "" } */ +} + +/* decl, without argname. */ + +extern int callee_2 (int, const char *, float); /* { dg-message "expected 'const char \\*' but argument is of type 'int'" } */ +/* { dg-begin-multiline-output "" } + extern int callee_2 (int, const char *, float); + ^~~~~~~~~~~~ + { dg-end-multiline-output "" } */ + +int test_2 (int first, int second, float third) +{ + return callee_2 (first, second, third); /* { dg-warning "passing argument 2 of 'callee_2' makes pointer from integer without a cast" } */ + /* { dg-begin-multiline-output "" } + return callee_2 (first, second, third); + ^~~~~~ + { dg-end-multiline-output "" } */ +} + +/* defn, with argname. */ + +static int callee_3 (int one, const char *two, float three) /* { dg-message "expected 'const char \\*' but argument is of type 'int'" } */ +/* { dg-begin-multiline-output "" } + static int callee_3 (int one, const char *two, float three) + ^~~~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +{ + return callee_2 (one, two, three); +} + +int test_3 (int first, int second, float third) +{ + return callee_3 (first, second, third); // { dg-warning "passing argument 2 of 'callee_3' makes pointer from integer without a cast" } + /* { dg-begin-multiline-output "" } + return callee_3 (first, second, third); + ^~~~~~ + { dg-end-multiline-output "" } */ +} -- 1.8.5.3