aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMark Mitchell <mark@markmitchell.com>1998-11-06 16:50:46 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1998-11-06 16:50:46 +0000
commit6ba89f8ecba5e27e4c847308cceaec857aaaa5cc (patch)
tree807068e3e7b12507ad2145dae78b50605cfdb525 /gcc
parent955fc2e7df0f443cbf538a0ad2991e352f8ab1f6 (diff)
downloadgcc-6ba89f8ecba5e27e4c847308cceaec857aaaa5cc.zip
gcc-6ba89f8ecba5e27e4c847308cceaec857aaaa5cc.tar.gz
gcc-6ba89f8ecba5e27e4c847308cceaec857aaaa5cc.tar.bz2
cp-tree.h (lang_decl_flags): Add defined_in_class.
* cp-tree.h (lang_decl_flags): Add defined_in_class. Decrease size of dummy. (DECL_DEFINED_IN_CLASS_P): New macro. (TEMPLATE_PARMS_FOR_INLINE): Document. (check_static_variable_definition): New function. * decl.c (cp_finish_decl): Set DECL_DEFINED_IN_CLASS_P, if appropriate. (check_static_variable_definition): Split out from ... (grokdeclarator): Here. * pt.c (check_default_tmpl_args): New function, split out from ... (push_template_decl_real): Here. (instantiate_template): Fix comment. From-SVN: r23549
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog15
-rw-r--r--gcc/cp/cp-tree.h12
-rw-r--r--gcc/cp/decl.c77
-rw-r--r--gcc/cp/pt.c178
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/defarg6.C27
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/defarg7.C11
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/static5.C9
7 files changed, 243 insertions, 86 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 9bc821c..ef4908f 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,18 @@
+1998-11-06 Mark Mitchell <mark@markmitchell.com>
+
+ * cp-tree.h (lang_decl_flags): Add defined_in_class. Decrease
+ size of dummy.
+ (DECL_DEFINED_IN_CLASS_P): New macro.
+ (TEMPLATE_PARMS_FOR_INLINE): Document.
+ (check_static_variable_definition): New function.
+ * decl.c (cp_finish_decl): Set DECL_DEFINED_IN_CLASS_P, if
+ appropriate.
+ (check_static_variable_definition): Split out from ...
+ (grokdeclarator): Here.
+ * pt.c (check_default_tmpl_args): New function, split out from ...
+ (push_template_decl_real): Here.
+ (instantiate_template): Fix comment.
+
1998-11-04 Mark Mitchell <mark@markmitchell.com>
* cp-tree.h (CP_TYPE_CONST_P): Make {0,1}-valued.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e55766f..d502f93 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1095,7 +1095,8 @@ struct lang_decl_flags
unsigned comdat : 1;
unsigned needs_final_overrider : 1;
unsigned bitfield : 1;
- unsigned dummy : 2;
+ unsigned defined_in_class : 1;
+ unsigned dummy : 1;
tree access;
tree context;
@@ -1165,6 +1166,11 @@ struct lang_decl
should be allocated. */
#define DECL_IN_AGGR_P(NODE) (DECL_LANG_FLAG_3(NODE))
+/* Nonzero if the DECL was defined in the class definition itself,
+ rather than outside the class. */
+#define DECL_DEFINED_IN_CLASS_P(DECL) \
+ (DECL_LANG_SPECIFIC (DECL)->decl_flags.defined_in_class)
+
/* Nonzero for FUNCTION_DECL means that this decl is just a
friend declaration, and should not be added to the list of
member functions for this class. */
@@ -1357,6 +1363,9 @@ struct lang_decl
#define INNERMOST_TEMPLATE_PARMS(NODE) TREE_VALUE(NODE)
+/* Nonzero if the NODE corresponds to the template parameters for a
+ member template, whose inline definition is being processed after
+ the class definition is complete. */
#define TEMPLATE_PARMS_FOR_INLINE(NODE) TREE_LANG_FLAG_1 (NODE)
#define DECL_SAVED_TREE(NODE) DECL_MEMFUNC_POINTER_TO (NODE)
@@ -2682,6 +2691,7 @@ extern void print_other_binding_stack PROTO((struct binding_level *));
extern void revert_static_member_fn PROTO((tree*, tree*, tree*));
extern void cat_namespace_levels PROTO((void));
extern void fixup_anonymous_union PROTO((tree));
+extern int check_static_variable_definition PROTO((tree, tree));
/* in decl2.c */
extern int check_java_method PROTO((tree));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 394984f..6ed993e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -7071,6 +7071,12 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
init = NULL_TREE;
}
+ if (current_class_type
+ && DECL_REAL_CONTEXT (decl) == current_class_type
+ && TYPE_BEING_DEFINED (current_class_type)
+ && (DECL_INITIAL (decl) || init))
+ DECL_DEFINED_IN_CLASS_P (decl) = 1;
+
if (TREE_CODE (decl) == VAR_DECL
&& DECL_CONTEXT (decl)
&& TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL
@@ -8493,6 +8499,41 @@ build_ptrmemfunc_type (type)
enum return_types { return_normal, return_ctor, return_dtor, return_conversion };
+/* DECL is a VAR_DECL defined in-class, whose TYPE is also given.
+ Check to see that the definition is valid. Issue appropriate error
+ messages. Return 1 if the definition is particularly bad, or 0
+ otherwise. */
+
+int
+check_static_variable_definition (decl, type)
+ tree decl;
+ tree type;
+{
+ /* Motion 10 at San Diego: If a static const integral data member is
+ initialized with an integral constant expression, the initializer
+ may appear either in the declaration (within the class), or in
+ the definition, but not both. If it appears in the class, the
+ member is a member constant. The file-scope definition is always
+ required. */
+ if (CLASS_TYPE_P (type) || TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ cp_error ("in-class initialization of static data member of non-integral type `%T'",
+ type);
+ /* If we just return the declaration, crashes will sometimes
+ occur. We therefore return void_type_node, as if this was a
+ friend declaration, to cause callers to completely ignore
+ this declaration. */
+ return 1;
+ }
+ else if (!CP_TYPE_CONST_P (type))
+ cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
+ decl);
+ else if (pedantic && !INTEGRAL_TYPE_P (type))
+ cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", decl, type);
+
+ return 0;
+}
+
tree
grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
tree declspecs;
@@ -10660,31 +10701,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
staticp = 1;
}
- /* Motion 10 at San Diego: If a static const integral data
- member is initialized with an integral constant
- expression, the initializer may appear either in the
- declaration (within the class), or in the definition,
- but not both. If it appears in the class, the member is
- a member constant. The file-scope definition is always
- required. */
- if (CLASS_TYPE_P (type)
- || TREE_CODE (type) == REFERENCE_TYPE)
- {
- cp_error ("in-class initialization of static data member of non-integral type `%T'",
- type);
- /* If we just return the declaration, crashes will
- sometimes occur. We therefore return
- void_type_node, as if this was a friend
- declaration, to cause callers to completely
- ignore this declaration. */
- return void_type_node;
- }
- else if (!(type_quals & TYPE_QUAL_CONST))
- cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
- declarator);
- else if (pedantic && ! INTEGRAL_TYPE_P (type)
- && !uses_template_parms (type))
- cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", declarator, type);
+ if (uses_template_parms (type))
+ /* We'll check at instantiation time. */
+ ;
+ else if (check_static_variable_definition (declarator,
+ type))
+ /* If we just return the declaration, crashes
+ will sometimes occur. We therefore return
+ void_type_node, as if this was a friend
+ declaration, to cause callers to completely
+ ignore this declaration. */
+ return void_type_node;
}
if (staticp)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 27882f7..aa81456 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -135,6 +135,7 @@ static tree tsubst_arg_types PROTO((tree, tree, tree));
static void check_specialization_scope PROTO((void));
static tree process_partial_specialization PROTO((tree));
static void set_current_access_from_decl PROTO((tree));
+static void check_default_tmpl_args PROTO((tree, tree, int, int));
/* We use TREE_VECs to hold template arguments. If there is only one
level of template arguments, then the TREE_VEC contains the
@@ -1853,28 +1854,9 @@ process_partial_specialization (decl)
int ntparms = TREE_VEC_LENGTH (inner_parms);
int i;
int did_error_intro = 0;
- int issued_default_arg_message = 0;
struct template_parm_data tpd;
struct template_parm_data tpd2;
- /* [temp.class.spec]
-
- The template parameter list of a specialization shall not
- contain default template argument values. */
- for (i = 0; i < ntparms; ++i)
- {
- if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)))
- {
- if (!issued_default_arg_message)
- {
- cp_error ("default argument in partial specialization `%T'",
- type);
- issued_default_arg_message = 1;
- }
- TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE;
- }
- }
-
/* We check that each of the template parameters given in the
partial specialization is used in the argument list to the
specialization. For example:
@@ -2029,6 +2011,107 @@ process_partial_specialization (decl)
return decl;
}
+/* Check that a template declaration's use of default arguments is not
+ invalid. Here, PARMS are the template parameters. IS_PRIMARY is
+ non-zero if DECL is the thing declared by a primary template.
+ IS_PARTIAL is non-zero if DECL is a partial specialization. */
+
+static void
+check_default_tmpl_args (decl, parms, is_primary, is_partial)
+ tree decl;
+ tree parms;
+ int is_primary;
+ int is_partial;
+{
+ char* msg;
+ int last_level_to_check;
+
+ /* [temp.param]
+
+ A default template-argument shall not be specified in a
+ function template declaration or a function template definition, nor
+ in the template-parameter-list of the definition of a member of a
+ class template. */
+
+ if (current_class_type
+ && !TYPE_BEING_DEFINED (current_class_type)
+ && DECL_REAL_CONTEXT (decl) == current_class_type
+ && DECL_DEFINED_IN_CLASS_P (decl))
+ /* We already checked these parameters when the template was
+ declared, so there's no need to do it again now. This is an
+ inline member function definition. */
+ return;
+
+ if (TREE_CODE (decl) != TYPE_DECL || is_partial || !is_primary)
+ /* For an ordinary class template, default template arguments are
+ allowed at the innermost level, e.g.:
+ template <class T = int>
+ struct S {};
+ but, in a partial specialization, they're not allowed even
+ there, as we have in [temp.class.spec]:
+
+ The template parameter list of a specialization shall not
+ contain default template argument values.
+
+ So, for a partial specialization, or for a function template,
+ we look at all of them. */
+ ;
+ else
+ /* But, for a primary class template that is not a partial
+ specialization we look at all template parameters except the
+ innermost ones. */
+ parms = TREE_CHAIN (parms);
+
+ /* Figure out what error message to issue. */
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ msg = "default argument for template parameter in function template `%D'";
+ else if (is_partial)
+ msg = "default argument in partial specialization `%D'";
+ else
+ msg = "default argument for template parameter for class enclosing `%D'";
+
+ if (current_class_type && TYPE_BEING_DEFINED (current_class_type))
+ /* If we're inside a class definition, there's no need to
+ examine the paramters to the class itself. On the one
+ hand, they will be checked when the class is defined, and,
+ on the other, default arguments are legal in things like:
+ template <class T = double>
+ struct S { template <class U> void f(U); };
+ Here the default argument for `S' has no bearing on the
+ declaration of `f'. */
+ last_level_to_check = template_class_depth (current_class_type) + 1;
+ else
+ /* Check everything. */
+ last_level_to_check = 0;
+
+ for (; parms && TMPL_PARMS_DEPTH (parms) >= last_level_to_check;
+ parms = TREE_CHAIN (parms))
+ {
+ tree inner_parms = TREE_VALUE (parms);
+ int i, ntparms;
+
+ ntparms = TREE_VEC_LENGTH (inner_parms);
+ for (i = 0; i < ntparms; ++i)
+ if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)))
+ {
+ if (msg)
+ {
+ cp_error (msg, decl);
+ msg = 0;
+ }
+
+ /* Clear out the default argument so that we are not
+ confused later. */
+ TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE;
+ }
+
+ /* At this point, if we're still interested in issuing messages,
+ they must apply to classes surrounding the object declared. */
+ if (msg)
+ msg = "default argument for template parameter for class enclosing `%D'";
+ }
+}
+
/* Creates a TEMPLATE_DECL for the indicated DECL using the template
parameters given by current_template_args, or reuses a
previously existing one, if appropriate. Returns the DECL, or an
@@ -2046,6 +2129,12 @@ push_template_decl_real (decl, is_friend)
tree info;
tree ctx;
int primary;
+ int is_partial;
+
+ /* See if this is a partial specialization. */
+ is_partial = (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)
+ && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
+ && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));
is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));
@@ -2076,6 +2165,7 @@ push_template_decl_real (decl, is_friend)
else
info = ctx;
+ /* See if this is a primary template. */
if (info && TREE_CODE (info) == FUNCTION_DECL)
primary = 0;
/* Note that template_class_depth returns 0 if given NULL_TREE, so
@@ -2096,47 +2186,13 @@ push_template_decl_real (decl, is_friend)
cp_error ("template declaration of `%#T'", TREE_TYPE (decl));
}
- /* Partial specialization. */
- if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)
- && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
- && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
- return process_partial_specialization (decl);
+ /* Check to see that the rules regarding the use of default
+ arguments are not being violated. */
+ check_default_tmpl_args (decl, current_template_parms,
+ primary, is_partial);
- /* [temp.param] A default template-argument shall not be specified in a
- function template declaration or a function template definition, nor
- in the template-parameter-list of the definition of a member of a
- class template. */
- {
- tree parms;
- int issued_default_arg_message = 0;
-
- parms = current_template_parms;
- if (primary)
- parms = TREE_CHAIN (parms);
- for (; parms; parms = TREE_CHAIN (parms))
- {
- tree inner_parms = TREE_VALUE (parms);
- int i, ntparms;
-
- if (TREE_TYPE (inner_parms))
- continue;
-
- ntparms = TREE_VEC_LENGTH (inner_parms);
- for (i = 0; i < ntparms; ++i)
- {
- if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)))
- {
- if (!issued_default_arg_message)
- {
- cp_error ("default argument for template parameter of class enclosing `%D'",
- decl);
- issued_default_arg_message = 1;
- }
- TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE;
- }
- }
- }
- }
+ if (is_partial)
+ return process_partial_specialization (decl);
args = current_template_args ();
@@ -4604,6 +4660,8 @@ instantiate_class_template (type)
DECL_IN_AGGR_P (r) = 1;
DECL_EXTERNAL (r) = 1;
cp_finish_decl (r, DECL_INITIAL (r), NULL_TREE, 0, 0);
+ if (DECL_DEFINED_IN_CLASS_P (r))
+ check_static_variable_definition (r, TREE_TYPE (r));
}
/* R will have a TREE_CHAIN if and only if it has already been
@@ -6468,7 +6526,7 @@ tsubst_expr (t, args, in_decl)
return NULL_TREE;
}
-/* Instantiate the indicated variable of function template TMPL with
+/* Instantiate the indicated variable or function template TMPL with
the template arguments in TARG_PTR. */
tree
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/defarg6.C b/gcc/testsuite/g++.old-deja/g++.pt/defarg6.C
new file mode 100644
index 0000000..0094c5c
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/defarg6.C
@@ -0,0 +1,27 @@
+// Build don't link:
+
+template <class T>
+struct C {
+ template <class U>
+ void f(U); // OK
+
+ template <class V = int>
+ struct I {}; // OK
+
+ template <class W = int>
+ void h(W); // ERROR - default argument
+
+ template <class Y>
+ void k(Y);
+};
+
+template <class T>
+template <class U = double>
+void C<T>::f(U) {} // ERROR - default argument
+
+template <class X = void*>
+void g(X); // ERROR - default argument
+
+template <class T = double>
+template <class Y>
+void C<T>::k(Y) {} // ERROR - default argument
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/defarg7.C b/gcc/testsuite/g++.old-deja/g++.pt/defarg7.C
new file mode 100644
index 0000000..0db043f
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/defarg7.C
@@ -0,0 +1,11 @@
+// Build don't link:
+
+template <int Dim, class T, class EngineTag>
+class Engine {};
+
+struct Brick;
+
+template<int Dim, class T = double , class EngineTag = Brick >
+struct ConstArray {
+ static const int dimensions = Engine<Dim, T, EngineTag>::dimensions;
+};
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/static5.C b/gcc/testsuite/g++.old-deja/g++.pt/static5.C
new file mode 100644
index 0000000..f6e125d
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/static5.C
@@ -0,0 +1,9 @@
+// Build don't link:
+
+template <class T>
+struct S
+{
+ static const T t = 3; // ERROR - initializing non-integral type
+};
+
+double d = S<double>::t;