/* Macro expansion. */
+static cpp_macro *get_deferred_or_lazy_macro (cpp_reader *, cpp_hashnode *,
+ location_t);
static int enter_macro_context (cpp_reader *, cpp_hashnode *,
const cpp_token *, location_t);
static int builtin_macro (cpp_reader *, cpp_hashnode *,
/* #define directive parsing and handling. */
static cpp_macro *lex_expansion_token (cpp_reader *, cpp_macro *);
-static bool warn_of_redefinition (cpp_reader *, cpp_hashnode *,
- const cpp_macro *);
-static bool compare_macros (const cpp_macro *, const cpp_macro *);
-
static bool parse_params (cpp_reader *, unsigned *, bool *);
static void check_trad_stringification (cpp_reader *, const cpp_macro *,
const cpp_string *);
static cpp_hashnode* macro_of_context (cpp_context *context);
-static bool in_macro_expansion_p (cpp_reader *pfile);
-
/* Statistical counter tracking the number of macros that got
expanded. */
unsigned num_expanded_macros_counter = 0;
(c) we are not in strictly conforming mode, then it has the
value 0. (b) and (c) are already checked in cpp_init_builtins. */
case BT_STDC:
- if (cpp_in_system_header (pfile))
+ if (_cpp_in_system_header (pfile))
number = 0;
else
number = 1;
break;
case BT_HAS_ATTRIBUTE:
- number = pfile->cb.has_attribute (pfile);
+ number = pfile->cb.has_attribute (pfile, false);
+ break;
+
+ case BT_HAS_STD_ATTRIBUTE:
+ number = pfile->cb.has_attribute (pfile, true);
break;
case BT_HAS_BUILTIN:
= (const cpp_token **) tokens_buff_last_token_ptr (buff);
}
else if (CPP_PEDANTIC (pfile) && ! CPP_OPTION (pfile, c99)
- && ! macro->syshdr && ! cpp_in_system_header (pfile))
+ && ! macro->syshdr && ! _cpp_in_system_header (pfile))
{
if (CPP_OPTION (pfile, cplusplus))
cpp_pedwarning (pfile, CPP_W_PEDANTIC,
}
else if (CPP_OPTION (pfile, cpp_warn_c90_c99_compat) > 0
&& ! CPP_OPTION (pfile, cplusplus)
- && ! macro->syshdr && ! cpp_in_system_header (pfile))
+ && ! macro->syshdr && ! _cpp_in_system_header (pfile))
cpp_warning (pfile, CPP_W_C90_C99_COMPAT,
"invoking macro %s argument %d: "
"empty macro arguments are undefined"
if (node->type == NT_VOID || (result->flags & NO_EXPAND))
break;
+ if (!(node->flags & NODE_USED)
+ && node->type == NT_USER_MACRO
+ && !node->value.macro
+ && !cpp_get_deferred_macro (pfile, node, result->src_loc))
+ break;
+
if (!(node->flags & NODE_DISABLED))
{
int ret = 0;
}
pfile->about_to_expand_macro_p = saved_about_to_expand_macro;
+
+ if (pfile->state.directive_file_token
+ && !pfile->state.parsing_args
+ && !(result->type == CPP_PADDING || result->type == CPP_COMMENT)
+ && !(15 & --pfile->state.directive_file_token))
+ {
+ /* Do header-name frobbery. Concatenate < ... > as approprate.
+ Do header search if needed, and finally drop the outer <> or
+ "". */
+ pfile->state.angled_headers = false;
+
+ /* Do angle-header reconstitution. Then do include searching.
+ We'll always end up with a ""-quoted header-name in that
+ case. If searching finds nothing, we emit a diagnostic and
+ an empty string. */
+ size_t len = 0;
+ char *fname = NULL;
+
+ cpp_token *tmp = _cpp_temp_token (pfile);
+ *tmp = *result;
+
+ tmp->type = CPP_HEADER_NAME;
+ bool need_search = !pfile->state.directive_file_token;
+ pfile->state.directive_file_token = 0;
+
+ bool angle = result->type != CPP_STRING;
+ if (result->type == CPP_HEADER_NAME
+ || (result->type == CPP_STRING && result->val.str.text[0] != 'R'))
+ {
+ len = result->val.str.len - 2;
+ fname = XNEWVEC (char, len + 1);
+ memcpy (fname, result->val.str.text + 1, len);
+ fname[len] = 0;
+ }
+ else if (result->type == CPP_LESS)
+ fname = _cpp_bracket_include (pfile);
+
+ if (fname)
+ {
+ /* We have a header-name. Look it up. This will emit an
+ unfound diagnostic. Canonicalize the found name. */
+ const char *found = fname;
+
+ if (need_search)
+ {
+ found = cpp_find_header_unit (pfile, fname, angle, tmp->src_loc);
+ if (!found)
+ found = "";
+ len = strlen (found);
+ }
+ /* Force a leading './' if it's not absolute. */
+ bool dotme = (found[0] == '.' ? !IS_DIR_SEPARATOR (found[1])
+ : found[0] && !IS_ABSOLUTE_PATH (found));
+
+ if (BUFF_ROOM (pfile->u_buff) < len + 1 + dotme * 2)
+ _cpp_extend_buff (pfile, &pfile->u_buff, len + 1 + dotme * 2);
+ unsigned char *buf = BUFF_FRONT (pfile->u_buff);
+ size_t pos = 0;
+
+ if (dotme)
+ {
+ buf[pos++] = '.';
+ /* Apparently '/' is unconditional. */
+ buf[pos++] = '/';
+ }
+ memcpy (&buf[pos], found, len);
+ pos += len;
+ buf[pos] = 0;
+
+ tmp->val.str.len = pos;
+ tmp->val.str.text = buf;
+
+ tmp->type = CPP_HEADER_NAME;
+ XDELETEVEC (fname);
+
+ result = tmp;
+ }
+ }
+
return result;
}
if (node->flags & NODE_CONDITIONAL)
return false;
- cpp_macro *macro1 = node->value.macro;
- if (macro1->lazy)
- {
- /* We don't want to mark MACRO as used, but do need to finalize
- its laziness. */
- pfile->cb.user_lazy_macro (pfile, macro1, macro1->lazy - 1);
- macro1->lazy = 0;
- }
-
- return compare_macros (macro1, macro2);
+ if (cpp_macro *macro1 = get_deferred_or_lazy_macro (pfile, node, macro2->line))
+ return cpp_compare_macros (macro1, macro2);
+ return false;
}
/* Return TRUE if MACRO1 and MACRO2 differ. */
-static bool
-compare_macros (const cpp_macro *macro1, const cpp_macro *macro2)
+bool
+cpp_compare_macros (const cpp_macro *macro1, const cpp_macro *macro2)
{
/* Redefinition of a macro is allowed if and only if the old and new
definitions are the same. (6.10.3 paragraph 2). */
macro->lazy = num + 1;
}
+/* NODE is a deferred macro, resolve it, returning the definition
+ (which may be NULL). */
+cpp_macro *
+cpp_get_deferred_macro (cpp_reader *pfile, cpp_hashnode *node,
+ location_t loc)
+{
+ node->value.macro = pfile->cb.user_deferred_macro (pfile, loc, node);
+
+ if (!node->value.macro)
+ node->type = NT_VOID;
+
+ return node->value.macro;
+}
+
+static cpp_macro *
+get_deferred_or_lazy_macro (cpp_reader *pfile, cpp_hashnode *node,
+ location_t loc)
+{
+ cpp_macro *macro = node->value.macro;
+ if (!macro)
+ {
+ macro = cpp_get_deferred_macro (pfile, node, loc);
+ if (!macro)
+ return NULL;
+ }
+
+ if (macro->lazy)
+ {
+ pfile->cb.user_lazy_macro (pfile, macro, macro->lazy - 1);
+ macro->lazy = 0;
+ }
+
+ return macro;
+}
+
/* Notify the use of NODE in a macro-aware context (i.e. expanding it,
or testing its existance). Also applies any lazy definition.
Return FALSE if the macro isn't really there. */
-extern void
+extern bool
_cpp_notify_macro_use (cpp_reader *pfile, cpp_hashnode *node,
location_t loc)
{
switch (node->type)
{
case NT_USER_MACRO:
- {
- cpp_macro *macro = node->value.macro;
- if (macro->lazy)
- {
- pfile->cb.user_lazy_macro (pfile, macro, macro->lazy - 1);
- macro->lazy = 0;
- }
- }
+ if (!get_deferred_or_lazy_macro (pfile, node, loc))
+ return false;
/* FALLTHROUGH. */
case NT_BUILTIN_MACRO:
default:
abort ();
}
+
+ return true;
}
/* Warn if a token in STRING matches one of a function-like MACRO's
const unsigned char *
cpp_macro_definition (cpp_reader *pfile, cpp_hashnode *node)
{
- unsigned int i, len;
- unsigned char *buffer;
-
gcc_checking_assert (cpp_user_macro_p (node));
- const cpp_macro *macro = node->value.macro;
+ if (const cpp_macro *macro = get_deferred_or_lazy_macro (pfile, node, 0))
+ return cpp_macro_definition (pfile, node, macro);
+ return NULL;
+}
+
+const unsigned char *
+cpp_macro_definition (cpp_reader *pfile, cpp_hashnode *node,
+ const cpp_macro *macro)
+{
+ unsigned int i, len;
+ unsigned char *buffer;
/* Calculate length. */
len = NODE_LEN (node) * 10 + 2; /* ' ' and NUL. */