aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/method.c
diff options
context:
space:
mode:
authorAlexandre Oliva <aoliva@redhat.com>2018-12-19 06:51:19 +0000
committerAlexandre Oliva <aoliva@gcc.gnu.org>2018-12-19 06:51:19 +0000
commitbceca9b3f7d9cd935574652edc62a117c8736823 (patch)
tree93061afdcfb56ab9463e3f2da40496c7479c5608 /gcc/cp/method.c
parent4469188ce7f228902629595941e1c2ff24b9c4d6 (diff)
downloadgcc-bceca9b3f7d9cd935574652edc62a117c8736823.zip
gcc-bceca9b3f7d9cd935574652edc62a117c8736823.tar.gz
gcc-bceca9b3f7d9cd935574652edc62a117c8736823.tar.bz2
[PR c++/88146] do not crash synthesizing inherited ctor(...)
This patch started out from the testcase in PR88146, that attempted to synthesize an inherited ctor without any args before a varargs ellipsis and crashed while at that, because of the unguarded dereferencing of the parm type list, that usually contains a terminator. The terminator is not there for varargs functions, however, and without any other args, we ended up dereferencing a NULL pointer. Oops. Guarding accesses to parm would be easy, but not necessary. In do_build_copy_constructor, non-inherited ctors are copy-ctors, that always have at least one parm, so parm needs not be guarded when we know the access will only take place when we're dealing with an inherited ctor. The only other problematic use was in the cvquals initializer, a variable only used in a loop over fields, that we skipped individually in inherited ctors. I've guarded the cvquals initialization and the entire loop over fields so they only run for copy-ctors. Avoiding the crash from unguarded accesses was easy, but I thought we should still produce the sorry message we got in other testcases that passed arguments through the ellipsis in inherited ctors. I put a check in, and noticed the inherited ctors were synthesized with the location assigned to the class name, although they were initially assigned the location of the using declaration. I decided the latter was better, and arranged for the better location to be retained. Further investigation revealed the lack of a sorry message had to do with the call being in a non-evaluated context, in this case, a noexcept expression. The sorry would be correctly reported in other contexts, so I rolled back the check I'd added, but retained the source location improvement. I was still concerned about issuing sorry messages while instantiating template ctors even in non-evaluated contexts, e.g., if a template ctor had a base initializer that used an inherited ctor with enough arguments that they'd go through an ellipsis. I wanted to defer the instantiation of such template ctors, but that would have been wrong for constexpr template ctors, and already done for non-constexpr ones. So, I just consolidated multiple test variants into a single testcase that explores and explains various of the possibilities I thought of. for gcc/cp/ChangeLog PR c++/88146 * method.c (do_build_copy_constructor): Guard cvquals init and loop over fields to run for non-inherited ctors only. (synthesize_method): Retain location of inherited ctor. for gcc/testsuite/ChangeLog PR c++/88146 * g++.dg/cpp0x/inh-ctor32.C: New. From-SVN: r267250
Diffstat (limited to 'gcc/cp/method.c')
-rw-r--r--gcc/cp/method.c89
1 files changed, 46 insertions, 43 deletions
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index fd023e2..17404a6 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -675,12 +675,9 @@ do_build_copy_constructor (tree fndecl)
}
else
{
- tree fields = TYPE_FIELDS (current_class_type);
tree member_init_list = NULL_TREE;
- int cvquals = cp_type_quals (TREE_TYPE (parm));
int i;
tree binfo, base_binfo;
- tree init;
vec<tree, va_gc> *vbases;
/* Initialize all the base-classes with the parameter converted
@@ -704,53 +701,58 @@ do_build_copy_constructor (tree fndecl)
inh, member_init_list);
}
- for (; fields; fields = DECL_CHAIN (fields))
+ if (!inh)
{
- tree field = fields;
- tree expr_type;
-
- if (TREE_CODE (field) != FIELD_DECL)
- continue;
- if (inh)
- continue;
+ int cvquals = cp_type_quals (TREE_TYPE (parm));
- expr_type = TREE_TYPE (field);
- if (DECL_NAME (field))
+ for (tree fields = TYPE_FIELDS (current_class_type);
+ fields; fields = DECL_CHAIN (fields))
{
- if (VFIELD_NAME_P (DECL_NAME (field)))
+ tree field = fields;
+ tree expr_type;
+
+ if (TREE_CODE (field) != FIELD_DECL)
continue;
- }
- else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type))
- /* Just use the field; anonymous types can't have
- nontrivial copy ctors or assignment ops or this
- function would be deleted. */;
- else
- continue;
- /* Compute the type of "init->field". If the copy-constructor
- parameter is, for example, "const S&", and the type of
- the field is "T", then the type will usually be "const
- T". (There are no cv-qualified variants of reference
- types.) */
- if (!TYPE_REF_P (expr_type))
- {
- int quals = cvquals;
+ expr_type = TREE_TYPE (field);
+ if (DECL_NAME (field))
+ {
+ if (VFIELD_NAME_P (DECL_NAME (field)))
+ continue;
+ }
+ else if (ANON_AGGR_TYPE_P (expr_type) && TYPE_FIELDS (expr_type))
+ /* Just use the field; anonymous types can't have
+ nontrivial copy ctors or assignment ops or this
+ function would be deleted. */;
+ else
+ continue;
- if (DECL_MUTABLE_P (field))
- quals &= ~TYPE_QUAL_CONST;
- quals |= cp_type_quals (expr_type);
- expr_type = cp_build_qualified_type (expr_type, quals);
- }
+ /* Compute the type of "init->field". If the copy-constructor
+ parameter is, for example, "const S&", and the type of
+ the field is "T", then the type will usually be "const
+ T". (There are no cv-qualified variants of reference
+ types.) */
+ if (!TYPE_REF_P (expr_type))
+ {
+ int quals = cvquals;
- init = build3 (COMPONENT_REF, expr_type, parm, field, NULL_TREE);
- if (move_p && !TYPE_REF_P (expr_type)
- /* 'move' breaks bit-fields, and has no effect for scalars. */
- && !scalarish_type_p (expr_type))
- init = move (init);
- init = build_tree_list (NULL_TREE, init);
+ if (DECL_MUTABLE_P (field))
+ quals &= ~TYPE_QUAL_CONST;
+ quals |= cp_type_quals (expr_type);
+ expr_type = cp_build_qualified_type (expr_type, quals);
+ }
+
+ tree init = build3 (COMPONENT_REF, expr_type, parm, field, NULL_TREE);
+ if (move_p && !TYPE_REF_P (expr_type)
+ /* 'move' breaks bit-fields, and has no effect for scalars. */
+ && !scalarish_type_p (expr_type))
+ init = move (init);
+ init = build_tree_list (NULL_TREE, init);
- member_init_list = tree_cons (field, init, member_init_list);
+ member_init_list = tree_cons (field, init, member_init_list);
+ }
}
+
finish_mem_initializers (member_init_list);
}
}
@@ -891,8 +893,9 @@ synthesize_method (tree fndecl)
/* Reset the source location, we might have been previously
deferred, and thus have saved where we were first needed. */
- DECL_SOURCE_LOCATION (fndecl)
- = DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (fndecl)));
+ if (!DECL_INHERITED_CTOR (fndecl))
+ DECL_SOURCE_LOCATION (fndecl)
+ = DECL_SOURCE_LOCATION (TYPE_NAME (DECL_CONTEXT (fndecl)));
/* If we've been asked to synthesize a clone, just synthesize the
cloned function instead. Doing so will automatically fill in the