Commit 4f2b0fb2 by Nathan Sidwell Committed by Nathan Sidwell

PR c++/2645, DR 295

cp:
	PR c++/2645, DR 295
	* cp-tree.h (tsubst_flags_t): Add tf_ignore_bad_quals,
	tf_keep_type_decl.
	(make_typename_type): Use tsubst_flags_t.
	* decl.c (make_typename_type): Adjust. Return non-artificial
	TYPE_DECLs, if required.
	(grokdeclarator): Simplify CVR qualification handling. Allow bad
	qualifiers on typedef types.
	* decl2.c (handle_class_head): Adjust make_typename_type call.
	* parse.y (nested_name_specifier): Likewise.
	(typename_sub0): Likewise.
	(typename_sub1): Likewise.
	* pt.c (convert_template_argument): Adjust make_typename_type
	return value.
	(tsubst): Adjust cp_build_qualified_type_real calls.
	(check_cv_quals_for_unify): Cope with alowing bad qualifications
	on template type parms.
	(instantiate_decl): Recheck substitutions to give warnings on bad
	qualifications.
	* tree.c (cp_build_qualified_type_real): Use tf_allow_bad_quals.
testsuite:
	* g++.dg/template/qualttp19.C: New test.
	* g++.dg/template/qualttp20.C: New test.
	* g++.old-deja/g++.jason/report.C: Adjust expected errors
	* g++.old-deja/g++.other/qual1.C: Likewise.

