Actually allow member concepts in using shorthand notation. 2014-06-24 Andrew Sutton <andrew.n.sut...@gmail.com> * gcc/cp/parser.c (cp_maybe_constrained_type_specifier): Defer handling the BASELINK check until concept-resolution in order to allow member conceps. (cp_parser_nonclass_name): Also Check for concept-names when the lookup finds a BASELINk. * gcc/cp/constraint.cc: (resolve_constraint_check) If the call target is a base-link, resolve against its overload set. (build_concept_check): Update comments and variable names to reflect actual processing. * gcc/testuite/g++.dg/concepts/mem-concept.C: New test. * gcc/testuite/g++.dg/concepts/mem-concept-err.C: New test.
Committed as r211946. Andrew Sutton
Index: mem-concept.C =================================================================== --- mem-concept.C (revision 0) +++ mem-concept.C (revision 0) @@ -0,0 +1,28 @@ +// { dg-options "-std=c++1y" } + +struct Base { + template<typename T> + static concept bool D() { return __is_same_as(T, int); } + + template<typename T, typename U> + static concept bool E() { return __is_same_as(T, U); } +}; + +void f1(Base::D) { } +void f2(Base::E<double> x) { } + +template<typename T> + struct S : Base { + void f1(Base::D) { } + void f2(Base::E<T> x) { } + }; + +int main() { + f1(0); + + f2(0.0); + + S<int> s; + s.f1(0); + s.f2(0); +} Index: mem-concept-err.C =================================================================== --- mem-concept-err.C (revision 0) +++ mem-concept-err.C (revision 0) @@ -0,0 +1,40 @@ +// { dg-options "-std=c++1y" } + + +// The following error is emitted without context. I'm not +// certain why that would be the case. It comes as a result +// of failing the declaration of S::f0(). +// +// cc1plus: error: expected ';' at end of member declaration + + +struct Base { + template<typename T, typename U> + bool C() const { return false; } // Not a concept! + + template<typename T> + static concept bool D() { return __is_same_as(T, int); } + + template<typename T, typename U> + static concept bool E() { return __is_same_as(T, U); } +}; + +void f1(Base::D) { } +void f2(Base::E<double> x) { } + +template<typename T> + struct S : Base { + void f0(Base::C<float> x) { } // { dg-error "expected|type" } + void f1(Base::D) { } + void f2(Base::E<T> x) { } + }; + +int main() { + f1('a'); // { dg-error "matching" } + f2(0); // { dg-error "matching" } + + S<int> s; + s.f1('a'); // { dg-error "matching" } + s.f2('a'); // { dg-error "matching" } +} +
Index: pt.c =================================================================== --- pt.c (revision 211415) +++ pt.c (working copy) @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. #include "coretypes.h" #include "tm.h" #include "tree.h" +#include "print-tree.h" #include "stringpool.h" #include "varasm.h" #include "attribs.h" Index: parser.c =================================================================== --- parser.c (revision 211935) +++ parser.c (working copy) @@ -15168,6 +15168,7 @@ cp_parser_allows_constrained_type_specif || parser->in_result_type_constraint_p); } + // Check if DECL and ARGS can form a constrained-type-specifier. If ARGS // is non-null, we try to form a concept check of the form DECL<?, ARGS> // where ? is a placeholder for any kind of template argument. If ARGS @@ -15177,13 +15178,6 @@ cp_maybe_constrained_type_specifier (cp_ { gcc_assert (args ? TREE_CODE (args) == TREE_VEC : true); - // If we get a reference to a member function, allow the referenced - // functions to participate in this resolution: the baselink may refer - // to a static member concept. - if (BASELINK_P (decl)) - decl = BASELINK_FUNCTIONS (decl); - gcc_assert (TREE_CODE (decl) == OVERLOAD); - // Don't do any heavy lifting if we know we're not in a context // where it could succeed. if (!cp_parser_allows_constrained_type_specifier (parser)) @@ -15191,7 +15185,8 @@ cp_maybe_constrained_type_specifier (cp_ // Try to build a call expression that evaluates the concept. This // can fail if the overload set refers only to non-templates. - tree call = build_concept_check (decl, build_nt(PLACEHOLDER_EXPR), args); + tree placeholder = build_nt(PLACEHOLDER_EXPR); + tree call = build_concept_check (decl, placeholder, args); if (call == error_mark_node) return NULL_TREE; @@ -15291,7 +15286,8 @@ cp_parser_nonclass_name (cp_parser* pars // // TODO: The name could also refer to a variable template or an // introduction (if followed by '{'). - if (flag_concepts && TREE_CODE (type_decl) == OVERLOAD) + if (flag_concepts && + (TREE_CODE (type_decl) == OVERLOAD || BASELINK_P (type_decl))) { // Determine whether the overload refers to a concept. if (tree decl = cp_maybe_concept_name (parser, type_decl)) Index: constraint.cc =================================================================== --- constraint.cc (revision 211591) +++ constraint.cc (working copy) @@ -181,8 +181,13 @@ resolve_constraint_check (tree call) { gcc_assert (TREE_CODE (call) == CALL_EXPR); - // A constraint check must be only be a template-id expression. + // A constraint check must be only a template-id expression. If + // it's a call to a base-link, its function(s) should be a + // template-id expressson. If this is not a template-id, then it + // cannot be a concept-check. tree target = CALL_EXPR_FN (call); + if (BASELINK_P (target)) + target = BASELINK_FUNCTIONS (target); if (TREE_CODE (target) != TEMPLATE_ID_EXPR) return NULL_TREE; @@ -850,19 +855,20 @@ build_call_check (tree id) } } // namespace -// Construct a concept check for the overloaded function, where the -// template arguments are the list given by ARG and REST. That is, it -// build the call expression OVL<ARG, REST>(). If REST is null, then -// the resulting constraint is OVL<ARG>(). +// Construct a concept check for the given TARGET. The target may be +// an overload set or a baselink referring to an overload set. Template +// arguments to the target are given by ARG and REST. If the target is +// a function (overload set or baselink reffering to an overload set), +// then ths builds the call expression TARGET<ARG, REST>(). If REST is +// NULL_TREE, then the resulting check is just TARGET<ARG>(). // -// TODO: Extend this to take a variable concept also. +// TODO: Allow TARGET to be a variable concept. tree -build_concept_check (tree ovl, tree arg, tree rest) +build_concept_check (tree target, tree arg, tree rest) { - gcc_assert (TREE_CODE (ovl) == OVERLOAD); gcc_assert (rest ? TREE_CODE (rest) == TREE_VEC : true); - // Build a template-id that acts as the call target using OVL as + // Build a template-id that acts as the call target using TARGET as // the template and ARG as the only explicit argument. int n = rest ? TREE_VEC_LENGTH (rest) : 0; tree targs = make_tree_vec (n + 1); @@ -871,7 +877,7 @@ build_concept_check (tree ovl, tree arg, for (int i = 0; i < n; ++i) TREE_VEC_ELT (targs, i + 1) = TREE_VEC_ELT (rest, i); SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, n + 1); - tree id = lookup_template_function (ovl, targs); + tree id = lookup_template_function (target, targs); return build_call_check (id); }