re PR c++/42137 (error: expected constructor, destructor, or type conversion before ‘{’ token)
PR c++/42137 * parser.c (cp_parser_mem_initializer_id): Pass typename_type to cp_parser_class_name. (cp_parser_unqualified_id): Same, rather than class_type. PR c++/11764 * parser.c (cp_parser_expression_statement): Give helpful error for constructor name used as type. From-SVN: r154519
This commit is contained in:
parent
3474a3b72b
commit
108e24453b
6 changed files with 72 additions and 22 deletions
|
@ -1,5 +1,14 @@
|
|||
2009-11-24 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/42137
|
||||
* parser.c (cp_parser_mem_initializer_id): Pass typename_type to
|
||||
cp_parser_class_name.
|
||||
(cp_parser_unqualified_id): Same, rather than class_type.
|
||||
|
||||
PR c++/11764
|
||||
* parser.c (cp_parser_expression_statement): Give helpful error
|
||||
for constructor name used as type.
|
||||
|
||||
* pt.c (determine_specialization): Give helpful error about missing
|
||||
"template<>".
|
||||
|
||||
|
|
|
@ -2401,11 +2401,15 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser,
|
|||
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);
|
||||
&& constructor_name_p (id, parser->scope))
|
||||
{
|
||||
/* A<T>::A<T>() */
|
||||
error_at (location, "%<%T::%E%> names the constructor, not"
|
||||
" the type", parser->scope, id);
|
||||
if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
|
||||
error_at (location, "and %qT has no template constructors",
|
||||
parser->scope);
|
||||
}
|
||||
else if (TYPE_P (parser->scope)
|
||||
&& dependent_scope_p (parser->scope))
|
||||
error_at (location, "need %<typename%> before %<%T::%E%> because "
|
||||
|
@ -3906,9 +3910,9 @@ 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).
|
||||
|
||||
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. */
|
||||
Note: in the calls to cp_parser_class_name below we pass
|
||||
typename_type so that lookup finds the injected-class-name
|
||||
rather than the constructor. */
|
||||
done = false;
|
||||
type_decl = NULL_TREE;
|
||||
if (scope)
|
||||
|
@ -3917,7 +3921,7 @@ cp_parser_unqualified_id (cp_parser* parser,
|
|||
type_decl = cp_parser_class_name (parser,
|
||||
/*typename_keyword_p=*/false,
|
||||
/*template_keyword_p=*/false,
|
||||
class_type,
|
||||
typename_type,
|
||||
/*check_dependency=*/false,
|
||||
/*class_head_p=*/false,
|
||||
declarator_p);
|
||||
|
@ -3935,7 +3939,7 @@ cp_parser_unqualified_id (cp_parser* parser,
|
|||
= cp_parser_class_name (parser,
|
||||
/*typename_keyword_p=*/false,
|
||||
/*template_keyword_p=*/false,
|
||||
class_type,
|
||||
typename_type,
|
||||
/*check_dependency=*/false,
|
||||
/*class_head_p=*/false,
|
||||
declarator_p);
|
||||
|
@ -3953,7 +3957,7 @@ cp_parser_unqualified_id (cp_parser* parser,
|
|||
= cp_parser_class_name (parser,
|
||||
/*typename_keyword_p=*/false,
|
||||
/*template_keyword_p=*/false,
|
||||
class_type,
|
||||
typename_type,
|
||||
/*check_dependency=*/false,
|
||||
/*class_head_p=*/false,
|
||||
declarator_p);
|
||||
|
@ -3972,7 +3976,7 @@ cp_parser_unqualified_id (cp_parser* parser,
|
|||
= cp_parser_class_name (parser,
|
||||
/*typename_keyword_p=*/false,
|
||||
/*template_keyword_p=*/false,
|
||||
class_type,
|
||||
typename_type,
|
||||
/*check_dependency=*/false,
|
||||
/*class_head_p=*/false,
|
||||
declarator_p);
|
||||
|
@ -7800,13 +7804,24 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
|
|||
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
|
||||
statement = cp_parser_expression (parser, /*cast_p=*/false, NULL);
|
||||
|
||||
/* Give a helpful message for "A<T>::type t;" */
|
||||
/* Give a helpful message for "A<T>::type t;" and the like. */
|
||||
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
|
||||
&& !cp_parser_uncommitted_to_tentative_parse_p (parser)
|
||||
&& TREE_CODE (statement) == SCOPE_REF)
|
||||
error_at (token->location, "need %<typename%> before %qE because "
|
||||
"%qT is a dependent scope",
|
||||
statement, TREE_OPERAND (statement, 0));
|
||||
&& !cp_parser_uncommitted_to_tentative_parse_p (parser))
|
||||
{
|
||||
if (TREE_CODE (statement) == SCOPE_REF)
|
||||
error_at (token->location, "need %<typename%> before %qE because "
|
||||
"%qT is a dependent scope",
|
||||
statement, TREE_OPERAND (statement, 0));
|
||||
else if (is_overloaded_fn (statement)
|
||||
&& DECL_CONSTRUCTOR_P (get_first_fn (statement)))
|
||||
{
|
||||
/* A::A a; */
|
||||
tree fn = get_first_fn (statement);
|
||||
error_at (token->location,
|
||||
"%<%T::%D%> names the constructor, not the type",
|
||||
DECL_CONTEXT (fn), DECL_NAME (fn));
|
||||
}
|
||||
}
|
||||
|
||||
/* Consume the final `;'. */
|
||||
cp_parser_consume_semicolon_at_end_of_statement (parser);
|
||||
|
@ -10020,7 +10035,7 @@ cp_parser_mem_initializer_id (cp_parser* parser)
|
|||
return cp_parser_class_name (parser,
|
||||
/*typename_keyword_p=*/true,
|
||||
/*template_keyword_p=*/template_p,
|
||||
none_type,
|
||||
typename_type,
|
||||
/*check_dependency_p=*/true,
|
||||
/*class_head_p=*/false,
|
||||
/*is_declaration=*/true);
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2009-11-23 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* g++.dg/tc1/dr147.C: Check for helpful messages. Add DR 318 tests.
|
||||
* g++.old-deja/g++.pt/ctor2.C: Adjust.
|
||||
* g++.dg/lookup/name-clash4.C: Adjust.
|
||||
|
||||
2009-11-23 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* g++.dg/template/spec15.C: Check for helpful message.
|
||||
|
|
|
@ -9,4 +9,4 @@ struct A
|
|||
template<int> struct A {}; // { dg-error "same name" }
|
||||
};
|
||||
|
||||
A::A<0> a; // { dg-error "not a template|invalid use of constructor" }
|
||||
A::A<0> a; // { dg-error "not a template|constructor" }
|
||||
|
|
|
@ -11,8 +11,12 @@ A::A() { }
|
|||
B::B() { }
|
||||
|
||||
B::A ba;
|
||||
A::A a; // { dg-error "" "the injected-class-name can never be found through qualified lookup" }
|
||||
A::A a; // { dg-error "constructor" "the injected-class-name can never be found through qualified lookup" }
|
||||
|
||||
void f()
|
||||
{
|
||||
A::A a; // { dg-error "constructor" }
|
||||
} // { dg-error "" "" { target *-*-* } 18 } error cascade
|
||||
}
|
||||
|
||||
namespace N2 {
|
||||
|
@ -26,6 +30,22 @@ template <class T> struct A {
|
|||
template <class T2> A(T2);
|
||||
static A x;
|
||||
};
|
||||
template<> template <> A<char>::A<char>(char);
|
||||
template<> A<int>::A<int>(A<int>::x); // { dg-error "" "this is an invalid declaration of the constructor" }
|
||||
|
||||
}
|
||||
|
||||
// But DR 318 says that in situations where a type is syntactically
|
||||
// required, lookup finds it.
|
||||
|
||||
struct C
|
||||
{
|
||||
C();
|
||||
typedef int T;
|
||||
};
|
||||
struct C::C c;
|
||||
C::C::T t;
|
||||
struct D: C::C
|
||||
{
|
||||
D(): C::C() { }
|
||||
};
|
||||
|
|
|
@ -8,6 +8,6 @@ struct A {
|
|||
};
|
||||
|
||||
template <class T>
|
||||
A<T>::A<T>() // { dg-error "invalid use of constructor|qualified name" }
|
||||
A<T>::A<T>() // { dg-error "constructor|qualified name" }
|
||||
{
|
||||
} // { dg-error "end of input" }
|
||||
|
|
Loading…
Add table
Reference in a new issue