From-SVN: r49961
parent 54fec3d5
2002-02-22 Nathan Sidwell <nathan@codesourcery.com>
PR c++/2645, DR 295
* cp-tree.h (tsubst_flags_t): Add tf_ignore_bad_quals,
tf_keep_type_decl.
(make_typename_type): Use tsubst_flags_t.
* decl.c (make_typename_type): Adjust. Return non-artificial
TYPE_DECLs, if required.
(grokdeclarator): Simplify CVR qualification handling. Allow bad
qualifiers on typedef types.
* decl2.c (handle_class_head): Adjust make_typename_type call.
* parse.y (nested_name_specifier): Likewise.
(typename_sub0): Likewise.
(typename_sub1): Likewise.
* pt.c (convert_template_argument): Adjust make_typename_type
return value.
(tsubst): Adjust cp_build_qualified_type_real calls.
(check_cv_quals_for_unify): Cope with alowing bad qualifications
on template type parms.
(instantiate_decl): Recheck substitutions to give warnings on bad
qualifications.
* tree.c (cp_build_qualified_type_real): Use tf_allow_bad_quals.
2002-02-21 Aldy Hernandez <aldyh@redhat.com> 2002-02-21 Aldy Hernandez <aldyh@redhat.com>
* cp/decl.c (duplicate_decls): Merge always_inline attribute. * cp/decl.c (duplicate_decls): Merge always_inline attribute.
......
...@@ -3070,7 +3070,10 @@ typedef enum tsubst_flags_t { ...@@ -3070,7 +3070,10 @@ typedef enum tsubst_flags_t {
tf_warning = 1 << 1, /* give warnings too */ tf_warning = 1 << 1, /* give warnings too */
tf_no_attributes = 1 << 2, /* ignore attributes on comparisons tf_no_attributes = 1 << 2, /* ignore attributes on comparisons
(instantiate_type use) */ (instantiate_type use) */
tf_ptrmem_ok = 1 << 3 /* pointers to member ok (internal tf_ignore_bad_quals = 1 << 3, /* ignore bad cvr qualifiers */
tf_keep_type_decl = 1 << 4, /* retain typedef type decls
(make_typename_type use) */
tf_ptrmem_ok = 1 << 5 /* pointers to member ok (internal
instantiate_type use) */ instantiate_type use) */
} tsubst_flags_t; } tsubst_flags_t;
...@@ -3693,7 +3696,7 @@ extern tree namespace_binding PARAMS ((tree, tree)); ...@@ -3693,7 +3696,7 @@ extern tree namespace_binding PARAMS ((tree, tree));
extern void set_namespace_binding PARAMS ((tree, tree, tree)); extern void set_namespace_binding PARAMS ((tree, tree, tree));
extern tree lookup_namespace_name PARAMS ((tree, tree)); extern tree lookup_namespace_name PARAMS ((tree, tree));
extern tree build_typename_type PARAMS ((tree, tree, tree, tree)); extern tree build_typename_type PARAMS ((tree, tree, tree, tree));
extern tree make_typename_type PARAMS ((tree, tree, int)); extern tree make_typename_type PARAMS ((tree, tree, tsubst_flags_t));
extern tree make_unbound_class_template PARAMS ((tree, tree, int)); extern tree make_unbound_class_template PARAMS ((tree, tree, int));
extern tree lookup_name_nonclass PARAMS ((tree)); extern tree lookup_name_nonclass PARAMS ((tree));
extern tree lookup_function_nonclass PARAMS ((tree, tree)); extern tree lookup_function_nonclass PARAMS ((tree, tree));
......
...@@ -5609,12 +5609,15 @@ build_typename_type (context, name, fullname, base_type) ...@@ -5609,12 +5609,15 @@ build_typename_type (context, name, fullname, base_type)
/* Resolve `typename CONTEXT::NAME'. Returns an appropriate type, /* Resolve `typename CONTEXT::NAME'. Returns an appropriate type,
unless an error occurs, in which case error_mark_node is returned. unless an error occurs, in which case error_mark_node is returned.
If COMPLAIN zero, don't complain about any errors that occur. */ If we locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is
set, we return that, rather than the _TYPE it corresponds to, in
other cases we look through the type decl. If TF_ERROR is set,
complain about errors, otherwise be quiet. */
tree tree
make_typename_type (context, name, complain) make_typename_type (context, name, complain)
tree context, name; tree context, name;
int complain; tsubst_flags_t complain;
{ {
tree fullname; tree fullname;
...@@ -5653,7 +5656,7 @@ make_typename_type (context, name, complain) ...@@ -5653,7 +5656,7 @@ make_typename_type (context, name, complain)
{ {
/* We can get here from typename_sub0 in the explicit_template_type /* We can get here from typename_sub0 in the explicit_template_type
expansion. Just fail. */ expansion. Just fail. */
if (complain) if (complain & tf_error)
error ("no class template named `%#T' in `%#T'", error ("no class template named `%#T' in `%#T'",
name, context); name, context);
return error_mark_node; return error_mark_node;
...@@ -5669,7 +5672,7 @@ make_typename_type (context, name, complain) ...@@ -5669,7 +5672,7 @@ make_typename_type (context, name, complain)
tmpl = lookup_field (context, name, 0, 0); tmpl = lookup_field (context, name, 0, 0);
if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl)) if (!tmpl || !DECL_CLASS_TEMPLATE_P (tmpl))
{ {
if (complain) if (complain & tf_error)
error ("no class template named `%#T' in `%#T'", error ("no class template named `%#T' in `%#T'",
name, context); name, context);
return error_mark_node; return error_mark_node;
...@@ -5687,14 +5690,18 @@ make_typename_type (context, name, complain) ...@@ -5687,14 +5690,18 @@ make_typename_type (context, name, complain)
if (!IS_AGGR_TYPE (context)) if (!IS_AGGR_TYPE (context))
{ {
if (complain) if (complain & tf_error)
error ("no type named `%#T' in `%#T'", name, context); error ("no type named `%#T' in `%#T'", name, context);
return error_mark_node; return error_mark_node;
} }
t = lookup_field (context, name, 0, 1); t = lookup_field (context, name, 0, 1);
if (t) if (t)
return TREE_TYPE (t); {
if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
t = TREE_TYPE (t);
return t;
}
} }
} }
...@@ -5702,7 +5709,7 @@ make_typename_type (context, name, complain) ...@@ -5702,7 +5709,7 @@ make_typename_type (context, name, complain)
there now or its never going to be. */ there now or its never going to be. */
if (!uses_template_parms (context)) if (!uses_template_parms (context))
{ {
if (complain) if (complain & tf_error)
error ("no type named `%#T' in `%#T'", name, context); error ("no type named `%#T' in `%#T'", name, context);
return error_mark_node; return error_mark_node;
} }
...@@ -5713,7 +5720,9 @@ make_typename_type (context, name, complain) ...@@ -5713,7 +5720,9 @@ make_typename_type (context, name, complain)
/* Resolve `CONTEXT::template NAME'. Returns an appropriate type, /* Resolve `CONTEXT::template NAME'. Returns an appropriate type,
unless an error occurs, in which case error_mark_node is returned. unless an error occurs, in which case error_mark_node is returned.
If COMPLAIN zero, don't complain about any errors that occur. */ If we locate a TYPE_DECL, we return that, rather than the _TYPE it
corresponds to. If COMPLAIN zero, don't complain about any errors
that occur. */
tree tree
make_unbound_class_template (context, name, complain) make_unbound_class_template (context, name, complain)
...@@ -9606,9 +9615,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) ...@@ -9606,9 +9615,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
tree spec; tree spec;
tree type = NULL_TREE; tree type = NULL_TREE;
int longlong = 0; int longlong = 0;
int constp;
int restrictp;
int volatilep;
int type_quals; int type_quals;
int virtualp, explicitp, friendp, inlinep, staticp; int virtualp, explicitp, friendp, inlinep, staticp;
int explicit_int = 0; int explicit_int = 0;
...@@ -10314,26 +10320,24 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) ...@@ -10314,26 +10320,24 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
type = build_complex_type (type); type = build_complex_type (type);
} }
if (sfk == sfk_conversion type_quals = TYPE_UNQUALIFIED;
&& (RIDBIT_SETP (RID_CONST, specbits) if (RIDBIT_SETP (RID_CONST, specbits))
|| RIDBIT_SETP (RID_VOLATILE, specbits) type_quals |= TYPE_QUAL_CONST;
|| RIDBIT_SETP (RID_RESTRICT, specbits))) if (RIDBIT_SETP (RID_VOLATILE, specbits))
type_quals |= TYPE_QUAL_VOLATILE;
if (RIDBIT_SETP (RID_RESTRICT, specbits))
type_quals |= TYPE_QUAL_RESTRICT;
if (sfk == sfk_conversion && type_quals != TYPE_UNQUALIFIED)
error ("qualifiers are not allowed on declaration of `operator %T'", error ("qualifiers are not allowed on declaration of `operator %T'",
ctor_return_type); ctor_return_type);
/* Set CONSTP if this declaration is `const', whether by type_quals |= cp_type_quals (type);
explicit specification or via a typedef. type = cp_build_qualified_type_real
Likewise for VOLATILEP. */ (type, type_quals, ((typedef_decl && !DECL_ARTIFICIAL (typedef_decl)
? tf_ignore_bad_quals : 0) | tf_error | tf_warning));
constp = !! RIDBIT_SETP (RID_CONST, specbits) + CP_TYPE_CONST_P (type); /* We might have ignored or rejected some of the qualifiers. */
restrictp = type_quals = cp_type_quals (type);
!! RIDBIT_SETP (RID_RESTRICT, specbits) + CP_TYPE_RESTRICT_P (type);
volatilep =
!! RIDBIT_SETP (RID_VOLATILE, specbits) + CP_TYPE_VOLATILE_P (type);
type_quals = ((constp ? TYPE_QUAL_CONST : 0)
| (restrictp ? TYPE_QUAL_RESTRICT : 0)
| (volatilep ? TYPE_QUAL_VOLATILE : 0));
type = cp_build_qualified_type (type, type_quals);
staticp = 0; staticp = 0;
inlinep = !! RIDBIT_SETP (RID_INLINE, specbits); inlinep = !! RIDBIT_SETP (RID_INLINE, specbits);
virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits); virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits);
...@@ -10826,21 +10830,30 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) ...@@ -10826,21 +10830,30 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
{ {
register tree typemodlist; register tree typemodlist;
int erred = 0; int erred = 0;
int constp = 0;
int volatilep = 0;
int restrictp = 0;
constp = 0;
volatilep = 0;
restrictp = 0;
for (typemodlist = TREE_TYPE (declarator); typemodlist; for (typemodlist = TREE_TYPE (declarator); typemodlist;
typemodlist = TREE_CHAIN (typemodlist)) typemodlist = TREE_CHAIN (typemodlist))
{ {
tree qualifier = TREE_VALUE (typemodlist); tree qualifier = TREE_VALUE (typemodlist);
if (qualifier == ridpointers[(int) RID_CONST]) if (qualifier == ridpointers[(int) RID_CONST])
{
constp++; constp++;
type_quals |= TYPE_QUAL_CONST;
}
else if (qualifier == ridpointers[(int) RID_VOLATILE]) else if (qualifier == ridpointers[(int) RID_VOLATILE])
{
volatilep++; volatilep++;
type_quals |= TYPE_QUAL_VOLATILE;
}
else if (qualifier == ridpointers[(int) RID_RESTRICT]) else if (qualifier == ridpointers[(int) RID_RESTRICT])
{
restrictp++; restrictp++;
type_quals |= TYPE_QUAL_RESTRICT;
}
else if (!erred) else if (!erred)
{ {
erred = 1; erred = 1;
...@@ -10853,20 +10866,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) ...@@ -10853,20 +10866,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
pedwarn ("duplicate `volatile'"); pedwarn ("duplicate `volatile'");
if (restrictp > 1) if (restrictp > 1)
pedwarn ("duplicate `restrict'"); pedwarn ("duplicate `restrict'");
type_quals = ((constp ? TYPE_QUAL_CONST : 0)
| (restrictp ? TYPE_QUAL_RESTRICT : 0)
| (volatilep ? TYPE_QUAL_VOLATILE : 0));
if (TREE_CODE (declarator) == ADDR_EXPR
&& (constp || volatilep))
{
if (constp)
pedwarn ("discarding `const' applied to a reference");
if (volatilep)
pedwarn ("discarding `volatile' applied to a reference");
type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
}
type = cp_build_qualified_type (type, type_quals); type = cp_build_qualified_type (type, type_quals);
type_quals = cp_type_quals (type);
} }
declarator = TREE_OPERAND (declarator, 0); declarator = TREE_OPERAND (declarator, 0);
ctype = NULL_TREE; ctype = NULL_TREE;
......
...@@ -5219,7 +5219,7 @@ handle_class_head (aggr, scope, id, defn_p, new_type_p) ...@@ -5219,7 +5219,7 @@ handle_class_head (aggr, scope, id, defn_p, new_type_p)
{ {
/* According to the suggested resolution of core issue /* According to the suggested resolution of core issue
180, 'typename' is assumed after a class-key. */ 180, 'typename' is assumed after a class-key. */
decl = make_typename_type (scope, id, 1); decl = make_typename_type (scope, id, tf_error);
if (decl != error_mark_node) if (decl != error_mark_node)
decl = TYPE_MAIN_DECL (decl); decl = TYPE_MAIN_DECL (decl);
else else
......
...@@ -3029,14 +3029,14 @@ nested_name_specifier: ...@@ -3029,14 +3029,14 @@ nested_name_specifier:
{ $$ = $2; } { $$ = $2; }
| nested_name_specifier TEMPLATE explicit_template_type SCOPE | nested_name_specifier TEMPLATE explicit_template_type SCOPE
{ got_scope = $$ { got_scope = $$
= make_typename_type ($1, $3, /*complain=*/1); } = make_typename_type ($1, $3, tf_error); }
/* Error handling per Core 125. */ /* Error handling per Core 125. */
| nested_name_specifier IDENTIFIER SCOPE | nested_name_specifier IDENTIFIER SCOPE
{ got_scope = $$ { got_scope = $$
= make_typename_type ($1, $2, /*complain=*/1); } = make_typename_type ($1, $2, tf_error); }
| nested_name_specifier PTYPENAME SCOPE | nested_name_specifier PTYPENAME SCOPE
{ got_scope = $$ { got_scope = $$
= make_typename_type ($1, $2, /*complain=*/1); } = make_typename_type ($1, $2, tf_error); }
; ;
/* Why the @#$%^& do type_name and notype_identifier need to be expanded /* Why the @#$%^& do type_name and notype_identifier need to be expanded
...@@ -3078,7 +3078,7 @@ typename_sub0: ...@@ -3078,7 +3078,7 @@ typename_sub0:
typename_sub1 identifier %prec EMPTY typename_sub1 identifier %prec EMPTY
{ {
if (TYPE_P ($1)) if (TYPE_P ($1))
$$ = make_typename_type ($1, $2, /*complain=*/1); $$ = make_typename_type ($1, $2, tf_error);
else if (TREE_CODE ($2) == IDENTIFIER_NODE) else if (TREE_CODE ($2) == IDENTIFIER_NODE)
error ("`%T' is not a class or namespace", $2); error ("`%T' is not a class or namespace", $2);
else else
...@@ -3091,9 +3091,9 @@ typename_sub0: ...@@ -3091,9 +3091,9 @@ typename_sub0:
| typename_sub1 template_type %prec EMPTY | typename_sub1 template_type %prec EMPTY
{ $$ = TREE_TYPE ($2); } { $$ = TREE_TYPE ($2); }
| typename_sub1 explicit_template_type %prec EMPTY | typename_sub1 explicit_template_type %prec EMPTY
{ $$ = make_typename_type ($1, $2, /*complain=*/1); } { $$ = make_typename_type ($1, $2, tf_error); }
| typename_sub1 TEMPLATE explicit_template_type %prec EMPTY | typename_sub1 TEMPLATE explicit_template_type %prec EMPTY
{ $$ = make_typename_type ($1, $3, /*complain=*/1); } { $$ = make_typename_type ($1, $3, tf_error); }
; ;
typename_sub1: typename_sub1:
...@@ -3107,7 +3107,7 @@ typename_sub1: ...@@ -3107,7 +3107,7 @@ typename_sub1:
| typename_sub1 typename_sub2 | typename_sub1 typename_sub2
{ {
if (TYPE_P ($1)) if (TYPE_P ($1))
$$ = make_typename_type ($1, $2, /*complain=*/1); $$ = make_typename_type ($1, $2, tf_error);
else if (TREE_CODE ($2) == IDENTIFIER_NODE) else if (TREE_CODE ($2) == IDENTIFIER_NODE)
error ("`%T' is not a class or namespace", $2); error ("`%T' is not a class or namespace", $2);
else else
...@@ -3119,10 +3119,10 @@ typename_sub1: ...@@ -3119,10 +3119,10 @@ typename_sub1:
} }
| typename_sub1 explicit_template_type SCOPE | typename_sub1 explicit_template_type SCOPE
{ got_scope = $$ { got_scope = $$
= make_typename_type ($1, $2, /*complain=*/1); } = make_typename_type ($1, $2, tf_error); }
| typename_sub1 TEMPLATE explicit_template_type SCOPE | typename_sub1 TEMPLATE explicit_template_type SCOPE
{ got_scope = $$ { got_scope = $$
= make_typename_type ($1, $3, /*complain=*/1); } = make_typename_type ($1, $3, tf_error); }
; ;
/* This needs to return a TYPE_DECL for simple names so that we don't /* This needs to return a TYPE_DECL for simple names so that we don't
......
...@@ -3335,8 +3335,6 @@ convert_template_argument (parm, arg, args, complain, i, in_decl) ...@@ -3335,8 +3335,6 @@ convert_template_argument (parm, arg, args, complain, i, in_decl)
arg = make_typename_type (TREE_OPERAND (arg, 0), arg = make_typename_type (TREE_OPERAND (arg, 0),
TREE_OPERAND (arg, 1), TREE_OPERAND (arg, 1),
complain & tf_error); complain & tf_error);
if (TREE_CODE (arg) == TYPE_DECL)
arg = TREE_TYPE (arg);
is_type = 1; is_type = 1;
} }
if (is_type != requires_type) if (is_type != requires_type)
...@@ -6407,7 +6405,7 @@ tsubst (t, args, complain, in_decl) ...@@ -6407,7 +6405,7 @@ tsubst (t, args, complain, in_decl)
my_friendly_assert (TYPE_P (arg), 0); my_friendly_assert (TYPE_P (arg), 0);
return cp_build_qualified_type_real return cp_build_qualified_type_real
(arg, cp_type_quals (arg) | cp_type_quals (t), (arg, cp_type_quals (arg) | cp_type_quals (t),
complain); complain | tf_ignore_bad_quals);
} }
else if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM) else if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
{ {
...@@ -6460,7 +6458,9 @@ tsubst (t, args, complain, in_decl) ...@@ -6460,7 +6458,9 @@ tsubst (t, args, complain, in_decl)
{ {
r = tsubst (TYPE_MAIN_VARIANT (t), args, complain, in_decl); r = tsubst (TYPE_MAIN_VARIANT (t), args, complain, in_decl);
r = cp_build_qualified_type_real r = cp_build_qualified_type_real
(r, cp_type_quals (t), complain); (r, cp_type_quals (t),
complain | (TREE_CODE (t) == TEMPLATE_TYPE_PARM
? tf_ignore_bad_quals : 0));
} }
else else
{ {
...@@ -6785,9 +6785,16 @@ tsubst (t, args, complain, in_decl) ...@@ -6785,9 +6785,16 @@ tsubst (t, args, complain, in_decl)
} }
} }
f = make_typename_type (ctx, f, complain & tf_error); f = make_typename_type (ctx, f,
(complain & tf_error) | tf_keep_type_decl);
if (f == error_mark_node) if (f == error_mark_node)
return f; return f;
if (TREE_CODE (f) == TYPE_DECL)
{
complain |= tf_ignore_bad_quals;
f = TREE_TYPE (f);
}
return cp_build_qualified_type_real return cp_build_qualified_type_real
(f, cp_type_quals (f) | cp_type_quals (t), complain); (f, cp_type_quals (f) | cp_type_quals (t), complain);
} }
...@@ -8463,12 +8470,28 @@ check_cv_quals_for_unify (strict, arg, parm) ...@@ -8463,12 +8470,28 @@ check_cv_quals_for_unify (strict, arg, parm)
tree arg; tree arg;
tree parm; tree parm;
{ {
int arg_quals = cp_type_quals (arg);
int parm_quals = cp_type_quals (parm);
if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM)
{
/* If the cvr quals of parm will not unify with ARG, they'll be
ignored in instantiation, so we have to do the same here. */
if (TREE_CODE (arg) == REFERENCE_TYPE
|| TREE_CODE (arg) == FUNCTION_TYPE
|| TREE_CODE (arg) == METHOD_TYPE)
parm_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
if (!POINTER_TYPE_P (arg) &&
TREE_CODE (arg) != TEMPLATE_TYPE_PARM)
parm_quals &= ~TYPE_QUAL_RESTRICT;
}
if (!(strict & (UNIFY_ALLOW_MORE_CV_QUAL | UNIFY_ALLOW_OUTER_MORE_CV_QUAL)) if (!(strict & (UNIFY_ALLOW_MORE_CV_QUAL | UNIFY_ALLOW_OUTER_MORE_CV_QUAL))
&& !at_least_as_qualified_p (arg, parm)) && (arg_quals & parm_quals) != parm_quals)
return 0; return 0;
if (!(strict & (UNIFY_ALLOW_LESS_CV_QUAL | UNIFY_ALLOW_OUTER_LESS_CV_QUAL)) if (!(strict & (UNIFY_ALLOW_LESS_CV_QUAL | UNIFY_ALLOW_OUTER_LESS_CV_QUAL))
&& !at_least_as_qualified_p (parm, arg)) && (parm_quals & arg_quals) != arg_quals)
return 0; return 0;
return 1; return 1;
...@@ -9930,6 +9953,27 @@ instantiate_decl (d, defer_ok) ...@@ -9930,6 +9953,27 @@ instantiate_decl (d, defer_ok)
import_export_decl (d); import_export_decl (d);
} }
if (!defer_ok)
{
/* Recheck the substitutions to obtain any warning messages
about ignoring cv qualifiers. */
tree gen = DECL_TEMPLATE_RESULT (gen_tmpl);
tree type = TREE_TYPE (gen);
if (TREE_CODE (gen) == FUNCTION_DECL)
{
tsubst (DECL_ARGUMENTS (gen), args, tf_error | tf_warning, d);
tsubst (TYPE_RAISES_EXCEPTIONS (type), args,
tf_error | tf_warning, d);
/* Don't simply tsubst the function type, as that will give
duplicate warnings about poor parameter qualifications.
The function arguments are the same as the decl_arguments
without the top level cv qualifiers. */
type = TREE_TYPE (type);
}
tsubst (type, args, tf_error | tf_warning, d);
}
if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d) if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d)
&& DECL_INITIAL (d) == NULL_TREE) && DECL_INITIAL (d) == NULL_TREE)
/* We should have set up DECL_INITIAL in instantiate_class_template. */ /* We should have set up DECL_INITIAL in instantiate_class_template. */
......
...@@ -506,8 +506,22 @@ build_cplus_array_type (elt_type, index_type) ...@@ -506,8 +506,22 @@ build_cplus_array_type (elt_type, index_type)
/* Make a variant of TYPE, qualified with the TYPE_QUALS. Handles /* Make a variant of TYPE, qualified with the TYPE_QUALS. Handles
arrays correctly. In particular, if TYPE is an array of T's, and arrays correctly. In particular, if TYPE is an array of T's, and
TYPE_QUALS is non-empty, returns an array of qualified T's. TYPE_QUALS is non-empty, returns an array of qualified T's.
Errors are emitted under control of COMPLAIN. If COMPLAIN is zero,
error_mark_node is returned for bad qualifiers. */ FLAGS determines how to deal with illformed qualifications. If
tf_ignore_bad_quals is set, then bad qualifications are dropped
(this is permitted if TYPE was introduced via a typedef or template
type parameter). If bad qualifications are dropped and tf_warning
is set, then a warning is issued for non-const qualifications. If
tf_ignore_bad_quals is not set and tf_error is not set, we
return error_mark_node. Otherwise, we issue an error, and ignore
the qualifications.
Qualification of a reference type is valid when the reference came
via a typedef or template type argument. [dcl.ref] No such
dispensation is provided for qualifying a function type. [dcl.fct]
DR 295 queries this and the proposed resolution brings it into line
with qualifiying a reference. We implement the DR. We also behave
in a similar manner for restricting non-pointer types. */
tree tree
cp_build_qualified_type_real (type, type_quals, complain) cp_build_qualified_type_real (type, type_quals, complain)
...@@ -516,6 +530,7 @@ cp_build_qualified_type_real (type, type_quals, complain) ...@@ -516,6 +530,7 @@ cp_build_qualified_type_real (type, type_quals, complain)
tsubst_flags_t complain; tsubst_flags_t complain;
{ {
tree result; tree result;
int bad_quals = TYPE_UNQUALIFIED;
if (type == error_mark_node) if (type == error_mark_node)
return type; return type;
...@@ -523,32 +538,51 @@ cp_build_qualified_type_real (type, type_quals, complain) ...@@ -523,32 +538,51 @@ cp_build_qualified_type_real (type, type_quals, complain)
if (type_quals == cp_type_quals (type)) if (type_quals == cp_type_quals (type))
return type; return type;
/* A restrict-qualified pointer type must be a pointer (or reference) /* A reference, fucntion or method type shall not be cv qualified.
[dcl.ref], [dct.fct] */
if (type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)
&& (TREE_CODE (type) == REFERENCE_TYPE
|| TREE_CODE (type) == FUNCTION_TYPE
|| TREE_CODE (type) == METHOD_TYPE))
{
bad_quals |= type_quals & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
type_quals &= ~(TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
}
/* A restrict-qualified type must be a pointer (or reference)
to object or incomplete type. */ to object or incomplete type. */
if ((type_quals & TYPE_QUAL_RESTRICT) if ((type_quals & TYPE_QUAL_RESTRICT)
&& TREE_CODE (type) != TEMPLATE_TYPE_PARM && TREE_CODE (type) != TEMPLATE_TYPE_PARM
&& (!POINTER_TYPE_P (type) && TREE_CODE (type) != TYPENAME_TYPE
|| TYPE_PTRMEM_P (type) && !POINTER_TYPE_P (type))
|| TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE))
{ {
if (complain & tf_error) bad_quals |= TYPE_QUAL_RESTRICT;
error ("`%T' cannot be `restrict'-qualified", type);
else
return error_mark_node;
type_quals &= ~TYPE_QUAL_RESTRICT; type_quals &= ~TYPE_QUAL_RESTRICT;
} }
if (type_quals != TYPE_UNQUALIFIED if (bad_quals == TYPE_UNQUALIFIED)
&& TREE_CODE (type) == FUNCTION_TYPE) /*OK*/;
{ else if (!(complain & (tf_error | tf_ignore_bad_quals)))
if (complain & tf_error)
error ("`%T' cannot be `const'-, `volatile'-, or `restrict'-qualified", type);
else
return error_mark_node; return error_mark_node;
type_quals = TYPE_UNQUALIFIED; else
{
if (complain & tf_ignore_bad_quals)
/* We're not going to warn about constifying things that can't
be constified. */
bad_quals &= ~TYPE_QUAL_CONST;
if (bad_quals)
{
tree bad_type = build_qualified_type (ptr_type_node, bad_quals);
if (!(complain & tf_ignore_bad_quals))
error ("`%V' qualifiers cannot be applied to `%T'",
bad_type, type);
else if (complain & tf_warning)
warning ("ignoring `%V' qualifiers on `%T'", bad_type, type);
}
} }
else if (TREE_CODE (type) == ARRAY_TYPE)
if (TREE_CODE (type) == ARRAY_TYPE)
{ {
/* In C++, the qualification really applies to the array element /* In C++, the qualification really applies to the array element
type. Obtain the appropriately qualified element type. */ type. Obtain the appropriately qualified element type. */
...@@ -590,7 +624,7 @@ cp_build_qualified_type_real (type, type_quals, complain) ...@@ -590,7 +624,7 @@ cp_build_qualified_type_real (type, type_quals, complain)
{ {
/* For a pointer-to-member type, we can't just return a /* For a pointer-to-member type, we can't just return a
cv-qualified version of the RECORD_TYPE. If we do, we cv-qualified version of the RECORD_TYPE. If we do, we
haven't change the field that contains the actual pointer to haven't changed the field that contains the actual pointer to
a method, and so TYPE_PTRMEMFUNC_FN_TYPE will be wrong. */ a method, and so TYPE_PTRMEMFUNC_FN_TYPE will be wrong. */
tree t; tree t;
......
2002-02-22 Nathan Sidwell <nathan@codesourcery.com>
* g++.dg/template/qualttp19.C: New test.
* g++.dg/template/qualttp20.C: New test.
* g++.old-deja/g++.jason/report.C: Adjust expected errors
* g++.old-deja/g++.other/qual1.C: Likewise.
2002-02-21 Aldy Hernandez <aldyh@redhat.com> 2002-02-21 Aldy Hernandez <aldyh@redhat.com>
* gcc.dg/attr-alwaysinline.c: New. * gcc.dg/attr-alwaysinline.c: New.
......
// { dg-do compile }
// Copyright (C) 2001 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 15 Dec 2001 <nathan@codesourcery.com>
// PR 2645
template <typename T>
struct call_traits
{
public:
typedef T type_less_spec;
};
template <typename T>
struct call_traits<T&>
{
typedef T type_more_spec;
};
int main()
{
int num;
// Two typedefs lead to the instant. of the less spec. ("wrong") template
typedef int& r_type;
typedef const r_type cr_type;
call_traits<cr_type>::type_less_spec var = num; // { dg-error "" "" }
// The explicit type leads to the instantiation of the "correct" one
call_traits<const int&>::type_more_spec var2 = num;
// As happen with a single typedef!
typedef const int& std_cr_type;
call_traits<std_cr_type>::type_more_spec var3 = num;
// As happen, indeed, without the cv-qualifier
call_traits<r_type>::type_more_spec var4;
}
// { dg-do compile }
// Copyright (C) 2001 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 15 Dec 2001 <nathan@codesourcery.com>
// PR 2645
struct AS
{
typedef void (myT) ();
struct L {};
};
template <typename T> struct B1 : T
{
typedef typename T::L __restrict__ r;// { dg-error "`__restrict' qualifiers cannot" "" }
typedef typename T::myT __restrict__ p;// { dg-warning "ignoring `__restrict'" "" }
typedef typename T::myT volatile *myvolatile; // { dg-warning "ignoring `volatile'" "" }
typename T::myT volatile *a; // { dg-warning "ignoring `volatile'" "" }
myvolatile b; // { dg-bogus "ignoring `volatile'" "" { xfail *-*-* } }
};
template <typename T> struct B2 : T
{
typedef typename T::myT const *myconst;
typename T::myT const *a;
myconst b;
};
B1<AS> b1; // { dg-error "instantiated" "" }
B2<AS> b2;
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// GROUPS passed error-reporting // GROUPS passed error-reporting
// Special g++ Options: -Wreturn-type // Special g++ Options: -Wreturn-type
// DR 295 allows qualification via typedef
template <char C> template <char C>
class badoo class badoo
{ {
...@@ -44,7 +46,8 @@ class X{ ...@@ -44,7 +46,8 @@ class X{
}; };
typedef int const * bart (); typedef int const * bart ();
typedef bart const * const * bar2; // ERROR - qualifiers typedef bart const * const * bar2; // ok - constifying qualifiers
typedef bart volatile * const * bar2v; // WARNING - qualifiers
bar2 baz (X::Y y) bar2 baz (X::Y y)
{ // ERROR - in this context { // ERROR - in this context
......
...@@ -2,13 +2,16 @@ ...@@ -2,13 +2,16 @@
// Origin: Benjamin Pflugmann <philemon@spin.de> // Origin: Benjamin Pflugmann <philemon@spin.de>
// Special g++ Options: -O // Special g++ Options: -O
// DR 295 allows qualification via typedef
typedef const char *(func_type)(); typedef const char *(func_type)();
class class
{ {
public: public:
func_type *Function; func_type *Function;
const func_type* function(void) { return Function; } // ERROR - qualifiers const func_type* function(void) { return Function; } // ok constifying
volatile func_type* functionv(void); // WARNING - qualifier
} action; } action;
void work(const char *source) void work(const char *source)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment