I've been surprised at the number of issues that have come up while I've
been working on implementing the notion of instantiation-dependent
expressions, which aren't currently described in the standard other than
as "expression involving a template parameter". I checked in fixes for
several of these issues last week, but now here's another batch.
The first patch fixes an issue with partial ordering whereby we weren't
keeping processing_template_decl set when instantiating a function using
dependent template arguments.
The second patch gives the error about using a parenthesized expression
list to initialize a non-class variable even if the expressions are
dependent, to avoid a diagnostic regression as more things become dependent.
The third patch uses coerce_template_parms to make sure that after we've
substituted the deduced args into the partial specialization argument
list, we do have arguments of the appropriate type and that constants
have been folded the way we want. Without this we could have unresolved
overloads and variables instead of constants.
The fourth patch implements making a template template parameter a
friend, which is tested in cpp0x/friend2.C and seems to have worked
before entirely by accident.
The fifth patch moves the decision to build a SCOPE_REF to express a
non-type-dependent qualified-id to a different place so that it is
preserved in partial instantiations.
And finally, the implementation of instantiation_dependent_expression_p.
We really only need to check it in two places: deciding whether a
decltype represents a dependent type, and in checking for
value-dependence. I've proposed to the committee that making
value-dependent a superset of instantiation-dependent, but not doing the
same for type-dependent, is the best way to handle
instantiation-dependency, and that's what I've implemented here. I also
implemented something that has been a bit controversial on the
committee: treating member references as instantiation-dependent even
when they don't actually involve any template parameters, because access
checking at instantiation time might vary between specializations; see
my test decltype41.C for an example.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 894047b122a1676c6f0ba9e94eb79ca812174e6a
Author: Jason Merrill <ja...@redhat.com>
Date: Thu Aug 30 11:54:34 2012 -0400
* pt.c (instantiate_template_1): Keep processing_template_decl set
if there are dependent args.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f8ff1df..54d92df 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14373,6 +14373,10 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain)
/* Instantiation of the function happens in the context of the function
template, not the context of the overload resolution we're doing. */
push_to_top_level ();
+ /* If there are dependent arguments, e.g. because we're doing partial
+ ordering, make sure processing_template_decl stays set. */
+ if (uses_template_parms (targ_ptr))
+ ++processing_template_decl;
if (DECL_CLASS_SCOPE_P (gen_tmpl))
{
tree ctx = tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr,
commit 764a3a0466f51b1c2c5eeca698cc0cd5b45bcf22
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Aug 29 19:43:20 2012 -0400
* decl.c (cp_finish_decl): Check for invalid multiple initializers
even if the initializer is dependent.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 4b2958c..19485fc 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6123,8 +6123,15 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
release_tree_vector (cleanups);
}
else if (!DECL_PRETTY_FUNCTION_P (decl))
- /* Deduce array size even if the initializer is dependent. */
- maybe_deduce_size_from_array_init (decl, init);
+ {
+ /* Deduce array size even if the initializer is dependent. */
+ maybe_deduce_size_from_array_init (decl, init);
+ /* And complain about multiple initializers. */
+ if (init && TREE_CODE (init) == TREE_LIST && TREE_CHAIN (init)
+ && !MAYBE_CLASS_TYPE_P (type))
+ init = build_x_compound_expr_from_list (init, ELK_INIT,
+ tf_warning_or_error);
+ }
if (init)
DECL_INITIAL (decl) = init;
diff --git a/gcc/testsuite/g++.dg/template/static30.C b/gcc/testsuite/g++.dg/template/static30.C
index 01fa5dc..07dafe2 100644
--- a/gcc/testsuite/g++.dg/template/static30.C
+++ b/gcc/testsuite/g++.dg/template/static30.C
@@ -7,4 +7,4 @@ template <int> struct A
};
template <int N> const int A<N>::i1(A<N>::i);
-template <int N> const int A<N>::i2(3, A<N>::i);
+template <int N> const int A<N>::i2(3, A<N>::i); // { dg-error "expression list" }
commit e75847b77eea8af35562e41dc5250b9bb4dbc956
Author: Jason Merrill <ja...@redhat.com>
Date: Thu Aug 30 16:29:47 2012 -0400
* pt.c (get_class_bindings): Call coerce_template_parms. Add
main_tmpl parameter.
(more_specialized_class): Add main_tmpl parameter.
(most_specialized_class): Adjust calls.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 54d92df..792e9d1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -128,7 +128,7 @@ static int unify (tree, tree, tree, tree, int, bool);
static void add_pending_template (tree);
static tree reopen_tinst_level (struct tinst_level *);
static tree tsubst_initializer_list (tree, tree);
-static tree get_class_bindings (tree, tree, tree);
+static tree get_class_bindings (tree, tree, tree, tree);
static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
bool, bool);
static void tsubst_enum (tree, tree, tree);
@@ -17087,7 +17087,8 @@ more_specialized_fn (tree pat1, tree pat2, int len)
return -1;
}
-/* Determine which of two partial specializations is more specialized.
+/* Determine which of two partial specializations of MAIN_TMPL is more
+ specialized.
PAT1 is a TREE_LIST whose TREE_TYPE is the _TYPE node corresponding
to the first partial specialization. The TREE_VALUE is the
@@ -17102,7 +17103,7 @@ more_specialized_fn (tree pat1, tree pat2, int len)
two templates is more specialized. */
static int
-more_specialized_class (tree pat1, tree pat2)
+more_specialized_class (tree main_tmpl, tree pat1, tree pat2)
{
tree targs;
tree tmpl1, tmpl2;
@@ -17117,7 +17118,7 @@ more_specialized_class (tree pat1, tree pat2)
types in the arguments, and we need our dependency check functions
to behave correctly. */
++processing_template_decl;
- targs = get_class_bindings (TREE_VALUE (pat1),
+ targs = get_class_bindings (main_tmpl, TREE_VALUE (pat1),
CLASSTYPE_TI_ARGS (tmpl1),
CLASSTYPE_TI_ARGS (tmpl2));
if (targs)
@@ -17126,7 +17127,7 @@ more_specialized_class (tree pat1, tree pat2)
any_deductions = true;
}
- targs = get_class_bindings (TREE_VALUE (pat2),
+ targs = get_class_bindings (main_tmpl, TREE_VALUE (pat2),
CLASSTYPE_TI_ARGS (tmpl2),
CLASSTYPE_TI_ARGS (tmpl1));
if (targs)
@@ -17205,8 +17206,8 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
return targs;
}
-/* Return the innermost template arguments that, when applied to a
- template specialization whose innermost template parameters are
+/* Return the innermost template arguments that, when applied to a partial
+ specialization of MAIN_TMPL whose innermost template parameters are
TPARMS, and whose specialization arguments are SPEC_ARGS, yield the
ARGS.
@@ -17221,7 +17222,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
is bound to `double'. */
static tree
-get_class_bindings (tree tparms, tree spec_args, tree args)
+get_class_bindings (tree main_tmpl, tree tparms, tree spec_args, tree args)
{
int i, ntparms = TREE_VEC_LENGTH (tparms);
tree deduced_args;
@@ -17261,6 +17262,9 @@ get_class_bindings (tree tparms, tree spec_args, tree args)
`T' is `A' but unify () does not check whether `typename T::X'
is `int'. */
spec_args = tsubst (spec_args, deduced_args, tf_none, NULL_TREE);
+ spec_args = coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (main_tmpl),
+ spec_args, main_tmpl,
+ tf_none, false, false);
if (spec_args == error_mark_node
/* We only need to check the innermost arguments; the other
arguments will always agree. */
@@ -17485,7 +17489,7 @@ most_specialized_class (tree type, tree tmpl, tsubst_flags_t complain)
if (partial_spec_args == error_mark_node)
return error_mark_node;
- spec_args = get_class_bindings (parms,
+ spec_args = get_class_bindings (tmpl, parms,
partial_spec_args,
args);
if (spec_args)
@@ -17506,7 +17510,7 @@ most_specialized_class (tree type, tree tmpl, tsubst_flags_t complain)
t = TREE_CHAIN (t);
for (; t; t = TREE_CHAIN (t))
{
- fate = more_specialized_class (champ, t);
+ fate = more_specialized_class (tmpl, champ, t);
if (fate == 1)
;
else
@@ -17527,7 +17531,7 @@ most_specialized_class (tree type, tree tmpl, tsubst_flags_t complain)
if (!ambiguous_p)
for (t = list; t && t != champ; t = TREE_CHAIN (t))
{
- fate = more_specialized_class (champ, t);
+ fate = more_specialized_class (tmpl, champ, t);
if (fate != 1)
{
ambiguous_p = true;
commit 69cd140a447cd745eb60042ccc2f9ceb4c73835a
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Aug 29 17:53:20 2012 -0400
* friend.c (make_friend_class): Handle template template parameters.
* parser.c (cp_parser_template_declaration_after_export): Likewise.
* pt.c (tsubst_friend_class): Likewise.
(instantiate_class_template_1): Likewise
* decl.c (check_elaborated_type_specifier): Likewise.
(lookup_and_check_tag): Likewise.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 19485fc..c909dea 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -11484,9 +11484,10 @@ check_elaborated_type_specifier (enum tag_types tag_code,
type, tag_name (tag_code));
return error_mark_node;
}
- /* Accept bound template template parameters. */
+ /* Accept template template parameters. */
else if (allow_template_p
- && TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM)
+ && (TREE_CODE (type) == BOUND_TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM))
;
/* [dcl.type.elab]
@@ -11574,7 +11575,9 @@ lookup_and_check_tag (enum tag_types tag_code, tree name,
else
decl = lookup_type_scope (name, scope);
- if (decl && DECL_CLASS_TEMPLATE_P (decl))
+ if (decl
+ && (DECL_CLASS_TEMPLATE_P (decl)
+ || DECL_TEMPLATE_TEMPLATE_PARM_P (decl)))
decl = DECL_TEMPLATE_RESULT (decl);
if (decl && TREE_CODE (decl) == TYPE_DECL)
@@ -11679,6 +11682,9 @@ xref_tag_1 (enum tag_types tag_code, tree name,
&& template_class_depth (current_class_type)
&& template_header_p)
{
+ if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
+ return t;
+
/* Since SCOPE is not TS_CURRENT, we are not looking at a
definition of this tag. Since, in addition, we are currently
processing a (member) template declaration of a template
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index d0cbaed..d4548ff 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -224,7 +224,8 @@ make_friend_class (tree type, tree friend_type, bool complain)
int class_template_depth = template_class_depth (type);
int friend_depth = processing_template_decl - class_template_depth;
- if (! MAYBE_CLASS_TYPE_P (friend_type))
+ if (! MAYBE_CLASS_TYPE_P (friend_type)
+ && TREE_CODE (friend_type) != TEMPLATE_TEMPLATE_PARM)
{
/* N1791: If the type specifier in a friend declaration designates a
(possibly cv-qualified) class type, that class is declared as a
@@ -349,6 +350,8 @@ make_friend_class (tree type, tree friend_type, bool complain)
error ("template parameter type %qT declared %<friend%>", friend_type);
return;
}
+ else if (TREE_CODE (friend_type) == TEMPLATE_TEMPLATE_PARM)
+ friend_type = TYPE_NAME (friend_type);
else if (!CLASSTYPE_TEMPLATE_INFO (friend_type))
{
/* template <class T> friend class A; where A is not a template */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 0f897c9..091a967 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -21240,7 +21240,9 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
decl = finish_member_template_decl (decl);
}
- else if (friend_p && decl && TREE_CODE (decl) == TYPE_DECL)
+ else if (friend_p && decl
+ && (TREE_CODE (decl) == TYPE_DECL
+ || DECL_TYPE_TEMPLATE_P (decl)))
make_friend_class (current_class_type, TREE_TYPE (decl),
/*complain=*/true);
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 792e9d1..6506a67 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8152,6 +8152,12 @@ tsubst_friend_class (tree friend_tmpl, tree args)
tree tmpl;
tree context;
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (friend_tmpl))
+ {
+ tree t = tsubst (TREE_TYPE (friend_tmpl), args, tf_none, NULL_TREE);
+ return TREE_TYPE (t);
+ }
+
context = CP_DECL_CONTEXT (friend_tmpl);
if (context != global_namespace)
@@ -8736,7 +8742,8 @@ instantiate_class_template_1 (tree type)
}
else
{
- if (TYPE_P (t) || DECL_CLASS_TEMPLATE_P (t))
+ if (TYPE_P (t) || DECL_CLASS_TEMPLATE_P (t)
+ || DECL_TEMPLATE_TEMPLATE_PARM_P (t))
{
/* Build new CLASSTYPE_FRIEND_CLASSES. */
commit 506539a34192c51c25b4d6a474a829c5f5691613
Author: Jason Merrill <ja...@redhat.com>
Date: Mon Aug 27 20:39:52 2012 -0400
* semantics.c (finish_qualified_id_expr): Handle building up a
non-dependent SCOPE_REF here.
(finish_id_expression): Not here.
* error.c (dump_decl) [SCOPE_REF]: Only pass TFF_UNQUALIFIED_NAME.
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 40f96d3..7d60fe0 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1042,7 +1042,7 @@ dump_decl (tree t, int flags)
case SCOPE_REF:
dump_type (TREE_OPERAND (t, 0), flags);
pp_string (cxx_pp, "::");
- dump_decl (TREE_OPERAND (t, 1), flags|TFF_UNQUALIFIED_NAME);
+ dump_decl (TREE_OPERAND (t, 1), TFF_UNQUALIFIED_NAME);
break;
case ARRAY_REF:
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index d66accf..6d7004b 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1792,6 +1792,23 @@ finish_qualified_id_expr (tree qualifying_class,
being taken. */
expr = build_offset_ref (qualifying_class, expr, /*address_p=*/false);
}
+ else if (BASELINK_P (expr))
+ ;
+ else
+ {
+ expr = convert_from_reference (expr);
+
+ /* In a template, return a SCOPE_REF for most qualified-ids
+ so that we can check access at instantiation time. But if
+ we're looking at a member of the current instantiation, we
+ know we have access and building up the SCOPE_REF confuses
+ non-type template argument handling. */
+ if (processing_template_decl
+ && !currently_open_class (qualifying_class))
+ expr = build_qualified_name (TREE_TYPE (expr),
+ qualifying_class, expr,
+ template_p);
+ }
return expr;
}
@@ -3253,7 +3270,7 @@ finish_id_expression (tree id_expression,
if (TREE_CODE (decl) == FUNCTION_DECL)
mark_used (decl);
- if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl))
+ if (TYPE_P (scope))
decl = finish_qualified_id_expr (scope,
decl,
done,
@@ -3261,21 +3278,7 @@ finish_id_expression (tree id_expression,
template_p,
template_arg_p);
else
- {
- tree r = convert_from_reference (decl);
-
- /* In a template, return a SCOPE_REF for most qualified-ids
- so that we can check access at instantiation time. But if
- we're looking at a member of the current instantiation, we
- know we have access and building up the SCOPE_REF confuses
- non-type template argument handling. */
- if (processing_template_decl && TYPE_P (scope)
- && !currently_open_class (scope))
- r = build_qualified_name (TREE_TYPE (r),
- scope, decl,
- template_p);
- decl = r;
- }
+ decl = convert_from_reference (decl);
}
else if (TREE_CODE (decl) == FIELD_DECL)
{
commit 121ddf0344d7cd0bee6eac5561339b82214f4fa5
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Jul 31 14:43:21 2012 -0400
PR c++/50545
PR c++/51222
* pt.c (instantiation_dependent_r): New.
(instantiation_dependent_expression_p): New.
(value_dependent_expression_p): Use it. SCOPE_REF is always dependent.
* semantics.c (finish_decltype_type): Use it.
* cp-tree.h: Declare it.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7ffc929..1b085bd 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5391,6 +5391,7 @@ extern bool any_type_dependent_arguments_p (const VEC(tree,gc) *);
extern bool any_type_dependent_elements_p (const_tree);
extern bool type_dependent_expression_p_push (tree);
extern bool value_dependent_expression_p (tree);
+extern bool instantiation_dependent_expression_p (tree);
extern bool any_value_dependent_elements_p (const_tree);
extern bool dependent_omp_for_p (tree, tree, tree, tree);
extern tree resolve_typename_type (tree, bool);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6506a67..5ce6e8a 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -19100,20 +19100,7 @@ dependent_scope_p (tree scope)
/* Note that this predicate is not appropriate for general expressions;
only constant expressions (that satisfy potential_constant_expression)
- can be tested for value dependence.
-
- We should really also have a predicate for "instantiation-dependent".
-
- fold_non_dependent_expr: fold if constant and not type-dependent and not value-dependent.
- (what about instantiation-dependent constant-expressions?)
- is_late_template_attribute: defer if instantiation-dependent.
- compute_array_index_type: proceed if constant and not t- or v-dependent
- if instantiation-dependent, need to remember full expression
- uses_template_parms: FIXME - need to audit callers
- tsubst_decl [function_decl]: Why is this using value_dependent_expression_p?
- dependent_type_p [array_type]: dependent if index type is dependent
- (or non-constant?)
- static_assert - instantiation-dependent */
+ can be tested for value dependence. */
bool
value_dependent_expression_p (tree expression)
@@ -19193,7 +19180,7 @@ value_dependent_expression_p (tree expression)
return true;
else if (TYPE_P (expression))
return dependent_type_p (expression);
- return type_dependent_expression_p (expression);
+ return instantiation_dependent_expression_p (expression);
case AT_ENCODE_EXPR:
/* An 'encode' expression is value-dependent if the operand is
@@ -19203,13 +19190,13 @@ value_dependent_expression_p (tree expression)
case NOEXCEPT_EXPR:
expression = TREE_OPERAND (expression, 0);
- return type_dependent_expression_p (expression);
+ return instantiation_dependent_expression_p (expression);
case SCOPE_REF:
- {
- tree name = TREE_OPERAND (expression, 1);
- return value_dependent_expression_p (name);
- }
+ /* instantiation_dependent_r treats this as dependent so that we
+ check access at instantiation time, and all instantiation-dependent
+ expressions should also be considered value-dependent. */
+ return true;
case COMPONENT_REF:
return (value_dependent_expression_p (TREE_OPERAND (expression, 0))
@@ -19488,6 +19475,104 @@ type_dependent_expression_p (tree expression)
return (dependent_type_p (TREE_TYPE (expression)));
}
+/* walk_tree callback function for instantiation_dependent_expression_p,
+ below. Returns non-zero if a dependent subexpression is found. */
+
+static tree
+instantiation_dependent_r (tree *tp, int *walk_subtrees,
+ void *data ATTRIBUTE_UNUSED)
+{
+ if (TYPE_P (*tp))
+ {
+ /* We don't have to worry about decltype currently because decltype
+ of an instantiation-dependent expr is a dependent type. This
+ might change depending on the resolution of DR 1172. */
+ *walk_subtrees = false;
+ return NULL_TREE;
+ }
+ enum tree_code code = TREE_CODE (*tp);
+ switch (code)
+ {
+ /* Don't treat an argument list as dependent just because it has no
+ TREE_TYPE. */
+ case TREE_LIST:
+ case TREE_VEC:
+ return NULL_TREE;
+
+ case TEMPLATE_PARM_INDEX:
+ return *tp;
+
+ /* Handle expressions with type operands. */
+ case SIZEOF_EXPR:
+ case ALIGNOF_EXPR:
+ case TYPEID_EXPR:
+ case AT_ENCODE_EXPR:
+ case TRAIT_EXPR:
+ {
+ tree op = TREE_OPERAND (*tp, 0);
+ if (TYPE_P (op))
+ {
+ if (dependent_type_p (op)
+ || (code == TRAIT_EXPR
+ && dependent_type_p (TREE_OPERAND (*tp, 1))))
+ return *tp;
+ else
+ {
+ *walk_subtrees = false;
+ return NULL_TREE;
+ }
+ }
+ break;
+ }
+
+ case COMPONENT_REF:
+ if (TREE_CODE (TREE_OPERAND (*tp, 1)) == IDENTIFIER_NODE)
+ /* In a template, finish_class_member_access_expr creates a
+ COMPONENT_REF with an IDENTIFIER_NODE for op1 even if it isn't
+ type-dependent, so that we can check access control at
+ instantiation time (PR 42277). See also Core issue 1273. */
+ return *tp;
+ break;
+
+ case SCOPE_REF:
+ /* Similarly, finish_qualified_id_expr builds up a SCOPE_REF in a
+ template so that we can check access at instantiation time even
+ though we know which member it resolves to. */
+ return *tp;
+
+ default:
+ break;
+ }
+
+ if (type_dependent_expression_p (*tp))
+ return *tp;
+ else
+ return NULL_TREE;
+}
+
+/* Returns TRUE if the EXPRESSION is instantiation-dependent, in the
+ sense defined by the ABI:
+
+ "An expression is instantiation-dependent if it is type-dependent
+ or value-dependent, or it has a subexpression that is type-dependent
+ or value-dependent." */
+
+bool
+instantiation_dependent_expression_p (tree expression)
+{
+ tree result;
+
+ if (!processing_template_decl)
+ return false;
+
+ if (expression == error_mark_node)
+ return false;
+
+ result = cp_walk_tree_without_duplicates (&expression,
+ instantiation_dependent_r, NULL);
+ return result != NULL_TREE;
+}
+
/* Like type_dependent_expression_p, but it also works while not processing
a template definition, i.e. during substitution or mangling. */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 6d7004b..183a78a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -5187,14 +5187,10 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p,
return error_mark_node;
}
- /* FIXME instantiation-dependent */
- if (type_dependent_expression_p (expr)
- /* In a template, a COMPONENT_REF has an IDENTIFIER_NODE for op1 even
- if it isn't dependent, so that we can check access control at
- instantiation time, so defer the decltype as well (PR 42277). */
- || (id_expression_or_member_access_p
- && processing_template_decl
- && TREE_CODE (expr) == COMPONENT_REF))
+ /* Depending on the resolution of DR 1172, we may later need to distinguish
+ instantiation-dependent but not type-dependent expressions so that, say,
+ A<decltype(sizeof(T))>::U doesn't require 'typename'. */
+ if (instantiation_dependent_expression_p (expr))
{
type = cxx_make_type (DECLTYPE_TYPE);
DECLTYPE_TYPE_EXPR (type) = expr;
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype40.C b/gcc/testsuite/g++.dg/cpp0x/decltype40.C
new file mode 100644
index 0000000..7933c95
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype40.C
@@ -0,0 +1,101 @@
+// PR c++/51222
+// { dg-options -std=c++11 }
+
+template<class T>
+struct add_rref {
+ typedef T&& type;
+};
+
+template<>
+struct add_rref<void> {
+ typedef void type;
+};
+
+template<class T>
+typename add_rref<T>::type declval();
+
+template<class T, class U, class =
+ decltype(::delete ::new T(declval<U>()))
+>
+auto f(int) -> char;
+
+template<class, class>
+auto f(...) -> char(&)[2];
+
+template<class T, class =
+ decltype(::delete ::new T())
+>
+auto g(int) -> char;
+
+template<class>
+auto g(...) -> char(&)[2];
+
+template<class T, class U>
+auto f2(int) -> decltype(::delete ::new T(declval<U>()), char());
+
+template<class, class>
+auto f2(...) -> char(&)[2];
+
+template<class T>
+auto g2(int) -> decltype(::delete ::new T(), char());
+
+template<class>
+auto g2(...) -> char(&)[2];
+
+struct C { };
+
+struct A {
+ virtual ~A() = 0;
+};
+
+struct D1 {
+ D1() = delete;
+};
+
+struct D2 {
+ ~D2() = delete;
+};
+
+static_assert(sizeof(g<void>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void()>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(g<A>(0)) == 2, "Ouch");
+static_assert(sizeof(g<D1>(0)) == 2, "Ouch");
+static_assert(sizeof(g<D2>(0)) == 2, "Ouch");
+static_assert(sizeof(g<int&>(0)) == 2, "Ouch");
+static_assert(sizeof(g<int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(g<void(&&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void(), void()>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void() const, void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(f<int, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f<C, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f<C, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f<int&, int&>(0)) == 2, "Ouch");
+static_assert(sizeof(f<int&&, int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void(&)(), void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f<void(&&)(), void(&&)()>(0)) == 2, "Ouch");
+
+static_assert(sizeof(g2<void>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void()>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<A>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<D1>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<D2>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<int&>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(g2<void(&&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void(), void()>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void() const, void() const>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<int, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<C, void>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<C, int>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<int&, int&>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<int&&, int&&>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void(&)(), void(&)()>(0)) == 2, "Ouch");
+static_assert(sizeof(f2<void(&&)(), void(&&)()>(0)) == 2, "Ouch");
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype41.C b/gcc/testsuite/g++.dg/cpp0x/decltype41.C
new file mode 100644
index 0000000..1439e15
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype41.C
@@ -0,0 +1,43 @@
+// Core 1273
+// { dg-do compile { target c++11 } }
+
+template <class T> struct C;
+template <class T> struct D;
+
+class A
+{
+ int i;
+ static int j;
+ friend struct C<int>;
+ friend struct D<int>;
+} a;
+
+class B
+{
+ int i;
+ static int j;
+ friend struct C<float>;
+ friend struct D<float>;
+} b;
+
+template <class T>
+struct C
+{
+ template <class U> decltype (a.i) f() { } // #1
+ template <class U> decltype (b.i) f() { } // #2
+};
+
+template <class T>
+struct D
+{
+ template <class U> decltype (A::j) f() { } // #1
+ template <class U> decltype (B::j) f() { } // #2
+};
+
+int main()
+{
+ C<int>().f<int>(); // calls #1
+ C<float>().f<float>(); // calls #2
+ D<int>().f<int>(); // calls #1
+ D<float>().f<float>(); // calls #2
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype42.C b/gcc/testsuite/g++.dg/cpp0x/decltype42.C
new file mode 100644
index 0000000..6c1aa43
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype42.C
@@ -0,0 +1,31 @@
+// PR c++/50545
+// { dg-do compile { target c++11 } }
+
+template< class T >
+T&& declval();
+
+// #1
+template< class T >
+auto f( int )
+ -> decltype( int{ declval<T>() } );
+
+// #2
+template< class >
+void f( ... );
+
+
+#define STATIC_ASSERT( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ )
+
+template< class T, class U >
+struct is_same {
+ static constexpr bool value = false;
+};
+
+template< class T >
+struct is_same<T, T> {
+ static constexpr bool value = true;
+};
+
+
+STATIC_ASSERT( is_same< decltype( f<int>(0) ), int >::value ); // OK; f<int>(0) calls #1.
+STATIC_ASSERT( is_same< decltype( f<int*>(0) ), void >::value ); // static assertion fails; f<int*>(0) should call #2, because int{ (int*)0 } is ill-formed, but calls #1.