}
\f
+
+/* Returns true if functions FN1 and FN2 have equivalent trailing
+ requires clauses. */
+
+static bool
+function_requirements_equivalent_p (tree newfn, tree oldfn)
+{
+ /* In the concepts TS, the combined constraints are compared. */
+ if (cxx_dialect < cxx2a)
+ {
+ tree ci1 = get_constraints (oldfn);
+ tree ci2 = get_constraints (newfn);
+ tree req1 = ci1 ? CI_ASSOCIATED_CONSTRAINTS (ci1) : NULL_TREE;
+ tree req2 = ci2 ? CI_ASSOCIATED_CONSTRAINTS (ci2) : NULL_TREE;
+ return cp_tree_equal (req1, req2);
+ }
+
+ /* Compare only trailing requirements. */
+ tree reqs1 = get_trailing_function_requirements (newfn);
+ tree reqs2 = get_trailing_function_requirements (oldfn);
+ if ((reqs1 != NULL_TREE) != (reqs2 != NULL_TREE))
+ return false;
+ return cp_tree_equal (reqs1, reqs2);
+}
+
/* Subroutine of duplicate_decls: return truthvalue of whether
or not types of these decls match.
else
types_match = 0;
+ /* Two function declarations match if either has a requires-clause
+ then both have a requires-clause and their constraints-expressions
+ are equivalent. */
+ if (types_match && flag_concepts)
+ types_match = function_requirements_equivalent_p (newdecl, olddecl);
+
/* The decls dont match if they correspond to two different versions
of the same function. Disallow extern "C" functions to be
versions for now. */
}
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
+ if (!template_heads_equivalent_p (newdecl, olddecl))
+ return 0;
+
tree oldres = DECL_TEMPLATE_RESULT (olddecl);
tree newres = DECL_TEMPLATE_RESULT (newdecl);
if (TREE_CODE (newres) != TREE_CODE (oldres))
return 0;
- if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
- DECL_TEMPLATE_PARMS (olddecl)))
- return 0;
-
- if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
- types_match = (same_type_p (TREE_TYPE (oldres), TREE_TYPE (newres))
- && equivalently_constrained (olddecl, newdecl));
+ /* Two template types match if they are the same. Otherwise, compare
+ the underlying declarations. */
+ if (TREE_CODE (newres) == TYPE_DECL)
+ types_match = same_type_p (TREE_TYPE (newres), TREE_TYPE (oldres));
else
- // We don't need to check equivalently_constrained for variable and
- // function templates because we check it on the results.
- types_match = decls_match (oldres, newres);
+ types_match = decls_match (newres, oldres);
}
else
{
COMPARE_REDECLARATION);
}
- // Normal functions can be constrained, as can variable partial
- // specializations.
- if (types_match && VAR_OR_FUNCTION_DECL_P (newdecl))
- types_match = equivalently_constrained (newdecl, olddecl);
-
return types_match;
}
&& lookup_attribute ("gnu_inline", \
DECL_ATTRIBUTES (fn)))
+/* A subroutine of duplicate_decls. Emits a diagnostic when newdecl
+ ambiguates olddecl. Returns true if an error occurs. */
+
+static bool
+duplicate_function_template_decls (tree newdecl, tree olddecl)
+{
+
+ tree newres = DECL_TEMPLATE_RESULT (newdecl);
+ tree oldres = DECL_TEMPLATE_RESULT (olddecl);
+ /* Function template declarations can be differentiated by parameter
+ and return type. */
+ if (compparms (TYPE_ARG_TYPES (TREE_TYPE (oldres)),
+ TYPE_ARG_TYPES (TREE_TYPE (newres)))
+ && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
+ TREE_TYPE (TREE_TYPE (olddecl))))
+ {
+ /* ... and also by their template-heads and requires-clauses. */
+ if (template_heads_equivalent_p (newdecl, olddecl)
+ && function_requirements_equivalent_p (newres, oldres))
+ {
+ error ("ambiguating new declaration %q+#D", newdecl);
+ inform (DECL_SOURCE_LOCATION (olddecl),
+ "old declaration %q#D", olddecl);
+ return true;
+ }
+
+ /* FIXME: The types are the same but the are differences
+ in either the template heads or function requirements.
+ We should be able to diagnose a set of common errors
+ stemming from these declarations. For example:
+
+ template<typename T> requires C void f(...);
+ template<typename T> void f(...) requires C;
+
+ These are functionally equivalent but not equivalent. */
+ }
+
+ return false;
+}
+
/* If NEWDECL is a redeclaration of OLDDECL, merge the declarations.
If the redeclaration is invalid, a diagnostic is issued, and the
error_mark_node is returned. Otherwise, OLDDECL is returned.
if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
+ tree oldres = DECL_TEMPLATE_RESULT (olddecl);
+ tree newres = DECL_TEMPLATE_RESULT (newdecl);
+
/* The name of a class template may not be declared to refer to
any other template, class, function, object, namespace, value,
or type in the same scope. */
- if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == TYPE_DECL
- || TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
+ if (TREE_CODE (oldres) == TYPE_DECL
+ || TREE_CODE (newres) == TYPE_DECL)
{
error_at (newdecl_loc,
"conflicting declaration of template %q#D", newdecl);
"previous declaration %q#D", olddecl);
return error_mark_node;
}
- else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL
- && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
- && compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))),
- TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))))
- && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
- DECL_TEMPLATE_PARMS (olddecl))
- /* Template functions can be disambiguated by
- return type. */
- && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
- TREE_TYPE (TREE_TYPE (olddecl)))
- /* Template functions can also be disambiguated by
- constraints. */
- && equivalently_constrained (olddecl, newdecl))
+
+ else if (TREE_CODE (oldres) == FUNCTION_DECL
+ && TREE_CODE (newres) == FUNCTION_DECL)
{
- error_at (newdecl_loc, "ambiguating new declaration %q#D",
- newdecl);
- inform (olddecl_loc,
- "old declaration %q#D", olddecl);
+ if (duplicate_function_template_decls (newdecl, olddecl))
+ return error_mark_node;
+ return NULL_TREE;
}
else if (check_concept_refinement (olddecl, newdecl))
return error_mark_node;
return NULL;
}
+ if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == CONCEPT_DECL)
+ return G_("redefinition of %q#D");
+
if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) != FUNCTION_DECL
|| (DECL_TEMPLATE_RESULT (newdecl)
== DECL_TEMPLATE_RESULT (olddecl)))
{"value", &value_identifier, cik_normal},
{"_FUN", &fun_identifier, cik_normal},
{"__closure", &closure_identifier, cik_normal},
+ {"heap uninit", &heap_uninit_identifier, cik_normal},
+ {"heap ", &heap_identifier, cik_normal},
+ {"heap deleted", &heap_deleted_identifier, cik_normal},
{NULL, NULL, cik_normal}
};
/* Anonymous unions are objects, so they can have specifiers. */;
SET_ANON_AGGR_TYPE_P (declared_type);
- if (TREE_CODE (declared_type) != UNION_TYPE
- && !in_system_header_at (input_location))
- pedwarn (input_location, OPT_Wpedantic, "ISO C++ prohibits anonymous structs");
+ if (TREE_CODE (declared_type) != UNION_TYPE)
+ pedwarn (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (declared_type)),
+ OPT_Wpedantic, "ISO C++ prohibits anonymous structs");
}
else
return NULL_TREE;
}
+/* Return true if DECL has either a trivial destructor, or for C++2A
+ is constexpr and has a constexpr destructor. */
+
+static bool
+decl_maybe_constant_destruction (tree decl, tree type)
+{
+ return (TYPE_HAS_TRIVIAL_DESTRUCTOR (type)
+ || (cxx_dialect >= cxx2a
+ && VAR_P (decl)
+ && DECL_DECLARED_CONSTEXPR_P (decl)
+ && type_has_constexpr_destructor (strip_array_types (type))));
+}
+
/* Finish processing of a declaration;
install its line number and initial value.
If the length of an array type is not known before,
TREE_READONLY (decl) = 1;
/* Likewise if it needs destruction. */
- if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
+ if (!decl_maybe_constant_destruction (decl, type))
TREE_READONLY (decl) = 0;
}
based on the actual type of the variable, so store it in a hash table. */
static GTY((cache)) tree_cache_map *decomp_type_table;
-static void
-store_decomp_type (tree v, tree t)
-{
- if (!decomp_type_table)
- decomp_type_table = tree_cache_map::create_ggc (13);
- decomp_type_table->put (v, t);
-}
tree
lookup_decomp_type (tree v)
goto error_out;
}
/* Save the decltype away before reference collapse. */
- store_decomp_type (v[i], eltype);
+ hash_map_safe_put<hm_ggc> (decomp_type_table, v[i], eltype);
eltype = cp_build_reference_type (eltype, !lvalue_p (init));
TREE_TYPE (v[i]) = eltype;
layout_decl (v[i], 0);
if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
return void_node;
+ if (decl_maybe_constant_destruction (decl, type)
+ && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+ {
+ cxx_maybe_build_cleanup (decl, tf_warning_or_error);
+ return void_node;
+ }
+
/* If we're using "__cxa_atexit" (or "__cxa_thread_atexit" or
"__aeabi_atexit"), and DECL is a class object, we can just pass the
destructor to "__cxa_atexit"; we don't have to build a temporary
gcc_assert (TREE_STATIC (decl));
/* Some variables require no dynamic initialization. */
- if (TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
+ if (decl_maybe_constant_destruction (decl, TREE_TYPE (decl)))
{
/* Make sure the destructor is callable. */
cxx_maybe_build_cleanup (decl, tf_warning_or_error);
tree tmpl_reqs = NULL_TREE;
if (processing_template_decl > template_class_depth (ctype))
tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
-
- /* Adjust the required expression into a constraint. */
- if (decl_reqs)
- decl_reqs = normalize_expression (decl_reqs);
-
tree ci = build_constraints (tmpl_reqs, decl_reqs);
+ if (concept_p && ci)
+ {
+ error_at (location, "a function concept cannot be constrained");
+ ci = NULL_TREE;
+ }
set_constraints (decl, ci);
}
if (!same_type_ignoring_top_level_qualifiers_p (type, boolean_type_node))
error_at (declspecs->locations[ds_type_spec],
"concept must have type %<bool%>");
+ if (TEMPLATE_PARMS_CONSTRAINTS (current_template_parms))
+ {
+ error_at (location, "a variable concept cannot be constrained");
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = NULL_TREE;
+ }
}
else if (flag_concepts
&& processing_template_decl > template_class_depth (scope))
{
tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
tree ci = build_constraints (reqs, NULL_TREE);
+
set_constraints (decl, ci);
}
TYPE_PTRMEMFUNC_FLAG (t) = 1;
field = build_decl (input_location, FIELD_DECL, pfn_identifier, type);
+ DECL_NONADDRESSABLE_P (field) = 1;
fields = field;
field = build_decl (input_location, FIELD_DECL, delta_identifier,
delta_type_node);
+ DECL_NONADDRESSABLE_P (field) = 1;
DECL_CHAIN (field) = fields;
fields = field;
if (ctype || in_namespace)
error ("cannot use %<::%> in parameter declaration");
- if (type_uses_auto (type)
- && !(cxx_dialect >= cxx17 && template_parm_flag))
+ tree auto_node = type_uses_auto (type);
+ if (auto_node && !(cxx_dialect >= cxx17 && template_parm_flag))
{
if (cxx_dialect >= cxx14)
- error_at (typespec_loc,
- "%<auto%> parameter not permitted in this context");
+ {
+ if (decl_context == PARM && AUTO_IS_DECLTYPE (auto_node))
+ error_at (typespec_loc,
+ "cannot declare a parameter with %<decltype(auto)%>");
+ else
+ error_at (typespec_loc,
+ "%<auto%> parameter not permitted in this context");
+ }
else
error_at (typespec_loc, "parameter declared %<auto%>");
type = error_mark_node;
"a destructor cannot be %<concept%>");
return error_mark_node;
}
- if (constexpr_p)
- {
- error_at (declspecs->locations[ds_constexpr],
- "a destructor cannot be %<constexpr%>");
- return error_mark_node;
- }
+ if (constexpr_p && cxx_dialect < cxx2a)
+ {
+ error_at (declspecs->locations[ds_constexpr],
+ "%<constexpr%> destructors only available"
+ " with %<-std=c++2a%> or %<-std=gnu++2a%>");
+ return error_mark_node;
+ }
}
else if (sfk == sfk_constructor && friendp && !ctype)
{
tree tmpl = TREE_OPERAND (unqualified_id, 0);
if (variable_template_p (tmpl))
{
- error ("specialization of variable template %qD "
- "declared as function", tmpl);
+ error_at (id_loc, "specialization of variable template "
+ "%qD declared as function", tmpl);
inform (DECL_SOURCE_LOCATION (tmpl),
"variable template declared here");
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;
+ function_context
+ = (ctype != NULL_TREE
+ ? decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE);
+ publicp = ((! friendp || ! staticp)
+ && function_context == NULL_TREE);
decl = grokfndecl (ctype, type,
TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR
or implicitly defined), there's no need to worry about their
existence. Theoretically, they should never even be
instantiated, but that's hard to forestall. */
- error ("invalid constructor; you probably meant %<%T (const %T&)%>",
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "invalid constructor; you probably meant %<%T (const %T&)%>",
ctype, ctype);
return false;
}
if (!processing_template_decl && FNDECL_USED_AUTO (fndecl)
&& TREE_TYPE (fntype) == DECL_SAVED_AUTO_RETURN_TYPE (fndecl))
{
- if (is_auto (DECL_SAVED_AUTO_RETURN_TYPE (fndecl)))
+ if (is_auto (DECL_SAVED_AUTO_RETURN_TYPE (fndecl))
+ && !current_function_returns_value
+ && !current_function_returns_null)
{
+ /* We haven't applied return type deduction because we haven't
+ seen any return statements. Do that now. */
+ tree node = type_uses_auto (DECL_SAVED_AUTO_RETURN_TYPE (fndecl));
+ do_auto_deduction (DECL_SAVED_AUTO_RETURN_TYPE (fndecl),
+ void_node, node, tf_warning_or_error,
+ adc_return_type);
+
apply_deduced_return_type (fndecl, void_type_node);
fntype = TREE_TYPE (fndecl);
}
cleanup = error_mark_node;
else if (TYPE_HAS_TRIVIAL_DESTRUCTOR (type))
/* Discard the call. */;
+ else if (decl_maybe_constant_destruction (decl, type)
+ && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
+ cxx_constant_dtor (call, decl);
else if (cleanup)
cleanup = cp_build_compound_expr (cleanup, call, complain);
else
the end of the block. So let's unset the location of the
destructor call instead. */
protected_set_expr_location (cleanup, UNKNOWN_LOCATION);
+ if (cleanup && CONVERT_EXPR_P (cleanup))
+ protected_set_expr_location (TREE_OPERAND (cleanup, 0), UNKNOWN_LOCATION);
if (cleanup
&& DECL_P (decl)
{
if (undeduced_auto_decl (decl))
{
- if (complain & tf_error)
+ if (TREE_NO_WARNING (decl) && seen_error ())
+ /* We probably already complained about deduction failure. */;
+ else if (complain & tf_error)
error ("use of %qD before deduction of %<auto%>", decl);
return false;
}