This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: PRs 19787, 19732, 19762, 19862, 19739
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 9 Feb 2005 16:39:08 -0800
- Subject: C++ PATCH: PRs 19787, 19732, 19762, 19862, 19739
- Reply-to: mark at codesourcery dot com
This patch fixes a handful of regressions:
* 19787 -- An ice-on-invalid where we were failing to check for
error_mark_node.
* 19732 -- We were failing to check for various incorrect uses of
destructor names to declare things that are not destructors.
* 19762 -- When encountering invalid destructor names, we crashed.
(In general it's bad to create expressions that have an
error_mark_node ntested in them somewhere; much better if the entire
expression collapses to the error_mark_node.)
* 19826 -- A rejects-valid for uses of type-dependent expressions as
array bounds in templates.
* 19739 -- An ice-on-valid for an obscure use of empty attribute
lists.
Tested on x86_64-unknown-linux-gnu, applied on the mainline. Those
PRs that are 3.4 regressions will also go there, as soon as tests
complete.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
2005-02-09 Mark Mitchell <mark@codesourcery.com>
PR c++/19787
* call.c (initialize_reference): Robustify.
PR ++/19732
* decl.c (grokdeclarator): Check for invalid use of destructor
names.
PR c++/19762
* parser.c (cp_parser_unqualified_id): Avoid creating destructor
names with invalid types.
PR c++/19826
* parser.c (cp_parser_direct_declarator): Allow type-dependent
expressions as array bounds.
PR c++/19739
* parser.c (cp_parser_attributes_list): Allow empty lists.
2005-02-09 Mark Mitchell <mark@codesourcery.com>
PR c++/19787
* g++.dg/conversion/ambig1.C: New test.
PR c++/19739
* g++.dg/ext/attrib19.C: New test.
PR c++/19732
* g++.dg/parse/dtor5.C: New test.
PR c++/19762
* g++.dg/template/dtor3.C: New test.
PR c++/19826
* g++.dg/template/static11.C: New test.
* g++.dg/template/crash2.C: Remove dg-error marker.
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.528
diff -c -5 -p -r1.528 call.c
*** cp/call.c 31 Jan 2005 01:16:53 -0000 1.528
--- cp/call.c 10 Feb 2005 00:26:04 -0000
*************** initialize_reference (tree type, tree ex
*** 6532,6616 ****
expr = convert_like_real (conv, expr,
/*fn=*/NULL_TREE, /*argnum=*/0,
/*inner=*/-1,
/*issue_conversion_warnings=*/true,
/*c_cast_p=*/false);
! if (!real_lvalue_p (expr))
{
! tree init;
! tree type;
!
! /* Create the temporary variable. */
! type = TREE_TYPE (expr);
! var = make_temporary_var_for_ref_to_temp (decl, type);
! layout_decl (var, 0);
! /* If the rvalue is the result of a function call it will be
! a TARGET_EXPR. If it is some other construct (such as a
! member access expression where the underlying object is
! itself the result of a function call), turn it into a
! TARGET_EXPR here. It is important that EXPR be a
! TARGET_EXPR below since otherwise the INIT_EXPR will
! attempt to make a bitwise copy of EXPR to initialize
! VAR. */
! if (TREE_CODE (expr) != TARGET_EXPR)
! expr = get_target_expr (expr);
! /* Create the INIT_EXPR that will initialize the temporary
! variable. */
! init = build2 (INIT_EXPR, type, var, expr);
! if (at_function_scope_p ())
{
! add_decl_expr (var);
! *cleanup = cxx_maybe_build_cleanup (var);
! /* We must be careful to destroy the temporary only
! after its initialization has taken place. If the
! initialization throws an exception, then the
! destructor should not be run. We cannot simply
! transform INIT into something like:
!
! (INIT, ({ CLEANUP_STMT; }))
!
! because emit_local_var always treats the
! initializer as a full-expression. Thus, the
! destructor would run too early; it would run at the
! end of initializing the reference variable, rather
! than at the end of the block enclosing the
! reference variable.
!
! The solution is to pass back a cleanup expression
! which the caller is responsible for attaching to
! the statement tree. */
}
else
! {
! rest_of_decl_compilation (var, /*toplev=*/1, at_eof);
! if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
! static_aggregates = tree_cons (NULL_TREE, var,
! static_aggregates);
! }
! /* Use its address to initialize the reference variable. */
! expr = build_address (var);
if (base_conv_type)
! expr = convert_to_base (expr,
! build_pointer_type (base_conv_type),
! /*check_access=*/true,
! /*nonnull=*/true);
! expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
}
- else
- /* Take the address of EXPR. */
- expr = build_unary_op (ADDR_EXPR, expr, 0);
- /* If a BASE_CONV was required, perform it now. */
- if (base_conv_type)
- expr = (perform_implicit_conversion
- (build_pointer_type (base_conv_type), expr));
- expr = build_nop (type, expr);
}
else
/* Perform the conversion. */
expr = convert_like (conv, expr);
!
/* Free all the conversions we allocated. */
obstack_free (&conversion_obstack, p);
return expr;
}
--- 6532,6621 ----
expr = convert_like_real (conv, expr,
/*fn=*/NULL_TREE, /*argnum=*/0,
/*inner=*/-1,
/*issue_conversion_warnings=*/true,
/*c_cast_p=*/false);
! if (error_operand_p (expr))
! expr = error_mark_node;
! else
{
! if (!real_lvalue_p (expr))
{
! tree init;
! tree type;
! /* Create the temporary variable. */
! type = TREE_TYPE (expr);
! var = make_temporary_var_for_ref_to_temp (decl, type);
! layout_decl (var, 0);
! /* If the rvalue is the result of a function call it will be
! a TARGET_EXPR. If it is some other construct (such as a
! member access expression where the underlying object is
! itself the result of a function call), turn it into a
! TARGET_EXPR here. It is important that EXPR be a
! TARGET_EXPR below since otherwise the INIT_EXPR will
! attempt to make a bitwise copy of EXPR to initialize
! VAR. */
! if (TREE_CODE (expr) != TARGET_EXPR)
! expr = get_target_expr (expr);
! /* Create the INIT_EXPR that will initialize the temporary
! variable. */
! init = build2 (INIT_EXPR, type, var, expr);
! if (at_function_scope_p ())
! {
! add_decl_expr (var);
! *cleanup = cxx_maybe_build_cleanup (var);
!
! /* We must be careful to destroy the temporary only
! after its initialization has taken place. If the
! initialization throws an exception, then the
! destructor should not be run. We cannot simply
! transform INIT into something like:
!
! (INIT, ({ CLEANUP_STMT; }))
!
! because emit_local_var always treats the
! initializer as a full-expression. Thus, the
! destructor would run too early; it would run at the
! end of initializing the reference variable, rather
! than at the end of the block enclosing the
! reference variable.
!
! The solution is to pass back a cleanup expression
! which the caller is responsible for attaching to
! the statement tree. */
! }
! else
! {
! rest_of_decl_compilation (var, /*toplev=*/1, at_eof);
! if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
! static_aggregates = tree_cons (NULL_TREE, var,
! static_aggregates);
! }
! /* Use its address to initialize the reference variable. */
! expr = build_address (var);
! if (base_conv_type)
! expr = convert_to_base (expr,
! build_pointer_type (base_conv_type),
! /*check_access=*/true,
! /*nonnull=*/true);
! expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
}
else
! /* Take the address of EXPR. */
! expr = build_unary_op (ADDR_EXPR, expr, 0);
! /* If a BASE_CONV was required, perform it now. */
if (base_conv_type)
! expr = (perform_implicit_conversion
! (build_pointer_type (base_conv_type), expr));
! expr = build_nop (type, expr);
}
}
else
/* Perform the conversion. */
expr = convert_like (conv, expr);
!
/* Free all the conversions we allocated. */
obstack_free (&conversion_obstack, p);
return expr;
}
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1360
diff -c -5 -p -r1.1360 decl.c
*** cp/decl.c 9 Feb 2005 02:53:37 -0000 1.1360
--- cp/decl.c 10 Feb 2005 00:26:04 -0000
*************** grokdeclarator (const cp_declarator *dec
*** 6551,6563 ****
return error_mark_node;
switch (TREE_CODE (decl))
{
case BIT_NOT_EXPR:
{
! tree type = TREE_OPERAND (decl, 0);
! type = constructor_name (type);
! name = IDENTIFIER_POINTER (type);
}
break;
case TEMPLATE_ID_EXPR:
{
--- 6551,6576 ----
return error_mark_node;
switch (TREE_CODE (decl))
{
case BIT_NOT_EXPR:
{
! tree type;
!
! if (innermost_code != cdk_function)
! {
! error ("declaration of %qD as non-function", decl);
! return error_mark_node;
! }
! else if (!qualifying_scope
! && !(current_class_type && at_class_scope_p ()))
! {
! error ("declaration of %qD as non-member", decl);
! return error_mark_node;
! }
!
! type = TREE_OPERAND (decl, 0);
! name = IDENTIFIER_POINTER (constructor_name (type));
}
break;
case TEMPLATE_ID_EXPR:
{
*************** grokdeclarator (const cp_declarator *dec
*** 7801,7819 ****
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
int publicp = 0;
tree function_context;
- /* We catch the others as conflicts with the builtin
- typedefs. */
- if (friendp && unqualified_id == ridpointers[(int) RID_SIGNED])
- {
- error ("function %qD cannot be declared friend",
- unqualified_id);
- friendp = 0;
- }
-
if (friendp == 0)
{
if (ctype == NULL_TREE)
ctype = current_class_type;
--- 7814,7823 ----
*************** grokdeclarator (const cp_declarator *dec
*** 7847,7856 ****
--- 7851,7872 ----
type = build_method_type_directly (ctype,
TREE_TYPE (type),
TYPE_ARG_TYPES (type));
}
+ /* Check that the name used for a destructor makes sense. */
+ if (sfk == sfk_destructor
+ && !same_type_p (TREE_OPERAND
+ (id_declarator->u.id.unqualified_name, 0),
+ ctype))
+ {
+ error ("declaration of %qD as member of %qT",
+ id_declarator->u.id.unqualified_name,
+ ctype);
+ return error_mark_node;
+ }
+
/* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */
function_context = (ctype != NULL_TREE) ?
decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
publicp = (! friendp || ! staticp)
&& function_context == NULL_TREE;
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.313
diff -c -5 -p -r1.313 parser.c
*** cp/parser.c 9 Feb 2005 02:53:38 -0000 1.313
--- cp/parser.c 10 Feb 2005 00:26:06 -0000
*************** cp_parser_unqualified_id (cp_parser* par
*** 3171,3180 ****
--- 3171,3181 ----
{
tree type_decl;
tree qualifying_scope;
tree object_scope;
tree scope;
+ bool done;
/* Consume the `~' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the class-name. The standard, as written, seems to
say that:
*************** cp_parser_unqualified_id (cp_parser* par
*** 3227,3236 ****
--- 3228,3238 ----
return build_nt (BIT_NOT_EXPR, scope);
}
/* If there was an explicit qualification (S::~T), first look
in the scope given by the qualification (i.e., S). */
+ done = false;
if (scope)
{
cp_parser_parse_tentatively (parser);
type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
*************** cp_parser_unqualified_id (cp_parser* par
*** 3238,3251 ****
none_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
! return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
/* In "N::S::~S", look in "N" as well. */
! if (scope && qualifying_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = qualifying_scope;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
--- 3240,3253 ----
none_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
! done = true;
}
/* In "N::S::~S", look in "N" as well. */
! if (!done && scope && qualifying_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = qualifying_scope;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
*************** cp_parser_unqualified_id (cp_parser* par
*** 3256,3269 ****
none_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
! return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
/* In "p->S::~T", look in the scope given by "*p" as well. */
! else if (object_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = object_scope;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
--- 3258,3271 ----
none_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
! done = true;
}
/* In "p->S::~T", look in the scope given by "*p" as well. */
! else if (!done && object_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = object_scope;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
*************** cp_parser_unqualified_id (cp_parser* par
*** 3274,3297 ****
none_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
! return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
/* Look in the surrounding context. */
! parser->scope = NULL_TREE;
! parser->object_scope = NULL_TREE;
! parser->qualifying_scope = NULL_TREE;
! type_decl
! = cp_parser_class_name (parser,
! /*typename_keyword_p=*/false,
! /*template_keyword_p=*/false,
! none_type,
! /*check_dependency=*/false,
! /*class_head_p=*/false,
! declarator_p);
/* If an error occurred, assume that the name of the
destructor is the same as the name of the qualifying
class. That allows us to keep parsing after running
into ill-formed destructor names. */
if (type_decl == error_mark_node && scope && TYPE_P (scope))
--- 3276,3302 ----
none_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
! done = true;
}
/* Look in the surrounding context. */
! if (!done)
! {
! parser->scope = NULL_TREE;
! parser->object_scope = NULL_TREE;
! parser->qualifying_scope = NULL_TREE;
! type_decl
! = cp_parser_class_name (parser,
! /*typename_keyword_p=*/false,
! /*template_keyword_p=*/false,
! none_type,
! /*check_dependency=*/false,
! /*class_head_p=*/false,
! declarator_p);
! }
/* If an error occurred, assume that the name of the
destructor is the same as the name of the qualifying
class. That allows us to keep parsing after running
into ill-formed destructor names. */
if (type_decl == error_mark_node && scope && TYPE_P (scope))
*************** cp_parser_direct_declarator (cp_parser*
*** 11097,11107 ****
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/true,
&non_constant_p);
if (!non_constant_p)
bounds = fold_non_dependent_expr (bounds);
! else if (!at_function_scope_p ())
{
error ("array bound is not an integer constant");
bounds = error_mark_node;
}
}
--- 11102,11122 ----
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/true,
&non_constant_p);
if (!non_constant_p)
bounds = fold_non_dependent_expr (bounds);
! /* Normally, the array bound must be an integral constant
! expression. However, as an extension, we allow VLAs
! in function scopes. And, we allow type-dependent
! expressions in templates; sometimes we don't know for
! sure whether or not something is a valid integral
! constant expression until instantiation time. (It
! doesn't make sense to check for value-dependency, as
! an expression is only value-dependent when it is a
! constant expression.) */
! else if (!type_dependent_expression_p (bounds)
! && !at_function_scope_p ())
{
error ("array bound is not an integer constant");
bounds = error_mark_node;
}
}
*************** cp_parser_attributes_opt (cp_parser* par
*** 14040,14053 ****
identifier
identifier ( identifier )
identifier ( identifier , expression-list )
identifier ( expression-list )
! Returns a TREE_LIST. Each node corresponds to an attribute. THe
! TREE_PURPOSE of each node is the identifier indicating which
! attribute is in use. The TREE_VALUE represents the arguments, if
! any. */
static tree
cp_parser_attribute_list (cp_parser* parser)
{
tree attribute_list = NULL_TREE;
--- 14055,14068 ----
identifier
identifier ( identifier )
identifier ( identifier , expression-list )
identifier ( expression-list )
! Returns a TREE_LIST, or NULL_TREE on error. Each node corresponds
! to an attribute. The TREE_PURPOSE of each node is the identifier
! indicating which attribute is in use. The TREE_VALUE represents
! the arguments, if any. */
static tree
cp_parser_attribute_list (cp_parser* parser)
{
tree attribute_list = NULL_TREE;
*************** cp_parser_attribute_list (cp_parser* par
*** 14061,14101 ****
tree attribute;
/* Look for the identifier. We also allow keywords here; for
example `__attribute__ ((const))' is legal. */
token = cp_lexer_peek_token (parser->lexer);
! if (token->type != CPP_NAME
! && token->type != CPP_KEYWORD)
! return error_mark_node;
! /* Consume the token. */
! token = cp_lexer_consume_token (parser->lexer);
! /* Save away the identifier that indicates which attribute this is. */
! identifier = token->value;
! attribute = build_tree_list (identifier, NULL_TREE);
! /* Peek at the next token. */
! token = cp_lexer_peek_token (parser->lexer);
! /* If it's an `(', then parse the attribute arguments. */
! if (token->type == CPP_OPEN_PAREN)
! {
! tree arguments;
! arguments = (cp_parser_parenthesized_expression_list
! (parser, true, /*cast_p=*/false,
! /*non_constant_p=*/NULL));
! /* Save the identifier and arguments away. */
! TREE_VALUE (attribute) = arguments;
! }
! /* Add this attribute to the list. */
! TREE_CHAIN (attribute) = attribute_list;
! attribute_list = attribute;
! /* Now, look for more attributes. */
! token = cp_lexer_peek_token (parser->lexer);
! /* If the next token isn't a `,', we're done. */
if (token->type != CPP_COMMA)
break;
/* Consume the comma and keep going. */
cp_lexer_consume_token (parser->lexer);
--- 14076,14118 ----
tree attribute;
/* Look for the identifier. We also allow keywords here; for
example `__attribute__ ((const))' is legal. */
token = cp_lexer_peek_token (parser->lexer);
! if (token->type == CPP_NAME
! || token->type == CPP_KEYWORD)
! {
! /* Consume the token. */
! token = cp_lexer_consume_token (parser->lexer);
! /* Save away the identifier that indicates which attribute
! this is. */
! identifier = token->value;
! attribute = build_tree_list (identifier, NULL_TREE);
! /* Peek at the next token. */
! token = cp_lexer_peek_token (parser->lexer);
! /* If it's an `(', then parse the attribute arguments. */
! if (token->type == CPP_OPEN_PAREN)
! {
! tree arguments;
! arguments = (cp_parser_parenthesized_expression_list
! (parser, true, /*cast_p=*/false,
! /*non_constant_p=*/NULL));
! /* Save the identifier and arguments away. */
! TREE_VALUE (attribute) = arguments;
! }
! /* Add this attribute to the list. */
! TREE_CHAIN (attribute) = attribute_list;
! attribute_list = attribute;
! token = cp_lexer_peek_token (parser->lexer);
! }
! /* Now, look for more attributes. If the next token isn't a
! `,', we're done. */
if (token->type != CPP_COMMA)
break;
/* Consume the comma and keep going. */
cp_lexer_consume_token (parser->lexer);
Index: testsuite/ChangeLog
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/ChangeLog,v
retrieving revision 1.5005
diff -c -5 -p -r1.5005 ChangeLog
*** testsuite/ChangeLog 9 Feb 2005 02:53:21 -0000 1.5005
--- testsuite/ChangeLog 10 Feb 2005 00:26:20 -0000
***************
*** 1,5 ****
--- 1,23 ----
+ 2005-02-09 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/19787
+ * g++.dg/conversion/ambig1.C: New test.
+
+ PR c++/19739
+ * g++.dg/ext/attrib19.C: New test.
+
+ PR c++/19732
+ * g++.dg/parse/dtor5.C: New test.
+
+ PR c++/19762
+ * g++.dg/template/dtor3.C: New test.
+
+ PR c++/19826
+ * g++.dg/template/static11.C: New test.
+ * g++.dg/template/crash2.C: Remove dg-error marker.
+
2005-02-08 Mark Mitchell <mark@codesourcery.com>
PR c++/19733
* g++.dg/parse/crash23.C: New test.
* g++.dg/warn/Weff1.C: New test.
Index: testsuite/g++.dg/conversion/ambig1.C
===================================================================
RCS file: testsuite/g++.dg/conversion/ambig1.C
diff -N testsuite/g++.dg/conversion/ambig1.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/conversion/ambig1.C 10 Feb 2005 00:26:46 -0000
***************
*** 0 ****
--- 1,8 ----
+ // PR c++/19787
+
+ struct H {
+ operator char(); // { dg-error "" }
+ operator short(); // { dg-error "" }
+ };
+
+ int const& ref = H(); // { dg-error "" }
Index: testsuite/g++.dg/ext/attrib19.C
===================================================================
RCS file: testsuite/g++.dg/ext/attrib19.C
diff -N testsuite/g++.dg/ext/attrib19.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/ext/attrib19.C 10 Feb 2005 00:26:46 -0000
***************
*** 0 ****
--- 1,10 ----
+ // PR c++/19739
+
+ void Dummy() __attribute__(( , ));
+ void Dummy() {}
+
+ int main (int argc, char **argv)
+ {
+ Dummy();
+ return 0;
+ }
Index: testsuite/g++.dg/parse/dtor5.C
===================================================================
RCS file: testsuite/g++.dg/parse/dtor5.C
diff -N testsuite/g++.dg/parse/dtor5.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/dtor5.C 10 Feb 2005 00:27:03 -0000
***************
*** 0 ****
--- 1,12 ----
+ // PR c++/19732
+
+ struct A;
+ typedef int ~A; // { dg-error "non-function" }
+ struct B {
+ ~A(); // { dg-error "" }
+ typedef int ~A; // { dg-error "non-function" }
+ void f() {
+ extern ~B(); // { dg-error "non-member" }
+ }
+ };
+ void ~A(); // { dg-error "non-member" }
Index: testsuite/g++.dg/template/crash2.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/template/crash2.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 crash2.C
*** testsuite/g++.dg/template/crash2.C 12 Nov 2004 21:47:13 -0000 1.3
--- testsuite/g++.dg/template/crash2.C 10 Feb 2005 00:27:03 -0000
***************
*** 3,13 ****
template <class EnumType>
class A
{
public:
static const EnumType size = max; // { dg-error "" }
! int table[size]; // { dg-error "" }
};
template <class EnumType>
const EnumType A<EnumType>::size;
--- 3,13 ----
template <class EnumType>
class A
{
public:
static const EnumType size = max; // { dg-error "" }
! int table[size];
};
template <class EnumType>
const EnumType A<EnumType>::size;
Index: testsuite/g++.dg/template/dtor3.C
===================================================================
RCS file: testsuite/g++.dg/template/dtor3.C
diff -N testsuite/g++.dg/template/dtor3.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/dtor3.C 10 Feb 2005 00:27:03 -0000
***************
*** 0 ****
--- 1,4 ----
+ // PR c++/19762
+
+ template<int> struct A { ~A(){} }; // { dg-error "" }
+ template A<>::~A(); // { dg-error "" }
Index: testsuite/g++.dg/template/static11.C
===================================================================
RCS file: testsuite/g++.dg/template/static11.C
diff -N testsuite/g++.dg/template/static11.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/static11.C 10 Feb 2005 00:27:03 -0000
***************
*** 0 ****
--- 1,8 ----
+ // PR c++/19826
+
+ template<typename T> struct A
+ {
+ static const T i = 1;
+ char a[i];
+ };
+