+2008-09-06 Jason Merrill <jason@redhat.com>
+
+ PR c++/37302
+ * parser.c (cp_parser_parameter_declaration_list): Process the
+ PARM_DECLs as we go and push them. Return a TREE_LIST.
+ (cp_parser_parameter_declaration_clause): Return a TREE_LIST.
+ (cp_parser_direct_declarator): Create a binding level and
+ suppress deprecated warnings in the parameter list.
+ (make_call_declarator): PARMS is now a tree.
+ * cp-tree.h (struct cp_declarator): Function parms are now a tree.
+ * decl.h (enum deprecated_states, deprecated_state): Move here.
+ * decl.c: From here.
+ (type_is_deprecated): New fn.
+ (grokparms): PARMLIST is a tree now. Warn about parms that
+ use deprecated types.
+ * mangle.c (write_expression): Handle PARM_DECL, CALL_EXPR and
+ 0-operand cast.
+ * pt.c (tsubst) [DECLTYPE_TYPE]: Set skip_evaluation.
+ (tsubst_copy) [PARM_DECL]: Handle a PARM_DECL used outside of a
+ function.
+ * name-lookup.c (pushtag): Look through function parameter scopes.
+ (pushdecl_maybe_friend): Don't set DECL_CONTEXT on a PARM_DECL
+ when we're parsing a function declarator.
+
2008-09-05 Douglas Gregor <doug.gregor@gmail.com>
PR c++/37342
} id;
/* For functions. */
struct {
- /* The parameters to the function. */
- cp_parameter_declarator *parameters;
+ /* The parameters to the function as a TREE_LIST of decl/default. */
+ tree parameters;
/* The cv-qualifiers for the function. */
cp_cv_quals qualifiers;
/* The exception-specification for the function. */
#include "tree-flow.h"
#include "pointer-set.h"
-static tree grokparms (cp_parameter_declarator *, tree *);
+static tree grokparms (tree parmlist, tree *);
static const char *redeclaration_error_message (tree, tree);
static int decl_jump_unsafe (tree);
with __attribute__((deprecated)). An object declared as
__attribute__((deprecated)) suppresses warnings of uses of other
deprecated items. */
-
-enum deprecated_states {
- DEPRECATED_NORMAL,
- DEPRECATED_SUPPRESS
-};
-
-static enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
+enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
\f
/* A TREE_LIST of VAR_DECLs. The TREE_PURPOSE is a RECORD_TYPE or
return arg;
}
+/* Returns a deprecated type used within TYPE, or NULL_TREE if none. */
+
+static tree
+type_is_deprecated (tree type)
+{
+ enum tree_code code;
+ if (TREE_DEPRECATED (type))
+ return type;
+ if (TYPE_NAME (type)
+ && TREE_DEPRECATED (TYPE_NAME (type)))
+ return type;
+
+ code = TREE_CODE (type);
+
+ if (code == POINTER_TYPE || code == REFERENCE_TYPE
+ || code == OFFSET_TYPE || code == FUNCTION_TYPE
+ || code == METHOD_TYPE || code == ARRAY_TYPE)
+ return type_is_deprecated (TREE_TYPE (type));
+
+ if (TYPE_PTRMEMFUNC_P (type))
+ return type_is_deprecated
+ (TREE_TYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type))));
+
+ return NULL_TREE;
+}
+
/* Decode the list of parameter types for a function type.
Given the list of things declared inside the parens,
return a list of types.
*PARMS is set to the chain of PARM_DECLs created. */
static tree
-grokparms (cp_parameter_declarator *first_parm, tree *parms)
+grokparms (tree parmlist, tree *parms)
{
tree result = NULL_TREE;
tree decls = NULL_TREE;
- int ellipsis = !first_parm || first_parm->ellipsis_p;
- cp_parameter_declarator *parm;
+ tree parm;
int any_error = 0;
- struct pointer_set_t *unique_decls = pointer_set_create ();
- for (parm = first_parm; parm != NULL; parm = parm->next)
+ for (parm = parmlist; parm != NULL_TREE; parm = TREE_CHAIN (parm))
{
tree type = NULL_TREE;
- tree init = parm->default_argument;
- tree attrs;
- tree decl;
+ tree init = TREE_PURPOSE (parm);
+ tree decl = TREE_VALUE (parm);
- if (parm == no_parameters)
+ if (parm == void_list_node)
break;
- attrs = parm->decl_specifiers.attributes;
- parm->decl_specifiers.attributes = NULL_TREE;
- decl = grokdeclarator (parm->declarator, &parm->decl_specifiers,
- PARM, init != NULL_TREE, &attrs);
if (! decl || TREE_TYPE (decl) == error_mark_node)
continue;
- if (attrs)
- cplus_decl_attributes (&decl, attrs, 0);
-
type = TREE_TYPE (decl);
if (VOID_TYPE_P (type))
{
if (same_type_p (type, void_type_node)
&& DECL_SELF_REFERENCE_P (type)
- && !DECL_NAME (decl) && !result && !parm->next && !ellipsis)
+ && !DECL_NAME (decl) && !result && TREE_CHAIN (parm) == void_list_node)
/* this is a parmlist of `(void)', which is ok. */
break;
cxx_incomplete_type_error (decl, type);
if (type != error_mark_node)
{
+ if (deprecated_state != DEPRECATED_SUPPRESS)
+ {
+ tree deptype = type_is_deprecated (type);
+ if (deptype)
+ warn_deprecated_use (deptype);
+ }
+
/* Top-level qualifiers on the parameters are
ignored for function types. */
type = cp_build_qualified_type (type, 0);
if (TREE_CODE (decl) == PARM_DECL
&& FUNCTION_PARAMETER_PACK_P (decl)
- && parm->next)
+ && TREE_CHAIN (parm)
+ && TREE_CHAIN (parm) != void_list_node)
error ("parameter packs must be at the end of the parameter list");
- if (DECL_NAME (decl))
- {
- if (pointer_set_contains (unique_decls, DECL_NAME (decl)))
- error ("multiple parameters named %qE", DECL_NAME (decl));
- else
- pointer_set_insert (unique_decls, DECL_NAME (decl));
- }
-
TREE_CHAIN (decl) = decls;
decls = decl;
result = tree_cons (init, type, result);
}
decls = nreverse (decls);
result = nreverse (result);
- if (!ellipsis)
+ if (parm)
result = chainon (result, void_list_node);
*parms = decls;
- pointer_set_destroy (unique_decls);
return result;
}
extern tree grokdeclarator (const cp_declarator *,
const cp_decl_specifier_seq *,
enum decl_context, int, tree*);
+
+/* States indicating how grokdeclarator() should handle declspecs marked
+ with __attribute__((deprecated)). An object declared as
+ __attribute__((deprecated)) suppresses warnings of uses of other
+ deprecated items. */
+
+enum deprecated_states {
+ DEPRECATED_NORMAL,
+ DEPRECATED_SUPPRESS
+};
+
+extern enum deprecated_states deprecated_state;
+
<expr-primary> ::= <template-param>
::= L <type> <value number> E # literal
::= L <mangled-name> E # external name
- ::= sr <type> <unqualified-name>
+ ::= st <type> # sizeof
+ ::= sr <type> <unqualified-name> # dependent name
::= sr <type> <unqualified-name> <template-args> */
static void
code = TREE_CODE (expr);
}
+ if (code == OVERLOAD)
+ {
+ expr = OVL_FUNCTION (expr);
+ code = TREE_CODE (expr);
+ }
+
/* Handle pointers-to-members by making them look like expression
nodes. */
if (code == PTRMEM_CST)
else if (TREE_CODE_CLASS (code) == tcc_constant
|| (abi_version_at_least (2) && code == CONST_DECL))
write_template_arg_literal (expr);
+ else if (code == PARM_DECL)
+ {
+ /* A function parameter used under decltype in a late-specified
+ return type. Represented with a type placeholder. */
+ write_string ("sT");
+ write_type (non_reference (TREE_TYPE (expr)));
+ }
else if (DECL_P (expr))
{
/* G++ 3.2 incorrectly mangled non-type template arguments of
switch (code)
{
case CALL_EXPR:
- sorry ("call_expr cannot be mangled due to a defect in the C++ ABI");
+ write_expression (CALL_EXPR_FN (expr));
+ for (i = 0; i < call_expr_nargs (expr); ++i)
+ write_expression (CALL_EXPR_ARG (expr, i));
+ write_char ('E');
break;
case CAST_EXPR:
write_type (TREE_TYPE (expr));
- /* There is no way to mangle a zero-operand cast like
- "T()". */
if (!TREE_OPERAND (expr, 0))
- sorry ("zero-operand casts cannot be mangled due to a defect "
- "in the C++ ABI");
+ /* "T()" is mangled as "T(void)". */
+ write_char ('v');
else
write_expression (TREE_VALUE (TREE_OPERAND (expr, 0)));
break;
write_expression (TREE_OPERAND (expr, 0));
break;
-
/* Handle pointers-to-members specially. */
case SCOPE_REF:
write_type (TREE_OPERAND (expr, 0));
scope of the current namespace, not the current
function. */
&& !(TREE_CODE (x) == VAR_DECL && DECL_EXTERNAL (x))
+ /* When parsing the parameter list of a function declarator,
+ don't set DECL_CONTEXT to an enclosing function. When we
+ push the PARM_DECLs in order to process the function body,
+ current_binding_level->this_entity will be set. */
+ && !(TREE_CODE (x) == PARM_DECL
+ && current_binding_level->kind == sk_function_parms
+ && current_binding_level->this_entity == NULL)
&& !DECL_CONTEXT (x))
DECL_CONTEXT (x) = current_function_decl;
}
else if (TREE_CODE (t) == PARM_DECL)
{
- gcc_assert (DECL_CONTEXT (t));
-
/* Check for duplicate params. */
if (duplicate_decls (x, t, is_friend))
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
while (/* Cleanup scopes are not scopes from the point of view of
the language. */
b->kind == sk_cleanup
+ /* Neither are function parameter scopes. */
+ || b->kind == sk_function_parms
/* Neither are the scopes used to hold template parameters
for an explicit specialization. For an ordinary template
declaration, these scopes are not scopes from the point of
VAR_DECLs or FUNCTION_DECLs) should do that directly. */
static cp_declarator *make_call_declarator
- (cp_declarator *, cp_parameter_declarator *, cp_cv_quals, tree, tree);
+ (cp_declarator *, tree, cp_cv_quals, tree, tree);
static cp_declarator *make_array_declarator
(cp_declarator *, tree);
static cp_declarator *make_pointer_declarator
cp_declarator *
make_call_declarator (cp_declarator *target,
- cp_parameter_declarator *parms,
+ tree parms,
cp_cv_quals cv_qualifiers,
tree exception_specification,
tree late_return_type)
(cp_parser *);
static void cp_parser_type_specifier_seq
(cp_parser *, bool, cp_decl_specifier_seq *);
-static cp_parameter_declarator *cp_parser_parameter_declaration_clause
+static tree cp_parser_parameter_declaration_clause
(cp_parser *);
-static cp_parameter_declarator *cp_parser_parameter_declaration_list
+static tree cp_parser_parameter_declaration_list
(cp_parser *, bool *);
static cp_parameter_declarator *cp_parser_parameter_declaration
(cp_parser *, bool, bool *);
if (!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
{
- cp_parameter_declarator *params;
+ tree params;
unsigned saved_num_template_parameter_lists;
+ bool is_declarator = false;
+ tree t;
/* In a member-declarator, the only valid interpretation
of a parenthesis is the start of a
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
+ begin_scope (sk_function_parms, NULL_TREE);
+
/* Parse the parameter-declaration-clause. */
params = cp_parser_parameter_declaration_clause (parser);
tree exception_specification;
tree late_return;
+ is_declarator = true;
+
if (ctor_dtor_or_conv_p)
*ctor_dtor_or_conv_p = *ctor_dtor_or_conv_p < 0;
first = false;
return type, so are not those of the declared
function. */
parser->default_arg_ok_p = false;
-
- /* Repeat the main loop. */
- continue;
}
+
+ /* Remove the function parms from scope. */
+ for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
+ pop_binding (DECL_NAME (t), t);
+ leave_scope();
+
+ if (is_declarator)
+ /* Repeat the main loop. */
+ continue;
}
/* If this is the first, we can try a parenthesized
value of NULL indicates a parameter-declaration-clause consisting
only of an ellipsis. */
-static cp_parameter_declarator *
+static tree
cp_parser_parameter_declaration_clause (cp_parser* parser)
{
- cp_parameter_declarator *parameters;
+ tree parameters;
cp_token *token;
bool ellipsis_p;
bool is_error;
{
/* Consume the `...' token. */
cp_lexer_consume_token (parser->lexer);
- return NULL;
+ return NULL_TREE;
}
else if (token->type == CPP_CLOSE_PAREN)
/* There are no parameters. */
#ifndef NO_IMPLICIT_EXTERN_C
if (in_system_header && current_class_type == NULL
&& current_lang_name == lang_name_c)
- return NULL;
+ return NULL_TREE;
else
#endif
- return no_parameters;
+ return void_list_node;
}
/* Check for `(void)', too, which is a special case. */
else if (token->keyword == RID_VOID
/* Consume the `void' token. */
cp_lexer_consume_token (parser->lexer);
/* There are no parameters. */
- return no_parameters;
+ return void_list_node;
}
/* Parse the parameter-declaration-list. */
ellipsis_p = false;
/* Finish the parameter list. */
- if (parameters && ellipsis_p)
- parameters->ellipsis_p = true;
+ if (!ellipsis_p)
+ parameters = chainon (parameters, void_list_node);
return parameters;
}
`void_list_node' is never appended to the list. Upon return,
*IS_ERROR will be true iff an error occurred. */
-static cp_parameter_declarator *
+static tree
cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
{
- cp_parameter_declarator *parameters = NULL;
- cp_parameter_declarator **tail = ¶meters;
+ tree parameters = NULL_TREE;
+ tree *tail = ¶meters;
bool saved_in_unbraced_linkage_specification_p;
/* Assume all will go well. */
while (true)
{
cp_parameter_declarator *parameter;
+ tree decl = error_mark_node;
bool parenthesized_p;
/* Parse the parameter. */
parameter
/*template_parm_p=*/false,
&parenthesized_p);
+ /* We don't know yet if the enclosing context is deprecated, so wait
+ and warn in grokparms if appropriate. */
+ deprecated_state = DEPRECATED_SUPPRESS;
+
+ if (parameter)
+ decl = grokdeclarator (parameter->declarator,
+ ¶meter->decl_specifiers,
+ PARM,
+ parameter->default_argument != NULL_TREE,
+ ¶meter->decl_specifiers.attributes);
+
+ deprecated_state = DEPRECATED_NORMAL;
+
/* If a parse error occurred parsing the parameter declaration,
then the entire parameter-declaration-list is erroneous. */
- if (!parameter)
+ if (decl == error_mark_node)
{
*is_error = true;
- parameters = NULL;
+ parameters = error_mark_node;
break;
}
+
+ if (parameter->decl_specifiers.attributes)
+ cplus_decl_attributes (&decl,
+ parameter->decl_specifiers.attributes,
+ 0);
+ if (DECL_NAME (decl))
+ decl = pushdecl (decl);
+
/* Add the new parameter to the list. */
- *tail = parameter;
- tail = ¶meter->next;
+ *tail = build_tree_list (parameter->default_argument, decl);
+ tail = &TREE_CHAIN (*tail);
/* Peek at the next token. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
{
tree type;
- type =
- finish_decltype_type (tsubst_expr
- (DECLTYPE_TYPE_EXPR (t), args,
- complain, in_decl,
- /*integral_constant_expression_p=*/false),
+ ++skip_evaluation;
+
+ type = tsubst_expr (DECLTYPE_TYPE_EXPR (t), args,
+ complain, in_decl,
+ /*integral_constant_expression_p=*/false);
+
+ --skip_evaluation;
+
+ type =
+ finish_decltype_type (type,
DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (t));
return cp_build_qualified_type_real (type,
cp_type_quals (t)
{
case PARM_DECL:
r = retrieve_local_specialization (t);
- gcc_assert (r != NULL);
+
+ if (r == NULL)
+ {
+ /* This can happen for a parameter name used later in a function
+ declaration (such as in a late-specified return type).
+ Replace it with an arbitrary expression with the same type
+ (*(T*)0). This should only occur in an unevaluated context
+ (i.e. decltype). */
+ gcc_assert (skip_evaluation && DECL_CONTEXT (t) == NULL_TREE);
+ r = non_reference (TREE_TYPE (t));
+ r = tsubst (r, args, complain, in_decl);
+ r = build_pointer_type (r);
+ r = build_c_cast (r, null_node);
+ return cp_build_indirect_ref (r, NULL, tf_warning_or_error);
+ }
+
if (TREE_CODE (r) == ARGUMENT_PACK_SELECT)
r = ARGUMENT_PACK_SELECT_ARG (r);
mark_used (r);
case 42:
break;
}
+
+ auto j = 42, k = 24;
}
auto x; // { dg-error "auto" }
+// If the type deduced for the template parameter U is not the same in each
+// deduction, the program is ill-formed.
+auto i = 42, j = 42.0; // { dg-error "" "" { xfail *-*-* } }
+
// New CWG issue
auto a[2] = { 1, 2 }; // { dg-error "auto" }
}
template<class T, class U>
-auto add(T t, U u) -> decltype (t+u); // { dg-bogus "not declared" "" { xfail *-*-* } }
+auto add(T t, U u) -> decltype (t+u);
+
+template<class T, class U>
+decltype(T()+U()) add2(T t, U u);
+
+template <class T, class U>
+U g (T, U);
+
+template<class T, class U>
+auto add3(T t, U u) -> decltype (g(t,u));
+
+int main()
+{
+ auto i = add(1, 2.0);
+ auto i2 = add2(1, 2.0);
+ auto i3 = add3(1, 2.0);
+}
extern void g0 (int a, int b);
extern void g1 (int a, float b);
-extern void f0 (int a,
- int a); // { dg-error "multiple parameters named 'a'" }
-extern void f1 (int a,
- float a); // { dg-error "multiple parameters named 'a'" }
-extern void f3 (int a, int b, int c,
- int a); // { dg-error "multiple parameters named 'a'" }
-extern void f4 (int a, int b, int c,
- int a,
- int a); // { dg-error "multiple parameters named 'a'" }
-extern void f5 (int a, int b, int c, int d, int e, int f, int g, int h,
- int a,
+extern void f0 (int a, // { dg-error "previous" }
+ int a); // { dg-error "redefinition" }
+extern void f1 (int a, // { dg-error "previous" }
+ float a); // { dg-error "conflicting" }
+extern void f3 (int a, int b, int c, // { dg-error "previous" }
+ int a); // { dg-error "redefinition" }
+extern void f4 (int a, int b, int c, // { dg-error "previous" }
+ int a, // { dg-error "redefinition" }
+ int a); // { dg-error "redefinition" }
+extern void f5 (int a, int b, int c, int d, int e, int f, int g, int h, // { dg-error "previous" }
+ int a, // { dg-error "redefinition" }
int i, int j, int k, int l, int m, int n, int o, int p,
int q, int r, int s, int t, int u, int v, int w, int x, int y,
- int z); // { dg-error "multiple parameters named 'a'" }
+ int z);
-extern void f6 (int a, int, int, int, int, int, int, int, int, int, int,
- int a,
+extern void f6 (int a, int, int, int, int, int, int, int, int, int, int, // { dg-error "previous" }
+ int a, // { dg-error "redefinition" }
int, int, int, int, int, int, int, int, int, int, int,
float, float, float, float, float, float, float, float,
- int); // { dg-error "multiple parameters named 'a'" }
-
-extern void f7 (void (*a)(int),
- void (*a)(int)); // { dg-error "multiple parameters named 'a'" }
-extern void f8 (float (*a)(int),
- int (*a)(float)); // { dg-error "multiple parameters named 'a'" }
-
-extern void f9 (int a,
- int a,
- int a);
-// { dg-error "multiple parameters named 'a'" "" { target *-*-* } 34 }
-
-extern void f10 (int a,
- int b,
- int c,
- int c,
- int b,
- int a);
-// { dg-error "multiple parameters named 'a'" "" { target *-*-* } 42 }
-// { dg-error "multiple parameters named 'b'" "" { target *-*-* } 42 }
-// { dg-error "multiple parameters named 'c'" "" { target *-*-* } 42 }
+ int);
+
+extern void f7 (void (*a)(int), // { dg-error "previous" }
+ void (*a)(int)); // { dg-error "redefinition" }
+extern void f8 (float (*a)(int), // { dg-error "previous" }
+ int (*a)(float)); // { dg-error "conflicting" }
+
+extern void f9 (int a, // { dg-error "previous" }
+ int a, // { dg-error "redefinition" }
+ int a); // { dg-error "redefinition" }
+
+extern void f10 (int a, // { dg-error "previous" }
+ int b, // { dg-error "previous" }
+ int c, // { dg-error "previous" }
+ int c, // { dg-error "redefinition" }
+ int b, // { dg-error "redefinition" }
+ int a); // { dg-error "redefinition" }
class C1 {
public:
void C1_g0 (int a, int b);
- void C1_f0 (int a,
- int a); // { dg-error "multiple parameters named 'a'" }
+ void C1_f0 (int a, // { dg-error "previous" }
+ int a); // { dg-error "redefinition" }
};
template <class T>
class C2 {
public:
void C2_g0 (T a, T b);
- void C2_f0 (T a,
- T a); // { dg-error "multiple parameters named 'a'" }
+ void C2_f0 (T a, // { dg-error "previous" }
+ T a); // { dg-error "redefinition" }
};
// { dg-do compile }
// Make sure we emit a decent error message when trying to mangle an
// expression not supported by the C++ ABI due to a defect.
+// Update: Better to make it supported, I think...
template <int N>
struct A {};
int main()
{
- func<B>(); // { dg-error "sorry, unimplemented" }
+ func<B>();
}
void bar()
{
- foo<0>(0);
+ foo<0>(0); // { dg-error "" }
}
char*, char*,
unsigned*));
// { dg-error "64: error: expected ',' or '...' before '&' token" "" { target *-*-* } { 5 } }
-
-/// in the coming test, the column information is broken as it points to
-// the end of the declaration instead of pointing to the begining of the
-// 'TYPE' identifier. This is due to the warning being generated by the
-// declaration groking code (gcc/cp/decl.c) and not the parser. So in that
-// code, the exact token location information is lost as the declaration
-// groking code manipulates TREEs only. The token location used is then
-// the global one that is not accurate enough. Anyway, let's say it is
-// good enough for now, until we find a way to propagate token location to
-// code paths that manipulate TREEs only.
-// { dg-error "64: error: ISO C\\+\\+ forbids declaration of 'TYPE' with no type" "" { target *-*-* } { 7 } }
+// { dg-error "60: error: ISO C\\+\\+ forbids declaration of 'TYPE' with no type" "" { target *-*-* } { 5 } }
// { dg-do assemble }
// Bug: g++ doesn't push parameter decls as they are parsed.
-void (*ptr) (int foo, int array[sizeof(foo)]); // { dg-bogus "" "" { xfail *-*-* } }
-void test2 (int bar, int array[sizeof(bar)]) { } // { dg-bogus "" "" { xfail *-*-* } }
+void (*ptr) (int foo, int array[sizeof(foo)]);
+void test2 (int bar, int array[sizeof(bar)]) { }
};
void bar() {
- foo<>::bar(0); // { dg-error "" "" } instantiated from here
+ foo<>::bar(0);
}
void f(U u);
template <class U>
- void g(U U);
+ void g(U u);
int c[16];
};