re PR c++/18001 (Badly formatted error message (quotation problem))

PR c++/18001
	* c-common.h (lvalue_use): Move here from c-ctypeck.c.
	(lvalue_or_else): Declare.
	* c-common.c (lvalue_or_else): Move here from c-typeck.c.
	* c-typeck.c (lvalue_use): Remove.
	(lvalue_or_else): Remove.

	PR c++/18556
	* toplev.c (check_global_declarations): Set DECL_IGNORED_P on
	unemitted variables with static storage duration.

	PR c++/18445
	* class.c (instantiate_type): Treat NON_DEPENDENT_EXPRs with
	unknown_type as non matching.  Tidy up.
	* pt.c (build_non_dependent_expr): Do not build a
	NON_DEPENDENT_EXPR for a VAR_DECL.

	PR c++/18001
	* cp-tree.h (lvalue_or_else): Remove declaration.
	* tree.c (lvalue_or_else): Remove.
	* typeck.c (build_unary_op): Adjust call to lvalue_or_else.
	(build_modify_expr): Likewise.

	PR c++/18625
	* decl.c (duplicate_decls): Return error_mark_node on error, as
	specified.

	PR c++/18466
	* decl.c (grokvardecl): Keep track of whether or not a there was
	explicit qualification.
	* name-lookup.c (set_decl_namespace): Complain about explicit
	qualification of a name within its own namespace.

	PR c++/18545
	* typeck.c (check_return_expr): Robustify.

	PR c++/18445
	* g++.dg/template/crash28.C: Likewise.

	PR c++/18001
	* g++.dg/expr/unary2.C: Adjust lvalue messages.
	* g++.dg/ext/lvaddr.C: Likewise.
	* g++.dg/opt/pr7503-3.C: Likewise.

	PR c++/18466
	* g++.dg/parse/qualified3.C: New test.
	* g++.old-deja/g++.other/friend7.C: Remove bogus qualification.

	PR c++/18545
	* g++.dg/expr/return1.C: New test.

From-SVN: r91301
This commit is contained in:
Mark Mitchell 2004-11-25 17:11:37 +00:00 committed by Mark Mitchell
parent 87c465f52c
commit 5ae9ba3e45
21 changed files with 231 additions and 129 deletions

View File

@ -1,3 +1,16 @@
2004-11-25 Mark Mitchell <mark@codesourcery.com>
PR c++/18001
* c-common.h (lvalue_use): Move here from c-ctypeck.c.
(lvalue_or_else): Declare.
* c-common.c (lvalue_or_else): Move here from c-typeck.c.
* c-typeck.c (lvalue_use): Remove.
(lvalue_or_else): Remove.
PR c++/18556
* toplev.c (check_global_declarations): Set DECL_IGNORED_P on
unemitted variables with static storage duration.
2004-11-25 Gerald Pfeifer <gerald@pfeifer.com>
* tree-cfg.c (tree_verify_flow_info): Do not terminate error()

View File

@ -5617,4 +5617,40 @@ fold_offsetof (tree expr)
return convert (size_type_node, fold_offsetof_1 (expr));
}
/* Return nonzero if REF is an lvalue valid for this language;
otherwise, print an error message and return zero. USE says
how the lvalue is being used and so selects the error message. */
int
lvalue_or_else (tree ref, enum lvalue_use use)
{
int win = lvalue_p (ref);
if (!win)
{
switch (use)
{
case lv_assign:
error ("invalid lvalue in assignment");
break;
case lv_increment:
error ("invalid lvalue in increment");
break;
case lv_decrement:
error ("invalid lvalue in decrement");
break;
case lv_addressof:
error ("invalid lvalue in unary %<&%>");
break;
case lv_asm:
error ("invalid lvalue in asm statement");
break;
default:
gcc_unreachable ();
}
}
return win;
}
#include "gt-c-common.h"

View File

