re PR c++/37806 (CV-qualifiers on function typedef's are inconsistently accepted depending on typedef scope)

* decl.c (grokdeclarator): Reject pointer to qualified function
        type.

        PR c++/37806, core issue 547
        * typeck.c (cp_apply_type_quals_to_decl): Don't apply any quals
        to a typedef.
        * tree.c (cp_build_qualified_type_real): Don't apply restrict to a
        function type.
        * decl.h (enum decl_context): Add TEMPLATE_TYPE_ARG.
        * decl.c (groktypename): Add is_template_arg parameter.
        (grokdeclarator): Allow function cv-quals on a template type arg.
        * parser.c (cp_parser_new_type_id, cp_parser_type_id): Add
        is_template_arg argument in calls to groktypename.
        * cp-tree.h: Adjust prototype.
        * error.c (dump_type_prefix, dump_type_suffix): Fix plain
        FUNCTION_TYPE printing.

        PR libstdc++/39310
        * include/tr1_impl/type_traits (is_function): Add partial
        specializations with function cv-quals.
        (__is_function_helper): Remove.
        (is_member_pointer): Don't define in terms of is_member_*_pointer.

From-SVN: r145648
This commit is contained in:
Jason Merrill 2009-04-07 00:38:10 -04:00 committed by Jason Merrill
parent e7326aee2c
commit 3f91721acb
14 changed files with 163 additions and 47 deletions

View File

@ -1,3 +1,22 @@
2009-04-07 Jason Merrill <jason@redhat.com>
* decl.c (grokdeclarator): Reject pointer to qualified function
type.
PR c++/37806, core issue 547
* typeck.c (cp_apply_type_quals_to_decl): Don't apply any quals
to a typedef.
* tree.c (cp_build_qualified_type_real): Don't apply restrict to a
function type.
* decl.h (enum decl_context): Add TEMPLATE_TYPE_ARG.
* decl.c (groktypename): Add is_template_arg parameter.
(grokdeclarator): Allow function cv-quals on a template type arg.
* parser.c (cp_parser_new_type_id, cp_parser_type_id): Add
is_template_arg argument in calls to groktypename.
* cp-tree.h: Adjust prototype.
* error.c (dump_type_prefix, dump_type_suffix): Fix plain
FUNCTION_TYPE printing.
2009-04-06 Jason Merrill <jason@redhat.com>
PR c++/35146

View File

@ -4331,7 +4331,7 @@ extern tree push_void_library_fn (tree, tree);
extern tree push_throw_library_fn (tree, tree);
extern tree check_tag_decl (cp_decl_specifier_seq *);
extern tree shadow_tag (cp_decl_specifier_seq *);
extern tree groktypename (cp_decl_specifier_seq *, const cp_declarator *);
extern tree groktypename (cp_decl_specifier_seq *, const cp_declarator *, bool);
extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int, tree, tree, tree *);
extern void start_decl_1 (tree, bool);
extern bool check_array_initializer (tree, tree, tree);

View File

