aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/decl.c')
-rw-r--r--gcc/cp/decl.c267
1 files changed, 242 insertions, 25 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 208173a..e8ed472 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -72,7 +72,6 @@ enum bad_spec_place {
BSP_FIELD /* field */
};
-static tree grokparms (tree parmlist, tree *);
static const char *redeclaration_error_message (tree, tree);
static int decl_jump_unsafe (tree);
@@ -1079,8 +1078,10 @@ decls_match (tree newdecl, tree olddecl)
}
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
- if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl))
- != TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)))
+ 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),
@@ -1088,11 +1089,12 @@ decls_match (tree newdecl, tree olddecl)
return 0;
if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
- types_match = same_type_p (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)),
- TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl)));
+ types_match = (same_type_p (TREE_TYPE (oldres), TREE_TYPE (newres))
+ && equivalently_constrained (olddecl, newdecl));
else
- types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl),
- DECL_TEMPLATE_RESULT (newdecl));
+ // 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);
}
else
{
@@ -1120,6 +1122,11 @@ decls_match (tree newdecl, tree olddecl)
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;
}
@@ -1243,6 +1250,36 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl)
return true;
}
+// If OLDDECL and NEWDECL are concept declarations with the same type
+// (i.e., and template parameters), but different requirements,
+// emit diagnostics and return true. Otherwise, return false.
+static inline bool
+check_concept_refinement (tree olddecl, tree newdecl)
+{
+ if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl))
+ return false;
+
+ tree d1 = DECL_TEMPLATE_RESULT (olddecl);
+ tree d2 = DECL_TEMPLATE_RESULT (newdecl);
+ if (TREE_CODE (d1) != TREE_CODE (d2))
+ return false;
+
+ tree t1 = TREE_TYPE (d1);
+ tree t2 = TREE_TYPE (d2);
+ if (TREE_CODE (d1) == FUNCTION_DECL)
+ {
+ if (compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2))
+ && comp_template_parms (DECL_TEMPLATE_PARMS (olddecl),
+ DECL_TEMPLATE_PARMS (newdecl))
+ && !equivalently_constrained (olddecl, newdecl))
+ {
+ error ("cannot specialize concept %q#D", olddecl);
+ return true;
+ }
+ }
+ return false;
+}
+
/* DECL is a redeclaration of a function or function template. If
it does have default arguments issue a diagnostic. Note: this
function is used to enforce the requirements in C++11 8.3.6 about
@@ -1571,12 +1608,17 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
/* Template functions can be disambiguated by
return type. */
&& same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
- TREE_TYPE (TREE_TYPE (olddecl))))
+ TREE_TYPE (TREE_TYPE (olddecl)))
+ // Template functions can also be disambiguated by
+ // constraints.
+ && equivalently_constrained (olddecl, newdecl))
{
error ("ambiguating new declaration %q+#D", newdecl);
inform (DECL_SOURCE_LOCATION (olddecl),
"old declaration %q#D", olddecl);
}
+ else if (check_concept_refinement (olddecl, newdecl))
+ return error_mark_node;
return NULL_TREE;
}
if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -1593,8 +1635,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
are not ambiguous. */
else if ((!DECL_FUNCTION_VERSIONED (newdecl)
&& !DECL_FUNCTION_VERSIONED (olddecl))
+ // The functions have the same parameter types.
&& compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
- TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
+ TYPE_ARG_TYPES (TREE_TYPE (olddecl)))
+ // And the same constraints.
+ && equivalently_constrained (newdecl, olddecl))
{
error ("ambiguating new declaration of %q+#D", newdecl);
inform (DECL_SOURCE_LOCATION (olddecl),
@@ -2576,6 +2621,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
if (snode)
snode->remove ();
}
+
+ /* Remove the associated constraints for newdecl, if any, before
+ reclaiming memory. */
+ if (flag_concepts)
+ remove_constraints (newdecl);
+
ggc_free (newdecl);
return olddecl;
@@ -3981,6 +4032,10 @@ cxx_init_decl_processing (void)
/* Ensure attribs.c is initialized. */
init_attributes ();
+
+ /* Ensure constraint.cc is initialized. */
+ init_constraint_processing ();
+
extvisattr = build_tree_list (get_identifier ("externally_visible"),
NULL_TREE);
newattrs = tree_cons (get_identifier ("alloc_size"),
@@ -6368,6 +6423,16 @@ value_dependent_init_p (tree init)
return false;
}
+// Returns true if a DECL is VAR_DECL with the concept specifier.
+static inline bool
+is_concept_var (tree decl)
+{
+ return (VAR_P (decl)
+ // Not all variables have DECL_LANG_SPECIFIC.
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_DECLARED_CONCEPT_P (decl));
+}
+
/* Finish processing of a declaration;
install its line number and initial value.
If the length of an array type is not known before,
@@ -6446,7 +6511,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
tf_warning_or_error);
d_init = resolve_nondeduced_context (d_init);
type = TREE_TYPE (decl) = do_auto_deduction (type, d_init,
- auto_node);
+ auto_node,
+ tf_warning_or_error,
+ adc_variable_type);
if (type == error_mark_node)
return;
cp_apply_type_quals_to_decl (cp_type_quals (type), decl);
@@ -6544,6 +6611,8 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
init = NULL_TREE;
release_tree_vector (cleanups);
}
+ else if (!init && is_concept_var (decl))
+ error ("variable concept has no initializer");
else if (!DECL_PRETTY_FUNCTION_P (decl))
{
/* Deduce array size even if the initializer is dependent. */
@@ -7606,6 +7675,23 @@ check_static_quals (tree decl, cp_cv_quals quals)
decl);
}
+// Check that FN takes no arguments and returns bool.
+static void
+check_concept_fn (tree fn)
+{
+ // A constraint is nullary.
+ if (DECL_ARGUMENTS (fn))
+ error ("concept %q#D declared with function parameters", fn);
+
+ // The declared return type of the concept shall be bool, and
+ // it shall not be deduced from it definition.
+ tree type = TREE_TYPE (TREE_TYPE (fn));
+ if (is_auto (type))
+ error ("concept %q#D declared with a deduced return type", fn);
+ else if (type != boolean_type_node)
+ error ("concept %q#D with non-%<bool%> return type %qT", fn, type);
+}
+
/* Helper function. Replace the temporary this parameter injected
during cp_finish_omp_declare_simd with the real this parameter. */
@@ -7646,6 +7732,7 @@ grokfndecl (tree ctype,
tree declarator,
tree parms,
tree orig_declarator,
+ tree decl_reqs,
int virtualp,
enum overload_flags flags,
cp_cv_quals quals,
@@ -7667,6 +7754,16 @@ grokfndecl (tree ctype,
int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
tree t;
+ // Was the concept specifier present?
+ bool concept_p = inlinep & 4;
+
+ // Concept declarations must have a corresponding definition.
+ if (concept_p && !funcdef_flag)
+ {
+ error ("concept %qD has no definition", declarator);
+ return NULL_TREE;
+ }
+
if (rqual)
type = build_ref_qualified_type (type, rqual);
if (raises)
@@ -7674,6 +7771,21 @@ grokfndecl (tree ctype,
decl = build_lang_decl (FUNCTION_DECL, declarator, type);
+ /* Set the constraints on the declaration. */
+ if (flag_concepts)
+ {
+ 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 = make_predicate_constraint (decl_reqs);
+
+ tree ci = build_constraints (tmpl_reqs, decl_reqs);
+ set_constraints (decl, ci);
+ }
+
/* If we have an explicit location, use it, otherwise use whatever
build_lang_decl used (probably input_location). */
if (location != UNKNOWN_LOCATION)
@@ -7848,6 +7960,14 @@ grokfndecl (tree ctype,
if (inlinep & 2)
DECL_DECLARED_CONSTEXPR_P (decl) = true;
+ // If the concept declaration specifier was found, check
+ // that the declaration satisfies the necessary requirements.
+ if (concept_p)
+ {
+ DECL_DECLARED_CONCEPT_P (decl) = true;
+ check_concept_fn (decl);
+ }
+
DECL_EXTERNAL (decl) = 1;
if (TREE_CODE (type) == FUNCTION_TYPE)
{
@@ -7967,7 +8087,8 @@ grokfndecl (tree ctype,
decl = check_explicit_specialization (orig_declarator, decl,
template_count,
2 * funcdef_flag +
- 4 * (friendp != 0));
+ 4 * (friendp != 0) +
+ 8 * concept_p);
if (decl == error_mark_node)
return NULL_TREE;
@@ -8125,7 +8246,7 @@ grokvardecl (tree type,
tree orig_declarator,
const cp_decl_specifier_seq *declspecs,
int initialized,
- int constp,
+ int flags,
int template_count,
tree scope)
{
@@ -8134,6 +8255,9 @@ grokvardecl (tree type,
gcc_assert (!name || identifier_p (name));
+ bool constp = flags&1;
+ bool conceptp = flags&2;
+
/* Compute the scope in which to place the variable, but remember
whether or not that scope was explicitly specified by the user. */
explicit_scope = scope;
@@ -8231,10 +8355,33 @@ grokvardecl (tree type,
else
DECL_INTERFACE_KNOWN (decl) = 1;
+ /* Check that the variable can be safely declared as a concept.
+ Note that this also forbids explicit specializations. */
+ if (conceptp)
+ {
+ if (!processing_template_decl)
+ {
+ error ("a non-template variable cannot be %<concept%>");
+ return NULL_TREE;
+ }
+ else
+ DECL_DECLARED_CONCEPT_P (decl) = true;
+ if (!same_type_ignoring_top_level_qualifiers_p (type, boolean_type_node))
+ error_at (declspecs->locations[ds_type_spec],
+ "concept must have type %<bool%>");
+ }
+ 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);
+ }
+
// Handle explicit specializations and instantiations of variable templates.
if (orig_declarator)
decl = check_explicit_specialization (orig_declarator, decl,
- template_count, 0);
+ template_count, conceptp * 8);
return decl != error_mark_node ? decl : NULL_TREE;
}
@@ -8969,6 +9116,7 @@ grokdeclarator (const cp_declarator *declarator,
bool array_parameter_p = false;
source_location saved_loc = input_location;
const char *errmsg;
+ tree reqs = NULL_TREE;
signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned);
@@ -8978,6 +9126,12 @@ grokdeclarator (const cp_declarator *declarator,
explicit_intN = declspecs->explicit_intN_p;
thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread);
+ // Was concept_p specified? Note that ds_concept
+ // implies ds_constexpr!
+ bool concept_p = decl_spec_seq_has_spec_p (declspecs, ds_concept);
+ if (concept_p)
+ constexpr_p = true;
+
if (decl_context == FUNCDEF)
funcdef_flag = true, decl_context = NORMAL;
else if (decl_context == MEMFUNCDEF)
@@ -9220,6 +9374,12 @@ grokdeclarator (const cp_declarator *declarator,
if (name == NULL)
name = decl_context == PARM ? "parameter" : "type name";
+ if (concept_p && typedef_p)
+ {
+ error ("%<concept%> cannot appear in a typedef declaration");
+ return error_mark_node;
+ }
+
if (constexpr_p && typedef_p)
{
error ("%<constexpr%> cannot appear in a typedef declaration");
@@ -9548,9 +9708,12 @@ grokdeclarator (const cp_declarator *declarator,
|| thread_p)
error ("storage class specifiers invalid in parameter declarations");
+ /* Function parameters cannot be concept. */
+ if (concept_p)
+ error ("a parameter cannot be declared %<concept%>");
/* Function parameters cannot be constexpr. If we saw one, moan
and pretend it wasn't there. */
- if (constexpr_p)
+ else if (constexpr_p)
{
error ("a parameter cannot be declared %<constexpr%>");
constexpr_p = 0;
@@ -9778,6 +9941,10 @@ grokdeclarator (const cp_declarator *declarator,
if (raises == error_mark_node)
raises = NULL_TREE;
+ if (reqs)
+ error_at (location_of (reqs), "requires-clause on return type");
+ reqs = declarator->u.function.requires_clause;
+
/* Say it's a definition only for the CALL_EXPR
closest to the identifier. */
funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id;
@@ -10373,6 +10540,9 @@ grokdeclarator (const cp_declarator *declarator,
type = error_mark_node;
}
+ if (reqs)
+ error_at (location_of (reqs), "requires-clause on typedef");
+
if (decl_context == FIELD)
decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
else
@@ -10566,6 +10736,9 @@ grokdeclarator (const cp_declarator *declarator,
error ("invalid qualifiers on non-member function type");
}
+ if (reqs)
+ error_at (location_of (reqs), "requires-clause on type-id");
+
return type;
}
else if (unqualified_id == NULL_TREE && decl_context != PARM
@@ -10587,6 +10760,13 @@ grokdeclarator (const cp_declarator *declarator,
return error_mark_node;
}
+ if (reqs
+ && TREE_CODE (type) != FUNCTION_TYPE
+ && TREE_CODE (type) != METHOD_TYPE)
+ error_at (location_of (reqs),
+ "requires-clause on declaration of non-function type %qT",
+ type);
+
/* We don't check parameter types here because we can emit a better
error message later. */
if (decl_context != PARM)
@@ -10744,6 +10924,11 @@ grokdeclarator (const cp_declarator *declarator,
uqname, ctype);
return error_mark_node;
}
+ if (concept_p)
+ {
+ error ("a destructor cannot be %<concept%>");
+ return error_mark_node;
+ }
if (constexpr_p)
{
error ("a destructor cannot be %<constexpr%>");
@@ -10757,6 +10942,17 @@ grokdeclarator (const cp_declarator *declarator,
id_declarator->u.id.unqualified_name);
return error_mark_node;
}
+ if (sfk == sfk_constructor)
+ if (concept_p)
+ {
+ error ("a constructor cannot be %<concept%>");
+ return error_mark_node;
+ }
+ if (concept_p)
+ {
+ error ("a concept cannot be a member function");
+ concept_p = false;
+ }
if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
{
@@ -10785,9 +10981,10 @@ grokdeclarator (const cp_declarator *declarator,
? unqualified_id : dname,
parms,
unqualified_id,
+ reqs,
virtualp, flags, memfn_quals, rqual, raises,
friendp ? -1 : 0, friendp, publicp,
- inlinep | (2 * constexpr_p),
+ inlinep | (2 * constexpr_p) | (4 * concept_p),
initialized == SD_DELETED, sfk,
funcdef_flag, template_count, in_namespace,
attrlist, declarator->id_loc);
@@ -10890,8 +11087,10 @@ grokdeclarator (const cp_declarator *declarator,
if (declspecs->gnu_thread_keyword_p)
SET_DECL_GNU_TLS_P (decl);
}
-
- if (constexpr_p && !initialized)
+ if (concept_p)
+ error ("static data member %qE declared %<concept%>",
+ unqualified_id);
+ else if (constexpr_p && !initialized)
{
error ("constexpr static data member %qD must have an "
"initializer", decl);
@@ -10900,7 +11099,10 @@ grokdeclarator (const cp_declarator *declarator,
}
else
{
- if (constexpr_p)
+ if (concept_p)
+ error ("non-static data member %qE declared %<concept%>",
+ unqualified_id);
+ else if (constexpr_p)
{
error ("non-static data member %qE declared %<constexpr%>",
unqualified_id);
@@ -11010,10 +11212,12 @@ grokdeclarator (const cp_declarator *declarator,
TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
- virtualp, flags, memfn_quals, rqual, raises,
+ reqs, virtualp, flags, memfn_quals, rqual, raises,
1, friendp,
- publicp, inlinep | (2 * constexpr_p),
- initialized == SD_DELETED, sfk,
+ publicp,
+ inlinep | (2 * constexpr_p) | (4 * concept_p),
+ initialized == SD_DELETED,
+ sfk,
funcdef_flag,
template_count, in_namespace, attrlist,
declarator->id_loc);
@@ -11054,7 +11258,7 @@ grokdeclarator (const cp_declarator *declarator,
decl = grokvardecl (type, dname, unqualified_id,
declspecs,
initialized,
- (type_quals & TYPE_QUAL_CONST) != 0,
+ ((type_quals & TYPE_QUAL_CONST) != 0) | (2 * concept_p),
template_count,
ctype ? ctype : in_namespace);
if (decl == NULL_TREE)
@@ -11304,7 +11508,7 @@ type_is_deprecated (tree type)
*PARMS is set to the chain of PARM_DECLs created. */
-static tree
+tree
grokparms (tree parmlist, tree *parms)
{
tree result = NULL_TREE;
@@ -12399,8 +12603,16 @@ xref_tag_1 (enum tag_types tag_code, tree name,
{
if (template_header_p && MAYBE_CLASS_TYPE_P (t))
{
- if (!redeclare_class_template (t, current_template_parms))
- return error_mark_node;
+ /* Check that we aren't trying to overload a class with different
+ constraints. */
+ tree constr = NULL_TREE;
+ if (current_template_parms)
+ {
+ tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
+ constr = build_constraints (reqs, NULL_TREE);
+ }
+ if (!redeclare_class_template (t, current_template_parms, constr))
+ return error_mark_node;
}
else if (!processing_template_decl
&& CLASS_TYPE_P (t)
@@ -14252,6 +14464,10 @@ finish_function (int flags)
fntype = TREE_TYPE (fndecl);
}
+ // If this is a concept, check that the definition is reasonable.
+ if (DECL_DECLARED_CONCEPT_P (fndecl))
+ check_function_concept (fndecl);
+
/* Save constexpr function body before it gets munged by
the NRV transformation. */
maybe_save_function_definition (fndecl);
@@ -14742,6 +14958,7 @@ cp_tree_node_structure (union lang_tree_node * t)
case TRAIT_EXPR: return TS_CP_TRAIT_EXPR;
case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR;
case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO;
+ case CONSTRAINT_INFO: return TS_CP_CONSTRAINT_INFO;
case USERDEF_LITERAL: return TS_CP_USERDEF_LITERAL;
default: return TS_CP_GENERIC;
}