@ -873,6 +873,19 @@ extern void verify_sequence_points (tree);
extern tree fold_offsetof (tree);
/* Places where an lvalue, or modifiable lvalue, may be required.
Used to select diagnostic messages in lvalue_or_else and
readonly_error. */
enum lvalue_use {
lv_assign,
lv_increment,
lv_decrement,
lv_addressof,
lv_asm
};
extern int lvalue_or_else (tree, enum lvalue_use);
/* In c-gimplify.c */
extern void c_genericize (tree);
extern int c_gimplify_expr (tree *, tree *, tree *);

View File

@ -44,17 +44,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tree-iterator.h"
#include "tree-gimple.h"
/* Places where an lvalue, or modifiable lvalue, may be required.
Used to select diagnostic messages in lvalue_or_else and
readonly_error. */
enum lvalue_use {
lv_assign,
lv_increment,
lv_decrement,
lv_addressof,
lv_asm
};
/* Possible cases of implicit bad conversions. Used to select
diagnostic messages in convert_for_assignment. */
enum impl_conv {
@ -109,7 +98,6 @@ static void add_pending_init (tree, tree);
static void set_nonincremental_init (void);
static void set_nonincremental_init_from_string (tree);
static tree find_init_member (tree);
static int lvalue_or_else (tree, enum lvalue_use);
static void readonly_error (tree, enum lvalue_use);
static void record_maybe_used_decl (tree);
@ -2714,43 +2702,6 @@ lvalue_p (tree ref)
return 0;
}
}
/* Return nonzero if REF is an lvalue valid for this language;
otherwise, print an error message and return zero. USE says
how the lvalue is being used and so selects the error message. */
static int
lvalue_or_else (tree ref, enum lvalue_use use)
{
int win = lvalue_p (ref);
if (!win)
{
switch (use)
{
case lv_assign:
error ("invalid lvalue in assignment");
break;
case lv_increment:
error ("invalid lvalue in increment");
break;
case lv_decrement:
error ("invalid lvalue in decrement");
break;
case lv_addressof:
error ("invalid lvalue in unary %<&%>");
break;
case lv_asm:
error ("invalid lvalue in asm statement");
break;
default:
gcc_unreachable ();
}
}
return win;
}
/* Give an error for storing in something that is 'const'. */

View File

@ -1,3 +1,30 @@
2004-11-25 Mark Mitchell <mark@codesourcery.com>
PR c++/18445
* class.c (instantiate_type): Treat NON_DEPENDENT_EXPRs with
unknown_type as non matching. Tidy up.
* pt.c (build_non_dependent_expr): Do not build a
NON_DEPENDENT_EXPR for a VAR_DECL.
PR c++/18001
* cp-tree.h (lvalue_or_else): Remove declaration.
* tree.c (lvalue_or_else): Remove.
* typeck.c (build_unary_op): Adjust call to lvalue_or_else.
(build_modify_expr): Likewise.
PR c++/18625
* decl.c (duplicate_decls): Return error_mark_node on error, as
specified.
PR c++/18466
* decl.c (grokvardecl): Keep track of whether or not a there was
explicit qualification.
* name-lookup.c (set_decl_namespace): Complain about explicit
qualification of a name within its own namespace.
PR c++/18545
* typeck.c (check_return_expr): Robustify.
2004-11-25 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
Friend class name lookup 3/n, PR c++/3332

View File

@ -5864,6 +5864,15 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t flags)
if (TREE_CODE (rhs) == BASELINK)
rhs = BASELINK_FUNCTIONS (rhs);
/* If we are in a template, and have a NON_DEPENDENT_EXPR, we cannot
deduce any type information. */
if (TREE_CODE (rhs) == NON_DEPENDENT_EXPR)
{
if (flags & tf_error)
error ("not enough type information");
return error_mark_node;
}
/* We don't overwrite rhs if it is an overloaded function.
Copying it would destroy the tree link. */
if (TREE_CODE (rhs) != OVERLOAD)
@ -5904,14 +5913,15 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t flags)
case COMPONENT_REF:
{
tree addr = instantiate_type (lhstype, TREE_OPERAND (rhs, 1), flags);
tree member = TREE_OPERAND (rhs, 1);
if (addr != error_mark_node
member = instantiate_type (lhstype, member, flags);
if (member != error_mark_node
&& TREE_SIDE_EFFECTS (TREE_OPERAND (rhs, 0)))
/* Do not lose object's side effects. */
addr = build2 (COMPOUND_EXPR, TREE_TYPE (addr),
TREE_OPERAND (rhs, 0), addr);
return addr;
return build2 (COMPOUND_EXPR, TREE_TYPE (member),
TREE_OPERAND (rhs, 0), member);
return member;
}
case OFFSET_REF:
@ -5943,12 +5953,6 @@ instantiate_type (tree lhstype, tree rhs, tsubst_flags_t flags)
/*template_only=*/false,
/*explicit_targs=*/NULL_TREE);
case TREE_LIST:
/* Now we should have a baselink. */
gcc_assert (BASELINK_P (rhs));
return instantiate_type (lhstype, BASELINK_FUNCTIONS (rhs), flags);
case CALL_EXPR:
/* This is too hard for now. */
gcc_unreachable ();

View File

@ -4186,7 +4186,6 @@ extern tree copy_binfo (tree, tree, tree,
tree *, int);
extern int member_p (tree);
extern cp_lvalue_kind real_lvalue_p (tree);
extern int lvalue_or_else (tree, const char *);
extern tree build_min (enum tree_code, tree, ...);
extern tree build_min_nt (enum tree_code, ...);
extern tree build_min_non_dep (enum tree_code, tree, ...);

View File

@ -1417,7 +1417,7 @@ duplicate_decls (tree newdecl, tree olddecl)
error ("conflicting declaration %q#D", newdecl);
cp_error_at ("%qD has a previous declaration as %q#D",
olddecl, olddecl);
return NULL_TREE;
return error_mark_node;
}
}
else if (TREE_CODE (newdecl) == FUNCTION_DECL
@ -5921,10 +5921,13 @@ grokvardecl (tree type,
tree scope)
{
tree decl;
tree explicit_scope;
gcc_assert (!name || TREE_CODE (name) == IDENTIFIER_NODE);
/* Compute the scope in which to place the variable. */
/* 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;
if (!scope)
{
/* An explicit "extern" specifier indicates a namespace-scope
@ -5949,8 +5952,8 @@ grokvardecl (tree type,
else
decl = build_decl (VAR_DECL, name, type);
if (scope && TREE_CODE (scope) == NAMESPACE_DECL)
set_decl_namespace (decl, scope, 0);
if (explicit_scope && TREE_CODE (explicit_scope) == NAMESPACE_DECL)
set_decl_namespace (decl, explicit_scope, 0);
else
DECL_CONTEXT (decl) = scope;

View File

@ -3114,42 +3114,46 @@ set_decl_namespace (tree decl, tree scope, bool friendp)
error ("declaration of %qD not in a namespace surrounding %qD",
decl, scope);
DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
if (scope != current_namespace)
/* Writing "int N::i" to declare a variable within "N" is invalid. */
if (scope == current_namespace)
{
/* See whether this has been declared in the namespace. */
old = namespace_binding (DECL_NAME (decl), scope);
if (!old)
/* No old declaration at all. */
goto complain;
/* A template can be explicitly specialized in any namespace. */
if (processing_explicit_instantiation)
return;
if (!is_overloaded_fn (decl))
/* Don't compare non-function decls with decls_match here,
since it can't check for the correct constness at this
point. pushdecl will find those errors later. */
return;
/* Since decl is a function, old should contain a function decl. */
if (!is_overloaded_fn (old))
goto complain;
if (processing_template_decl || processing_specialization)
/* We have not yet called push_template_decl to turn a
FUNCTION_DECL into a TEMPLATE_DECL, so the declarations
won't match. But, we'll check later, when we construct the
template. */
return;
if (is_overloaded_fn (old))
{
for (; old; old = OVL_NEXT (old))
if (decls_match (decl, OVL_CURRENT (old)))
return;
}
else
if (decls_match (decl, old))
if (at_namespace_scope_p ())
error ("explicit qualification in declaration of `%D'",
decl);
return;
}
/* See whether this has been declared in the namespace. */
old = namespace_binding (DECL_NAME (decl), scope);
if (!old)
/* No old declaration at all. */
goto complain;
/* A template can be explicitly specialized in any namespace. */
if (processing_explicit_instantiation)
return;
if (!is_overloaded_fn (decl))
/* Don't compare non-function decls with decls_match here, since
it can't check for the correct constness at this
point. pushdecl will find those errors later. */
return;
/* Since decl is a function, old should contain a function decl. */
if (!is_overloaded_fn (old))
goto complain;
if (processing_template_decl || processing_specialization)
/* We have not yet called push_template_decl to turn a
FUNCTION_DECL into a TEMPLATE_DECL, so the declarations won't
match. But, we'll check later, when we construct the
template. */
return;
if (is_overloaded_fn (old))
{
for (; old; old = OVL_NEXT (old))
if (decls_match (decl, OVL_CURRENT (old)))
return;
}
else
return;
else if (decls_match (decl, old))
return;
complain:
error ("%qD should have been declared inside %qD", decl, scope);
}

View File

@ -12296,6 +12296,9 @@ build_non_dependent_expr (tree expr)
|| TREE_CODE (inner_expr) == TEMPLATE_DECL
|| TREE_CODE (inner_expr) == TEMPLATE_ID_EXPR)
return expr;
/* There is no need to return a proxy for a variable. */
if (TREE_CODE (expr) == VAR_DECL)
return expr;
/* Preserve string constants; conversions from string constants to
"char *" are allowed, even though normally a "const char *"
cannot be used to initialize a "char *". */

View File

@ -215,20 +215,6 @@ lvalue_p (tree ref)
(lvalue_p_1 (ref, /*class rvalue ok*/ 1) != clk_none);
}
/* Return nonzero if REF is an lvalue valid for this language;
otherwise, print an error message and return zero. */
int
lvalue_or_else (tree ref, const char* string)
{
if (!lvalue_p (ref))
{
error ("non-lvalue in %s", string);
return 0;
}
return 1;
}
/* Build a TARGET_EXPR, initializing the DECL with the VALUE. */
static tree

View File

@ -3956,7 +3956,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
/* Complain about anything else that is not a true lvalue. */
if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement")))
? lv_increment : lv_decrement)))
return error_mark_node;
/* Forbid using -- on `bool'. */
@ -4100,7 +4100,7 @@ build_unary_op (enum tree_code code, tree xarg, int noconvert)
is an error. */
else if (TREE_CODE (argtype) != FUNCTION_TYPE
&& TREE_CODE (argtype) != METHOD_TYPE
&& !lvalue_or_else (arg, "unary %<&$>"))
&& !lvalue_or_else (arg, lv_addressof))
return error_mark_node;
if (argtype != error_mark_node)
@ -5294,7 +5294,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
case MAX_EXPR:
/* MIN_EXPR and MAX_EXPR are currently only permitted as lvalues,
when neither operand has side-effects. */
if (!lvalue_or_else (lhs, "assignment"))
if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))
@ -5322,7 +5322,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
/* Check this here to avoid odd errors when trying to convert
a throw to the type of the COND_EXPR. */
if (!lvalue_or_else (lhs, "assignment"))
if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
cond = build_conditional_expr
@ -5421,7 +5421,7 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
}
/* The left-hand side must be an lvalue. */
if (!lvalue_or_else (lhs, "assignment"))
if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
/* Warn about modifying something that is `const'. Don't warn if
@ -6230,6 +6230,15 @@ check_return_expr (tree retval)
/* Remember that this function did return a value. */
current_function_returns_value = 1;
/* Check for errnoneous operands -- but after giving ourselves a
chance to provide an error about returning a value from a void
function. */
if (error_operand_p (retval))
{
current_function_return_value = error_mark_node;
return error_mark_node;
}
/* Only operator new(...) throw(), can return NULL [expr.new/13]. */
if ((DECL_OVERLOADED_OPERATOR_P (current_function_decl) == NEW_EXPR
|| DECL_OVERLOADED_OPERATOR_P (current_function_decl) == VEC_NEW_EXPR)
@ -6305,8 +6314,8 @@ check_return_expr (tree retval)
/* We don't need to do any conversions when there's nothing being
returned. */
if (!retval || retval == error_mark_node)
return retval;
if (!retval)
return NULL_TREE;
/* Do any required conversions. */
if (retval == result || DECL_CONSTRUCTOR_P (current_function_decl))

View File

@ -1,3 +1,20 @@
2004-11-25 Mark Mitchell <mark@codesourcery.com>
PR c++/18445
* g++.dg/template/crash28.C: Likewise.
PR c++/18001
* g++.dg/expr/unary2.C: Adjust lvalue messages.
* g++.dg/ext/lvaddr.C: Likewise.
* g++.dg/opt/pr7503-3.C: Likewise.
PR c++/18466
* g++.dg/parse/qualified3.C: New test.
* g++.old-deja/g++.other/friend7.C: Remove bogus qualification.
PR c++/18545
* g++.dg/expr/return1.C: New test.
2004-11-25 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
Friend class name lookup 3/n, PR c++/3332

View File

@ -0,0 +1,9 @@
// PR c++/18545
struct A;
A foo() // { dg-error "" }
{
A a; // { dg-error "" }
return a;
}

View File

@ -8,13 +8,13 @@ int n;
void f(void)
{
-n = 0; // { dg-error "non-lvalue" }
+n = 0; // { dg-error "non-lvalue" }
-n = 0; // { dg-error "lvalue" }
+n = 0; // { dg-error "lvalue" }
}
template <int>
void g(void)
{
-n = 0; // { dg-error "non-lvalue" "" { xfail *-*-* } }
+n = 0; // { dg-error "non-lvalue" "" { xfail *-*-* } }
-n = 0; // { dg-error "lvalue" "" { xfail *-*-* } }
+n = 0; // { dg-error "lvalue" "" { xfail *-*-* } }
}

View File

@ -6,5 +6,5 @@
void f()
{
int n;
char* p = &(char) n; // { dg-error "non-lvalue" }
char* p = &(char) n; // { dg-error "lvalue" }
}

View File

@ -6,21 +6,21 @@ extern int A, B;
void test1()
{
(A++ <? B) = 0; // { dg-error "non-lvalue in assignment" }
(A++ <? B) = 0; // { dg-error "lvalue in assignment" }
}
void test2()
{
(A <? B++) = 0; // { dg-error "non-lvalue in assignment" }
(A <? B++) = 0; // { dg-error "lvalue in assignment" }
}
void test3()
{
(A++ >? B) = 0; // { dg-error "non-lvalue in assignment" }
(A++ >? B) = 0; // { dg-error "lvalue in assignment" }
}
void test4()
{
(A >? B++) = 0; // { dg-error "non-lvalue in assignment" }
(A >? B++) = 0; // { dg-error "lvalue in assignment" }
}

View File

@ -0,0 +1,8 @@
// PR c++/18466
int ::i; // { dg-error "" }
void ::f(); // { dg-error "" }
namespace N {
int N::j; // { dg-error "" }
void N::g(); // { dg-error "" }
}

View File

@ -0,0 +1,13 @@
// PR c++/18445
struct a
{
int what();
};
void g(void*);
template<class T>
void f()
{
a ex;
g(ex.what); // { dg-error "" }
}

View File

@ -15,7 +15,7 @@ class S {
};
}
void (::foo)(M::S *ptr) {
void (foo)(M::S *ptr) {
M::S::s.Fn();
ptr->Fn();
}

View File

@ -819,6 +819,13 @@ check_global_declarations (tree *vec, int len)
{
decl = vec[i];
/* Do not emit debug information about variables that are in
static storage, but not defined. */
if (TREE_CODE (decl) == VAR_DECL
&& TREE_STATIC (decl)
&& !TREE_ASM_WRITTEN (decl))
DECL_IGNORED_P (decl) = 1;
/* Warn about any function
declared static but not defined.
We don't warn about variables,