📄 typeck2.c
字号:
/* Report error messages, build initializers, and perform some front-end optimizations for C++ compiler. Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc. Hacked by Michael Tiemann (tiemann@cygnus.com)This file is part of GNU CC.GNU CC is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU CC is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU CC; see the file COPYING. If not, write tothe Free Software Foundation, 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. *//* This file is part of the C++ front end. It contains routines to build C++ expressions given their operands, including computing the types of the result, C and C++ specific error checks, and some optimization. There are also routines to build RETURN_STMT nodes and CASE_STMT nodes, and to process initializations in declarations (since they work like a strange sort of assignment). */#include "config.h"#include "system.h"#include "tree.h"#include "cp-tree.h"#include "flags.h"#include "toplev.h"static tree process_init_constructor PROTO((tree, tree, tree *));static void ack PVPROTO ((const char *, ...)) ATTRIBUTE_PRINTF_1;extern int errorcount;extern int sorrycount;/* Print an error message stemming from an attempt to use BASETYPE as a base class for TYPE. */treeerror_not_base_type (basetype, type) tree basetype, type;{ if (TREE_CODE (basetype) == FUNCTION_DECL) basetype = DECL_CLASS_CONTEXT (basetype); cp_error ("type `%T' is not a base type for type `%T'", basetype, type); return error_mark_node;}treebinfo_or_else (parent_or_type, type) tree parent_or_type, type;{ tree binfo; if (TYPE_MAIN_VARIANT (parent_or_type) == TYPE_MAIN_VARIANT (type)) return TYPE_BINFO (parent_or_type); if ((binfo = get_binfo (parent_or_type, TYPE_MAIN_VARIANT (type), 0))) { if (binfo == error_mark_node) return NULL_TREE; return binfo; } error_not_base_type (parent_or_type, type); return NULL_TREE;}/* According to ARM $7.1.6, "A `const' object may be initialized, but its value may not be changed thereafter. Thus, we emit hard errors for these, rather than just pedwarns. If `SOFT' is 1, then we just pedwarn. (For example, conversions to references.) */voidreadonly_error (arg, string, soft) tree arg; const char *string; int soft;{ const char *fmt; void (*fn) PVPROTO ((const char *, ...)); if (soft) fn = cp_pedwarn; else fn = cp_error; if (TREE_CODE (arg) == COMPONENT_REF) { if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0)))) fmt = "%s of member `%D' in read-only structure"; else fmt = "%s of read-only member `%D'"; (*fn) (fmt, string, TREE_OPERAND (arg, 1)); } else if (TREE_CODE (arg) == VAR_DECL) { if (DECL_LANG_SPECIFIC (arg) && DECL_IN_AGGR_P (arg) && !TREE_STATIC (arg)) fmt = "%s of constant field `%D'"; else fmt = "%s of read-only variable `%D'"; (*fn) (fmt, string, arg); } else if (TREE_CODE (arg) == PARM_DECL) (*fn) ("%s of read-only parameter `%D'", string, arg); else if (TREE_CODE (arg) == INDIRECT_REF && TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0))) == REFERENCE_TYPE && (TREE_CODE (TREE_OPERAND (arg, 0)) == VAR_DECL || TREE_CODE (TREE_OPERAND (arg, 0)) == PARM_DECL)) (*fn) ("%s of read-only reference `%D'", string, TREE_OPERAND (arg, 0)); else if (TREE_CODE (arg) == RESULT_DECL) (*fn) ("%s of read-only named return value `%D'", string, arg); else if (TREE_CODE (arg) == FUNCTION_DECL) (*fn) ("%s of function `%D'", string, arg); else (*fn) ("%s of read-only location", string);}/* Print an error message for invalid use of a type which declares virtual functions which are not inheritable. */voidabstract_virtuals_error (decl, type) tree decl; tree type;{ tree u = CLASSTYPE_ABSTRACT_VIRTUALS (type); tree tu; if (decl) { if (TREE_CODE (decl) == RESULT_DECL) return; if (TREE_CODE (decl) == VAR_DECL) cp_error ("cannot declare variable `%D' to be of type `%T'", decl, type); else if (TREE_CODE (decl) == PARM_DECL) cp_error ("cannot declare parameter `%D' to be of type `%T'", decl, type); else if (TREE_CODE (decl) == FIELD_DECL) cp_error ("cannot declare field `%D' to be of type `%T'", decl, type); else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) cp_error ("invalid return type for method `%#D'", decl); else if (TREE_CODE (decl) == FUNCTION_DECL) cp_error ("invalid return type for function `%#D'", decl); } else cp_error ("cannot allocate an object of type `%T'", type); /* Only go through this once. */ if (TREE_PURPOSE (u) == NULL_TREE) { TREE_PURPOSE (u) = error_mark_node; error (" since the following virtual functions are abstract:"); for (tu = u; tu; tu = TREE_CHAIN (tu)) cp_error_at ("\t%#D", TREE_VALUE (tu)); } else cp_error (" since type `%T' has abstract virtual functions", type);}/* Print an error message for invalid use of a signature type. Signatures are treated similar to abstract classes here, they cannot be instantiated. */voidsignature_error (decl, type) tree decl; tree type;{ if (decl) { if (TREE_CODE (decl) == RESULT_DECL) return; if (TREE_CODE (decl) == VAR_DECL) cp_error ("cannot declare variable `%D' to be of signature type `%T'", decl, type); else if (TREE_CODE (decl) == PARM_DECL) cp_error ("cannot declare parameter `%D' to be of signature type `%T'", decl, type); else if (TREE_CODE (decl) == FIELD_DECL) cp_error ("cannot declare field `%D' to be of signature type `%T'", decl, type); else if (TREE_CODE (decl) == FUNCTION_DECL && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE) cp_error ("invalid return type for method `%#D'", decl); else if (TREE_CODE (decl) == FUNCTION_DECL) cp_error ("invalid return type for function `%#D'", decl); } else cp_error ("cannot allocate an object of signature type `%T'", type);}/* Print an error message for invalid use of an incomplete type. VALUE is the expression that was used (or 0 if that isn't known) and TYPE is the type that was invalid. */voidincomplete_type_error (value, type) tree value; tree type;{ /* Avoid duplicate error message. */ if (TREE_CODE (type) == ERROR_MARK) return;retry: /* We must print an error message. Be clever about what it says. */ switch (TREE_CODE (type)) { case RECORD_TYPE: case UNION_TYPE: case ENUMERAL_TYPE: cp_error ("invalid use of undefined type `%#T'", type); cp_error_at ("forward declaration of `%#T'", type); break; case VOID_TYPE: cp_error ("invalid use of void expression"); break; case ARRAY_TYPE: if (TYPE_DOMAIN (type)) { type = TREE_TYPE (type); goto retry; } cp_error ("invalid use of array with unspecified bounds"); break; case OFFSET_TYPE: bad_member: cp_error ("invalid use of member (did you forget the `&' ?)"); break; case TEMPLATE_TYPE_PARM: cp_error ("invalid use of template type parameter"); break; case UNKNOWN_TYPE: if (value && TREE_CODE (value) == COMPONENT_REF) goto bad_member; else if (value && TREE_CODE (value) == ADDR_EXPR) cp_error ("address of overloaded function with no contextual type information"); else if (value && TREE_CODE (value) == OVERLOAD) cp_error ("overloaded function with no contextual type information"); else cp_error ("insufficient contextual information to determine type"); break; default: my_friendly_abort (108); } if (value != 0 && (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL)) cp_error_at ("incomplete `%D' defined here", value);}/* Like error(), but don't call report_error_function(). */static voidack VPROTO ((const char *msg, ...)){#ifndef ANSI_PROTOTYPES const char *msg;#endif va_list ap; extern char * progname; VA_START (ap, msg);#ifndef ANSI_PROTOTYPES msg = va_arg (ap, const char *);#endif if (input_filename) fprintf (stderr, "%s:%d: ", input_filename, lineno); else fprintf (stderr, "%s: ", progname); vfprintf (stderr, msg, ap); va_end (ap); fprintf (stderr, "\n");} /* There are times when the compiler can get very confused, confused to the point of giving up by aborting, simply because of previous input errors. It is much better to have the user go back and correct those errors first, and see if it makes us happier, than it is to abort on him. This is because when one has a 10,000 line program, and the compiler comes back with ``core dump'', the user is left not knowing even where to begin to fix things and no place to even try and work around things. The parameter is to uniquely identify the problem to the user, so that they can say, I am having problem 59, and know that fix 7 will probably solve their problem. Or, we can document what problem 59 is, so they can understand how to work around it, should they ever run into it. We used to tell people to "fix the above error[s] and try recompiling the program" via a call to fatal, but that message tended to look silly. So instead, we just do the equivalent of a call to fatal in the same situation (call exit). We used to assign sequential numbers for the aborts; now we use an encoding of the date the abort was added, since that has more meaning when we only see the error message. */static int abortcount = 0;voidmy_friendly_abort (i) int i;{ /* if the previous error came through here, i.e. report_error_function ended up calling us again, don't just exit; we want a diagnostic of some kind. */ if (abortcount == 1) current_function_decl = NULL_TREE; else if (errorcount > 0 || sorrycount > 0) { if (abortcount > 1) { if (i == 0) ack ("Internal compiler error."); else ack ("Internal compiler error %d.", i); ack ("Please submit a full bug report."); ack ("See %s for instructions.", GCCBUGURL); } else error ("confused by earlier errors, bailing out"); exit (34); } ++abortcount; if (i == 0) error ("Internal compiler error."); else error ("Internal compiler error %d.", i); error ("Please submit a full bug report."); fatal ("See %s for instructions.", GCCBUGURL);}voidmy_friendly_assert (cond, where) int cond, where;{ if (cond == 0) my_friendly_abort (where);}/* Return nonzero if VALUE is a valid constant-valued expression for use in initializing a static variable; one that can be an element of a "constant" initializer. Return null_pointer_node if the value is absolute; if it is relocatable, return the variable that determines the relocation. We assume that VALUE has been folded as much as possible; therefore, we do not need to check for such things as arithmetic-combinations of integers. */treeinitializer_constant_valid_p (value, endtype) tree value; tree endtype;{ switch (TREE_CODE (value)) { case CONSTRUCTOR: if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE && TREE_CONSTANT (value)) return initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)), endtype); return TREE_STATIC (value) ? null_pointer_node : 0; case INTEGER_CST: case REAL_CST: case STRING_CST: case COMPLEX_CST: case PTRMEM_CST: return null_pointer_node; case ADDR_EXPR: return TREE_OPERAND (value, 0); case NON_LVALUE_EXPR: return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype); case CONVERT_EXPR: case NOP_EXPR: /* Allow conversions between pointer types. */ if (POINTER_TYPE_P (TREE_TYPE (value)) && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -