aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/c-common.c36
-rw-r--r--gcc/c-common.h13
-rw-r--r--gcc/c-typeck.c49
-rw-r--r--gcc/cp/ChangeLog27
-rw-r--r--gcc/cp/class.c26
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/decl.c11
-rw-r--r--gcc/cp/name-lookup.c72
-rw-r--r--gcc/cp/pt.c3
-rw-r--r--gcc/cp/tree.c14
-rw-r--r--gcc/cp/typeck.c23
-rw-r--r--gcc/testsuite/ChangeLog17
-rw-r--r--gcc/testsuite/g++.dg/expr/return1.C9
-rw-r--r--gcc/testsuite/g++.dg/expr/unary2.C8
-rw-r--r--gcc/testsuite/g++.dg/ext/lvaddr.C2
-rw-r--r--gcc/testsuite/g++.dg/opt/pr7503-3.C8
-rw-r--r--gcc/testsuite/g++.dg/parse/qualified3.C8
-rw-r--r--gcc/testsuite/g++.dg/template/crash28.C13
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/friend7.C2
-rw-r--r--gcc/toplev.c7
21 files changed, 232 insertions, 130 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a8cdba2..0f8ebea 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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()
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 81bdbbf..bfefeb2 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -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"
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 63c095c..d0fbaa8 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -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 *);
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index c540104..23ff80e 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -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'. */
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e79b20e..6a8aea8 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index e146abc..3db223a 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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 ();
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 0f0bfb2..f6da43c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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, ...);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 98ca4f9..2085a57 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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;
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index aa5e5d2..14c94a8 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -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)
- {
- /* 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))
- return;
+
+ /* Writing "int N::i" to declare a variable within "N" is invalid. */
+ if (scope == current_namespace)
+ {
+ if (at_namespace_scope_p ())
+ error ("explicit qualification in declaration of `%D'",
+ decl);
+ return;
}
- else
+
+ /* 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))
+ return;
complain:
error ("%qD should have been declared inside %qD", decl, scope);
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b514cc1..cc11f36 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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 *". */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 82aebe4..a4b470e 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 60f03c9..149a388 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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))
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 934cb9a..dc9628f 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/expr/return1.C b/gcc/testsuite/g++.dg/expr/return1.C
new file mode 100644
index 0000000..7a64988
--- /dev/null
+++ b/gcc/testsuite/g++.dg/expr/return1.C
@@ -0,0 +1,9 @@
+// PR c++/18545
+
+struct A;
+
+A foo() // { dg-error "" }
+{
+ A a; // { dg-error "" }
+ return a;
+}
diff --git a/gcc/testsuite/g++.dg/expr/unary2.C b/gcc/testsuite/g++.dg/expr/unary2.C
index 9d6acc8..8418815 100644
--- a/gcc/testsuite/g++.dg/expr/unary2.C
+++ b/gcc/testsuite/g++.dg/expr/unary2.C
@@ -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 *-*-* } }
}
diff --git a/gcc/testsuite/g++.dg/ext/lvaddr.C b/gcc/testsuite/g++.dg/ext/lvaddr.C
index 184afce..5b217d1 100644
--- a/gcc/testsuite/g++.dg/ext/lvaddr.C
+++ b/gcc/testsuite/g++.dg/ext/lvaddr.C
@@ -6,5 +6,5 @@
void f()
{
int n;
- char* p = &(char) n; // { dg-error "non-lvalue" }
+ char* p = &(char) n; // { dg-error "lvalue" }
}
diff --git a/gcc/testsuite/g++.dg/opt/pr7503-3.C b/gcc/testsuite/g++.dg/opt/pr7503-3.C
index ed223f4..34d91dd 100644
--- a/gcc/testsuite/g++.dg/opt/pr7503-3.C
+++ b/gcc/testsuite/g++.dg/opt/pr7503-3.C
@@ -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" }
}
diff --git a/gcc/testsuite/g++.dg/parse/qualified3.C b/gcc/testsuite/g++.dg/parse/qualified3.C
new file mode 100644
index 0000000..ab160ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/qualified3.C
@@ -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 "" }
+}
diff --git a/gcc/testsuite/g++.dg/template/crash28.C b/gcc/testsuite/g++.dg/template/crash28.C
new file mode 100644
index 0000000..e8b2bbb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/crash28.C
@@ -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 "" }
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/friend7.C b/gcc/testsuite/g++.old-deja/g++.other/friend7.C
index 1055d99..aed56a1 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/friend7.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/friend7.C
@@ -15,7 +15,7 @@ class S {
};
}
-void (::foo)(M::S *ptr) {
+void (foo)(M::S *ptr) {
M::S::s.Fn();
ptr->Fn();
}
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 29ae065..e2efecd 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -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,