aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2009-11-21 01:33:56 -0500
committerJason Merrill <jason@gcc.gnu.org>2009-11-21 01:33:56 -0500
commitabd5730b2df531b752b1447e05f1c947f5ecdeb2 (patch)
tree7f4536668ed93e9f54f2a097d69e1d19bbdfd521
parent42a06e46ab05b7cf751579a50ee302a8ab6b9cae (diff)
downloadgcc-abd5730b2df531b752b1447e05f1c947f5ecdeb2.zip
gcc-abd5730b2df531b752b1447e05f1c947f5ecdeb2.tar.gz
gcc-abd5730b2df531b752b1447e05f1c947f5ecdeb2.tar.bz2
PR c++/9050, DR 147, DR 318
PR c++/9050, DR 147, DR 318 * parser.c (cp_parser_lookup_name): If the name matches the explicit class scope, we're naming the constructor. (cp_parser_constructor_declarator_p): Just use cp_parser_unqualified_id if we have a nested-name-specifier. (cp_parser_direct_declarator): Handle getting an overload set as a constructor declarator. (cp_parser_unqualified_id): Avoid looking up the constructor when naming the destructor. (cp_parser_diagnose_invalid_type_name): Give good diagnostic for improper use of constructor as template. * typeck.c (finish_class_member_access_expr): Give good diagnostic about calling constructor. * error.c (dump_aggr_type): Don't print A::A for injected-class-name. From-SVN: r154403
-rw-r--r--gcc/cp/ChangeLog18
-rw-r--r--gcc/cp/error.c9
-rw-r--r--gcc/cp/parser.c119
-rw-r--r--gcc/cp/typeck.c8
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/g++.dg/lookup/name-clash4.C2
-rw-r--r--gcc/testsuite/g++.dg/tc1/dr147.C4
-rw-r--r--gcc/testsuite/g++.dg/template/ctor9.C9
-rw-r--r--gcc/testsuite/g++.old-deja/g++.jason/temporary5.C8
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/ctor2.C2
10 files changed, 141 insertions, 47 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 520262e..b9f1cbe 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,21 @@
+2009-11-20 Jason Merrill <jason@redhat.com>
+
+ PR c++/9050, DR 147, DR 318
+ * parser.c (cp_parser_lookup_name): If the name matches the explicit
+ class scope, we're naming the constructor.
+ (cp_parser_constructor_declarator_p): Just use cp_parser_unqualified_id
+ if we have a nested-name-specifier.
+ (cp_parser_direct_declarator): Handle getting an overload set as a
+ constructor declarator.
+ (cp_parser_unqualified_id): Avoid looking up the constructor when
+ naming the destructor.
+ (cp_parser_diagnose_invalid_type_name): Give good
+ diagnostic for improper use of constructor as template.
+ * typeck.c (finish_class_member_access_expr): Give good diagnostic
+ about calling constructor.
+
+ * error.c (dump_aggr_type): Don't print A::A for injected-class-name.
+
2009-11-20 Simon Martin <simartin@users.sourceforge.net>
PR c++/38646
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index a424299..e0e5ae5 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -568,10 +568,11 @@ dump_aggr_type (tree t, int flags)
{
typdef = !DECL_ARTIFICIAL (name);
- if (typdef
- && ((flags & TFF_CHASE_TYPEDEF)
- || (!flag_pretty_templates && DECL_LANG_SPECIFIC (name)
- && DECL_TEMPLATE_INFO (name))))
+ if ((typdef
+ && ((flags & TFF_CHASE_TYPEDEF)
+ || (!flag_pretty_templates && DECL_LANG_SPECIFIC (name)
+ && DECL_TEMPLATE_INFO (name))))
+ || DECL_SELF_REFERENCE_P (name))
{
t = TYPE_MAIN_VARIANT (t);
name = TYPE_NAME (t);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 284d167..c7560a8 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2400,6 +2400,12 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser,
if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
error_at (location, "%qE in namespace %qE does not name a type",
id, parser->scope);
+ else if (CLASS_TYPE_P (parser->scope)
+ && constructor_name_p (id, parser->scope)
+ && cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+ /* A<T>::A<T>() */
+ error_at (location, "invalid use of constructor %<%T::%E%> as "
+ "template", parser->scope, id);
else if (TYPE_P (parser->scope)
&& dependent_scope_p (parser->scope))
error_at (location, "need %<typename%> before %<%T::%E%> because "
@@ -3890,7 +3896,7 @@ cp_parser_unqualified_id (cp_parser* parser,
if (scope
&& token->type == CPP_NAME
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
- == CPP_OPEN_PAREN)
+ != CPP_LESS)
&& constructor_name_p (token->u.value, scope))
{
cp_lexer_consume_token (parser->lexer);
@@ -3898,7 +3904,11 @@ cp_parser_unqualified_id (cp_parser* parser,
}
/* If there was an explicit qualification (S::~T), first look
- in the scope given by the qualification (i.e., S). */
+ in the scope given by the qualification (i.e., S).
+
+ Note: in the calls to cp_parser_class_name below we pretend that
+ the lookup had an explicit 'class' tag so that lookup finds the
+ injected-class-name rather than the constructor. */
done = false;
type_decl = NULL_TREE;
if (scope)
@@ -3907,7 +3917,7 @@ cp_parser_unqualified_id (cp_parser* parser,
type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
- none_type,
+ class_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
@@ -3925,7 +3935,7 @@ cp_parser_unqualified_id (cp_parser* parser,
= cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
- none_type,
+ class_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
@@ -3943,7 +3953,7 @@ cp_parser_unqualified_id (cp_parser* parser,
= cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
- none_type,
+ class_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
@@ -3962,7 +3972,7 @@ cp_parser_unqualified_id (cp_parser* parser,
= cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
- none_type,
+ class_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
@@ -14275,6 +14285,10 @@ cp_parser_direct_declarator (cp_parser* parser,
unqualified_name = constructor_name (class_type);
sfk = sfk_constructor;
}
+ else if (is_overloaded_fn (unqualified_name)
+ && DECL_CONSTRUCTOR_P (get_first_fn
+ (unqualified_name)))
+ sfk = sfk_constructor;
if (ctor_dtor_or_conv_p && sfk != sfk_none)
*ctor_dtor_or_conv_p = -1;
@@ -17969,6 +17983,26 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
lookup_member, we must enter the scope here. */
if (dependent_p)
pushed_scope = push_scope (parser->scope);
+
+ /* 3.4.3.1: In a lookup in which the constructor is an acceptable
+ lookup result and the nested-name-specifier nominates a class C:
+ * if the name specified after the nested-name-specifier, when
+ looked up in C, is the injected-class-name of C (Clause 9), or
+ * if the name specified after the nested-name-specifier is the
+ same as the identifier or the simple-template-id's template-
+ name in the last component of the nested-name-specifier,
+ the name is instead considered to name the constructor of
+ class C. [ Note: for example, the constructor is not an
+ acceptable lookup result in an elaborated-type-specifier so
+ the constructor would not be used in place of the
+ injected-class-name. --end note ] Such a constructor name
+ shall be used only in the declarator-id of a declaration that
+ names a constructor or in a using-declaration. */
+ if (tag_type == none_type
+ && CLASS_TYPE_P (parser->scope)
+ && constructor_name_p (name, parser->scope))
+ name = ctor_identifier;
+
/* If the PARSER->SCOPE is a template specialization, it
may be instantiated during name lookup. In that case,
errors may be issued. Even if we rollback the current
@@ -18320,8 +18354,7 @@ static bool
cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
{
bool constructor_p;
- tree type_decl = NULL_TREE;
- bool nested_name_p;
+ tree nested_name_specifier;
cp_token *next_token;
/* The common case is that this is not a constructor declarator, so
@@ -18347,34 +18380,48 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
/* Look for the nested-name-specifier. */
- nested_name_p
+ nested_name_specifier
= (cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/false,
/*check_dependency_p=*/false,
/*type_p=*/false,
- /*is_declaration=*/false)
- != NULL_TREE);
+ /*is_declaration=*/false));
/* Outside of a class-specifier, there must be a
nested-name-specifier. */
- if (!nested_name_p &&
+ if (!nested_name_specifier &&
(!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type)
|| friend_p))
constructor_p = false;
+ else if (nested_name_specifier == error_mark_node)
+ constructor_p = false;
+
+ /* If we have a class scope, this is easy; DR 147 says that S::S always
+ names the constructor, and no other qualified name could. */
+ if (constructor_p && nested_name_specifier
+ && TYPE_P (nested_name_specifier))
+ {
+ tree id = cp_parser_unqualified_id (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/false,
+ /*declarator_p=*/true,
+ /*optional_p=*/false);
+ if (is_overloaded_fn (id))
+ id = DECL_NAME (get_first_fn (id));
+ if (!constructor_name_p (id, nested_name_specifier))
+ constructor_p = false;
+ }
/* If we still think that this might be a constructor-declarator,
look for a class-name. */
- if (constructor_p)
+ else if (constructor_p)
{
/* If we have:
- template <typename T> struct S { S(); };
- template <typename T> S<T>::S ();
-
- we must recognize that the nested `S' names a class.
- Similarly, for:
+ template <typename T> struct S {
+ S();
+ };
- template <typename T> S<T>::S<T> ();
-
- we must recognize that the nested `S' names a template. */
+ we must recognize that the nested `S' names a class. */
+ tree type_decl;
type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
@@ -18384,22 +18431,23 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
/*is_declaration=*/false);
/* If there was no class-name, then this is not a constructor. */
constructor_p = !cp_parser_error_occurred (parser);
- }
- /* If we're still considering a constructor, we have to see a `(',
- to begin the parameter-declaration-clause, followed by either a
- `)', an `...', or a decl-specifier. We need to check for a
- type-specifier to avoid being fooled into thinking that:
+ /* If we're still considering a constructor, we have to see a `(',
+ to begin the parameter-declaration-clause, followed by either a
+ `)', an `...', or a decl-specifier. We need to check for a
+ type-specifier to avoid being fooled into thinking that:
- S::S (f) (int);
+ S (f) (int);
- is a constructor. (It is actually a function named `f' that
- takes one parameter (of type `int') and returns a value of type
- `S::S'. */
- if (constructor_p
- && cp_parser_require (parser, CPP_OPEN_PAREN, "%<(%>"))
- {
- if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
+ is a constructor. (It is actually a function named `f' that
+ takes one parameter (of type `int') and returns a value of type
+ `S'. */
+ if (constructor_p
+ && !cp_parser_require (parser, CPP_OPEN_PAREN, "%<(%>"))
+ constructor_p = false;
+
+ if (constructor_p
+ && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_ELLIPSIS)
/* A parameter declaration begins with a decl-specifier,
which is either the "attribute" keyword, a storage class
@@ -18454,8 +18502,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
constructor_p = !cp_parser_error_occurred (parser);
}
}
- else
- constructor_p = false;
+
/* We did not really want to consume any tokens. */
cp_parser_abort_tentative_parse (parser);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 8685530..307825f 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -2429,6 +2429,14 @@ finish_class_member_access_expr (tree object, tree name, bool template_p,
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE
|| TREE_CODE (name) == BIT_NOT_EXPR);
+ if (constructor_name_p (name, scope))
+ {
+ if (complain & tf_error)
+ error ("cannot call constructor %<%T::%D%> directly",
+ scope, name);
+ return error_mark_node;
+ }
+
/* Find the base of OBJECT_TYPE corresponding to SCOPE. */
access_path = lookup_base (object_type, scope, ba_check, NULL);
if (access_path == error_mark_node)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index bb722a7..0c06750 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,12 @@
+2009-11-20 Jason Merrill <jason@redhat.com>
+
+ PR c++/9050, DR 147, DR 318
+ * g++.dg/template/ctor9.C: New.
+ * g++.dg/tc1/dr147.C: Remove xfails.
+ * g++.dg/lookup/name-clash4.C: Adjust.
+ * g++.old-deja/g++.jason/temporary5.C: Adjust.
+ * g++.old-deja/g++.pt/ctor2.C: Adjust.
+
2009-11-21 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/42078
diff --git a/gcc/testsuite/g++.dg/lookup/name-clash4.C b/gcc/testsuite/g++.dg/lookup/name-clash4.C
index d4ff551..d6c6d97 100644
--- a/gcc/testsuite/g++.dg/lookup/name-clash4.C
+++ b/gcc/testsuite/g++.dg/lookup/name-clash4.C
@@ -9,4 +9,4 @@ struct A
template<int> struct A {}; // { dg-error "same name" }
};
-A::A<0> a; // { dg-error "not a template" }
+A::A<0> a; // { dg-error "not a template|invalid use of constructor" }
diff --git a/gcc/testsuite/g++.dg/tc1/dr147.C b/gcc/testsuite/g++.dg/tc1/dr147.C
index 26ac6a6..9c90d98 100644
--- a/gcc/testsuite/g++.dg/tc1/dr147.C
+++ b/gcc/testsuite/g++.dg/tc1/dr147.C
@@ -11,7 +11,7 @@ A::A() { }
B::B() { }
B::A ba;
-A::A a; // { dg-error "" "the injected-class-name can never be found through qualified lookup" { xfail *-*-* } }
+A::A a; // { dg-error "" "the injected-class-name can never be found through qualified lookup" }
}
@@ -26,6 +26,6 @@ template <class T> struct A {
template <class T2> A(T2);
static A x;
};
-template<> A<int>::A<int>(A<int>::x); // { dg-error "" "this is an invalid declaration of the constructor" { xfail *-*-* } }
+template<> A<int>::A<int>(A<int>::x); // { dg-error "" "this is an invalid declaration of the constructor" }
}
diff --git a/gcc/testsuite/g++.dg/template/ctor9.C b/gcc/testsuite/g++.dg/template/ctor9.C
new file mode 100644
index 0000000..819ca1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/ctor9.C
@@ -0,0 +1,9 @@
+// PR c++/9050, DR 147, 318
+
+struct Y
+{
+ template <typename T> Y (T);
+ template <typename T> void foo (T);
+};
+
+template <> Y::Y<int> (int) { }
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/temporary5.C b/gcc/testsuite/g++.old-deja/g++.jason/temporary5.C
index d233fa9..eef2e20 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/temporary5.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/temporary5.C
@@ -1,6 +1,6 @@
-// { dg-do run }
// PRMS Id: 6604
-// Bug: Scoped constructor call is not properly recognized as a functional cast
+// Old bug: Scoped constructor call is not properly recognized as a functional cast
+// But after DR 147 A::A() is a constructor call, not a functional cast.
int c;
@@ -12,6 +12,8 @@ struct A {
int main ()
{
- A::A();
+ A a;
+ a.A::A(); // { dg-error "" }
+ A::A(); // { dg-error "" }
return c;
}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C b/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C
index 46039ac..802c2a4 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ctor2.C
@@ -10,4 +10,4 @@ struct A {
template <class T>
A<T>::A<T>() // { dg-error "invalid use of constructor|qualified name" }
{
-}
+} // { dg-error "end of input" }