@ -3967,13 +3967,16 @@ shadow_tag (cp_decl_specifier_seq *declspecs)
tree
groktypename (cp_decl_specifier_seq *type_specifiers,
const cp_declarator *declarator)
const cp_declarator *declarator,
bool is_template_arg)
{
tree attrs;
tree type;
enum decl_context context
= is_template_arg ? TEMPLATE_TYPE_ARG : TYPENAME;
attrs = type_specifiers->attributes;
type_specifiers->attributes = NULL_TREE;
type = grokdeclarator (declarator, type_specifiers, TYPENAME, 0, &attrs);
type = grokdeclarator (declarator, type_specifiers, context, 0, &attrs);
if (attrs && type != error_mark_node)
{
if (CLASS_TYPE_P (type))
@ -7603,6 +7606,7 @@ grokdeclarator (const cp_declarator *declarator,
bool type_was_error_mark_node = false;
bool parameter_pack_p = declarator? declarator->parameter_pack_p : false;
bool set_no_warning = false;
bool template_type_arg = false;
signed_p = declspecs->specs[(int)ds_signed];
unsigned_p = declspecs->specs[(int)ds_unsigned];
@ -7617,6 +7621,8 @@ grokdeclarator (const cp_declarator *declarator,
funcdef_flag = true, decl_context = FIELD;
else if (decl_context == BITFIELD)
bitfield = 1, decl_context = FIELD;
else if (decl_context == TEMPLATE_TYPE_ARG)
template_type_arg = true, decl_context = TYPENAME;
if (initialized > 1)
funcdef_flag = true;
@ -8476,6 +8482,12 @@ grokdeclarator (const cp_declarator *declarator,
memfn_quals = TYPE_UNQUALIFIED;
}
if (TREE_CODE (type) == FUNCTION_TYPE
&& cp_type_quals (type) != TYPE_UNQUALIFIED)
error ("cannot declare %s to qualified function type %qT",
declarator->kind == cdk_reference ? "reference" : "pointer",
type);
if (declarator->kind == cdk_reference)
{
/* In C++0x, the type we are creating a reference to might be
@ -8948,15 +8960,17 @@ grokdeclarator (const cp_declarator *declarator,
}
else if (memfn_quals)
{
if (ctype == NULL_TREE)
{
if (TREE_CODE (type) != METHOD_TYPE)
error ("invalid qualifiers on non-member function type");
else
ctype = TYPE_METHOD_BASETYPE (type);
}
if (ctype == NULL_TREE
&& TREE_CODE (type) == METHOD_TYPE)
ctype = TYPE_METHOD_BASETYPE (type);
if (ctype)
type = build_memfn_type (type, ctype, memfn_quals);
/* Core issue #547: need to allow this in template type args. */
else if (template_type_arg && TREE_CODE (type) == FUNCTION_TYPE)
type = cp_build_qualified_type (type, memfn_quals);
else
error ("invalid qualifiers on non-member function type");
}
return type;

View File

@ -27,6 +27,7 @@ enum decl_context
FIELD, /* Declaration inside struct or union */
BITFIELD, /* Likewise but with specified width */
TYPENAME, /* Typename (inside cast or sizeof) */
TEMPLATE_TYPE_ARG, /* Almost the same as TYPENAME */
MEMFUNCDEF /* Member function definition */
};

View File

@ -550,7 +550,8 @@ dump_type_prefix (tree t, int flags)
tree sub = TREE_TYPE (t);
dump_type_prefix (sub, flags);
if (TREE_CODE (sub) == ARRAY_TYPE)
if (TREE_CODE (sub) == ARRAY_TYPE
|| TREE_CODE (sub) == FUNCTION_TYPE)
{
pp_cxx_whitespace (cxx_pp);
pp_cxx_left_paren (cxx_pp);
@ -585,12 +586,10 @@ dump_type_prefix (tree t, int flags)
pp_base (cxx_pp)->padding = pp_before;
break;
/* Can only be reached through function pointer -- this would not be
correct if FUNCTION_DECLs used it. */
/* This can be reached without a pointer when dealing with
templates, e.g. std::is_function. */
case FUNCTION_TYPE:
dump_type_prefix (TREE_TYPE (t), flags);
pp_maybe_space (cxx_pp);
pp_cxx_left_paren (cxx_pp);
break;
case METHOD_TYPE:
@ -654,17 +653,19 @@ dump_type_suffix (tree t, int flags)
case POINTER_TYPE:
case REFERENCE_TYPE:
case OFFSET_TYPE:
if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE
|| TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
pp_cxx_right_paren (cxx_pp);
dump_type_suffix (TREE_TYPE (t), flags);
break;
/* Can only be reached through function pointer. */
case FUNCTION_TYPE:
case METHOD_TYPE:
{
tree arg;
pp_cxx_right_paren (cxx_pp);
if (TREE_CODE (t) == METHOD_TYPE)
/* Can only be reached through a pointer. */
pp_cxx_right_paren (cxx_pp);
arg = TYPE_ARG_TYPES (t);
if (TREE_CODE (t) == METHOD_TYPE)
arg = TREE_CHAIN (arg);
@ -677,7 +678,7 @@ dump_type_suffix (tree t, int flags)
pp_cxx_cv_qualifier_seq
(cxx_pp, TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))));
else
pp_cxx_cv_qualifier_seq(cxx_pp, t);
pp_cxx_cv_qualifier_seq (cxx_pp, t);
dump_exception_spec (TYPE_RAISES_EXCEPTIONS (t), flags);
dump_type_suffix (TREE_TYPE (t), flags);
break;

View File

@ -1733,6 +1733,10 @@ static tree cp_parser_declarator_id
(cp_parser *, bool);
static tree cp_parser_type_id
(cp_parser *);
static tree cp_parser_template_type_arg
(cp_parser *);
static tree cp_parser_type_id_1
(cp_parser *, bool);
static void cp_parser_type_specifier_seq
(cp_parser *, bool, cp_decl_specifier_seq *);
static tree cp_parser_parameter_declaration_clause
@ -5773,7 +5777,7 @@ cp_parser_new_type_id (cp_parser* parser, tree *nelts)
new_declarator = NULL;
}
type = groktypename (&type_specifier_seq, new_declarator);
type = groktypename (&type_specifier_seq, new_declarator, false);
return type;
}
@ -10545,7 +10549,7 @@ cp_parser_template_argument (cp_parser* parser)
Therefore, we try a type-id first. */
cp_parser_parse_tentatively (parser);
argument = cp_parser_type_id (parser);
argument = cp_parser_template_type_arg (parser);
/* If there was no error parsing the type-id but the next token is a
'>>', our behavior depends on which dialect of C++ we're
parsing. In C++98, we probably found a typo for '> >'. But there
@ -10733,7 +10737,7 @@ cp_parser_template_argument (cp_parser* parser)
was the only alternative that matched (albeit with a '>' after
it). We can assume it's just a typo from the user, and a
diagnostic will then be issued. */
return cp_parser_type_id (parser);
return cp_parser_template_type_arg (parser);
}
/* Parse an explicit-instantiation.
@ -13767,7 +13771,7 @@ cp_parser_declarator_id (cp_parser* parser, bool optional_p)
Returns the TYPE specified. */
static tree
cp_parser_type_id (cp_parser* parser)
cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg)
{
cp_decl_specifier_seq type_specifier_seq;
cp_declarator *abstract_declarator;
@ -13796,7 +13800,18 @@ cp_parser_type_id (cp_parser* parser)
return error_mark_node;
}
return groktypename (&type_specifier_seq, abstract_declarator);
return groktypename (&type_specifier_seq, abstract_declarator,
is_template_arg);
}
static tree cp_parser_type_id (cp_parser *parser)
{
return cp_parser_type_id_1 (parser, false);
}
static tree cp_parser_template_type_arg (cp_parser *parser)
{
return cp_parser_type_id_1 (parser, true);
}
/* Parse a type-specifier-seq.

View File

@ -852,11 +852,10 @@ cp_build_qualified_type_real (tree type,
}
/* A restrict-qualified type must be a pointer (or reference)
to object or incomplete type, or a function type. */
to object or incomplete type. */
if ((type_quals & TYPE_QUAL_RESTRICT)
&& TREE_CODE (type) != TEMPLATE_TYPE_PARM
&& TREE_CODE (type) != TYPENAME_TYPE
&& TREE_CODE (type) != FUNCTION_TYPE
&& !POINTER_TYPE_P (type))
{
bad_quals |= TYPE_QUAL_RESTRICT;

View File

@ -7239,6 +7239,9 @@ cp_apply_type_quals_to_decl (int type_quals, tree decl)
if (type == error_mark_node)
return;
if (TREE_CODE (decl) == TYPE_DECL)
return;
if (TREE_CODE (type) == FUNCTION_TYPE
&& type_quals != TYPE_UNQUALIFIED)
{

View File

@ -1,3 +1,10 @@
2009-04-07 Jason Merrill <jason@redhat.com>
* g++.dg/other/typedef2.C: New test.
PR c++/37806
* g++.dg/template/typedef17.C: New test.
2009-04-06 Laurent GUERBY <laurent@guerby.net>
* lib/gnat.exp: Handle multilib.

View File

@ -0,0 +1,3 @@
typedef void fn() const;
fn* fp; // { dg-error "pointer.*qualified function type" }

View File

@ -17,7 +17,7 @@ struct AS
template <typename T> struct B1 : T
{
typedef typename T::L __restrict__ r;// { dg-error "'__restrict__' qualifiers cannot" "" }
typedef typename T::myT __restrict__ p;// { dg-error "ignoring '__restrict__'" }
typedef typename T::myT __restrict__ p;
// The following are DR 295 dependent
typedef typename T::myT volatile *myvolatile;

View File

@ -0,0 +1,32 @@
// PR c++/37806
extern "C" int printf (const char *, ...);
template <typename T>
struct S1
{
typedef void (function_type)(int) const;
};
struct S2: public S1<int>
{
virtual function_type f = 0;
};
struct S3: public S2
{
void
f (int i) const
{
printf ("Hello world: %d\n", i);
}
};
int
main()
{
S3 s;
s.f(5);
}

View File

@ -1,3 +1,11 @@
2009-04-07 Jason Merrill <jason@redhat.com>
PR libstdc++/39310
* include/tr1_impl/type_traits (is_function): Add partial
specializations with function cv-quals.
(__is_function_helper): Remove.
(is_member_pointer): Don't define in terms of is_member_*_pointer.
2009-04-02 Jakub Jelinek <jakub@redhat.com>
* config/abi/post/powerpc64-linux-gnu/32/baseline_symbols.txt:

View File

@ -224,24 +224,34 @@ _GLIBCXX_BEGIN_NAMESPACE_TR1
: public integral_constant<bool, __is_class(_Tp)>
{ };
template<typename>
struct __is_function_helper
: public false_type { };
template<typename _Res, typename... _ArgTypes>
struct __is_function_helper<_Res(_ArgTypes...)>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct __is_function_helper<_Res(_ArgTypes......)>
: public true_type { };
/// is_function
template<typename _Tp>
template<typename>
struct is_function
: public integral_constant<bool, (__is_function_helper<typename
remove_cv<_Tp>::type>::value)>
{ };
: public false_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes...)>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......)>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes...) const>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......) const>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes...) volatile>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......) volatile>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes...) const volatile>
: public true_type { };
template<typename _Res, typename... _ArgTypes>
struct is_function<_Res(_ArgTypes......) const volatile>
: public true_type { };
// composite type traits [4.5.2].
@ -287,10 +297,14 @@ _GLIBCXX_BEGIN_NAMESPACE_TR1
/// is_member_pointer
template<typename _Tp>
struct is_member_pointer
: public integral_constant<bool,
(is_member_object_pointer<_Tp>::value
|| is_member_function_pointer<_Tp>::value)>
struct __is_member_pointer_helper
: public false_type { };
_DEFINE_SPEC(2, __is_member_pointer_helper, _Tp _Cp::*, true)
template<typename _Tp>
struct is_member_pointer
: public integral_constant<bool, (__is_member_pointer_helper<
typename remove_cv<_Tp>::type>::value)>
{ };
// type properties [4.5.3].