https://gcc.gnu.org/g:f60bb700835b8548f6f402297388589462e22f8f
commit f60bb700835b8548f6f402297388589462e22f8f Author: Iain Buclaw <ibuc...@gdcproject.org> Date: Tue May 24 23:03:23 2022 +0200 d: Implement preprocessor for importC gcc/ChangeLog: * config/darwin-d.cc (darwin_register_objc_includes): New function. (darwin_register_frameworks): New function. gcc/d/ChangeLog: * Make-lang.in (D_OBJS): Add d/d-preprocess.o. * d-builtins.cc (covariant_with_builtin_type_p): Match va_list parameters converted from array to pointer. * d-lang.cc (d_init_options): Initialize global.preprocess and importC preprocessor. (d_handle_option): Call d_cpp_handle_option. * d-tree.h (struct OutBuffer): Add opaque declaration. (d_cpp_init_options): Add prototype. (d_cpp_handle_option): Add prototype. (d_cpp_preprocess): Add prototype. * lang-specs.h: Forward -D and -U to compiler proper. * lang.opt: Add -D, -U, -dirafter, -imacros, -include, and -iquote. * d-preprocess.cc: New file. Diff: --- gcc/config/darwin-d.cc | 35 +++ gcc/d/Make-lang.in | 1 + gcc/d/d-builtins.cc | 12 +- gcc/d/d-lang.cc | 15 +- gcc/d/d-preprocess.cc | 755 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/d/d-tree.h | 7 + gcc/d/lang-specs.h | 2 +- gcc/d/lang.opt | 24 ++ 8 files changed, 848 insertions(+), 3 deletions(-) diff --git a/gcc/config/darwin-d.cc b/gcc/config/darwin-d.cc index e23a6cd12708..0afb3d281136 100644 --- a/gcc/config/darwin-d.cc +++ b/gcc/config/darwin-d.cc @@ -74,3 +74,38 @@ darwin_d_register_target_info (void) #define TARGET_D_MINFO_SECTION_END "*section$end$__DATA$__minfodata" struct gcc_targetdm targetdm = TARGETDM_INITIALIZER; + +/* Provide stubs for the hooks defined by darwin.h + TARGET_EXTRA_PRE_INCLUDES, TARGET_EXTRA_INCLUDES + + As both, gcc and gdc link in incpath.o, we cannot conditionally undefine said + hooks if D is build. However, we can define do-nothing stubs of said hooks + as we are not interested in objc include files in D. + + The hooks original purpose (see also darwin-c.cc): + * darwin_register_objc_includes + Register the GNU objective-C runtime include path if STDINC. + + * darwin_register_frameworks + Register all the system framework paths if STDINC is true and setup + the missing_header callback for subframework searching if any + frameworks had been registered. */ + +/* Prototypes for functions below to avoid a lengthy list of includes + to achieve the same. */ +void darwin_register_objc_includes (const char *, const char *, int); +void darwin_register_frameworks (const char *, const char *, int); + +void +darwin_register_objc_includes (const char *sysroot ATTRIBUTE_UNUSED, + const char *iprefix ATTRIBUTE_UNUSED, + int stdinc ATTRIBUTE_UNUSED) +{ +} + +void +darwin_register_frameworks (const char *sysroot ATTRIBUTE_UNUSED, + const char *iprefix ATTRIBUTE_UNUSED, + int stdinc ATTRIBUTE_UNUSED) +{ +} diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index 2d444c999530..0292f6e4ccf2 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -225,6 +225,7 @@ D_OBJS = \ d/d-lang.o \ d/d-longdouble.o \ d/d-port.o \ + d/d-preprocess.o \ d/d-target.o \ d/decl.o \ d/expr.o \ diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 9c146459d574..1ed0f0577236 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -758,7 +758,17 @@ covariant_with_builtin_type_p (Type *t1, Type *t2) || fparam1->isLazy () != fparam2->isLazy ()) return false; - if (!matches_builtin_type (fparam1->type, fparam2->type)) + /* va_list array parameters are implicitly converted to pointers. */ + Type *fptype1 = fparam1->type; + Type *fptype2 = fparam2->type; + + if (valist_array_p (fptype1)) + fptype1 = dmd::pointerTo (fptype1->nextOf ()); + + if (valist_array_p (fptype2)) + fptype2 = dmd::pointerTo (fptype2->nextOf ()); + + if (!matches_builtin_type (fptype1, fptype2)) return false; } diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index ec2ea59938c4..b88748d547e6 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -285,7 +285,8 @@ deps_write (Module *module, obstack *buffer) the option handlers. */ static void -d_init_options (unsigned int, cl_decoded_option *decoded_options) +d_init_options (unsigned int decoded_options_count, + cl_decoded_option *decoded_options) { /* Initialize the D runtime. */ rt_init (); @@ -300,6 +301,8 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options) /* Default extern(C++) mangling to C++17. */ global.params.cplusplus = CppStdRevisionCpp17; + global.preprocess = &d_cpp_preprocess; + /* Warnings and deprecations are disabled by default. */ global.params.useDeprecated = DIAGNOSTICinform; global.params.useWarnings = DIAGNOSTICoff; @@ -317,6 +320,9 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options) d_option.deps_target = vNULL; d_option.deps_phony = false; d_option.stdinc = true; + + /* Initialize CPP-related options. */ + d_cpp_init_options (decoded_options_count); } /* Implements the lang_hooks.init_options_struct routine for language D. @@ -808,6 +814,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; default: + if (cl_options[code].flags & d_option_lang_mask ()) + break; + + result = false; break; } @@ -816,6 +826,9 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, d_option_lang_mask (), kind, loc, handlers, global_dc); + if (d_cpp_handle_option (scode, arg)) + return true; + return result; } diff --git a/gcc/d/d-preprocess.cc b/gcc/d/d-preprocess.cc new file mode 100644 index 000000000000..79ef803b6cf8 --- /dev/null +++ b/gcc/d/d-preprocess.cc @@ -0,0 +1,755 @@ +/* d-preprocess.cc -- D frontend interface to cpplib. + Copyright (C) 2024 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" + +#include "dmd/root/dcompat.h" +#include "dmd/root/filename.h" +#include "dmd/errors.h" +#include "dmd/globals.h" + +#include "cpplib.h" +#include "cppbuiltin.h" +#include "tree.h" +#include "memmodel.h" +#include "diagnostic.h" +#include "target.h" +#include "tm_p.h" +#include "incpath.h" + +#include "d-tree.h" + +#ifndef TARGET_SYSTEM_ROOT +# define TARGET_SYSTEM_ROOT NULL +#endif + +/* Holds switches parsed by d_cpp_handle_option (), but whose + handling is deferred to d_cpp_preprocess (). */ +typedef struct +{ + opt_code code; + const char *arg; +} +d_cpp_deferred_opt_t; + +/* Options handled by the compiler that are passed to cpplib. */ +struct d_cpp_option_data +{ + const char *multilib; /* -imultilib <dir> */ + const char *prefix; /* -iprefix <dir> */ + const char *sysroot; /* -isysroot <dir> */ + + bool stdinc; /* -nostdinc */ + bool verbose; /* -v */ + + /* Options whose handling is deferred until after cpplib is initialized. */ + d_cpp_deferred_opt_t *deferred_opt; + int deferred_opt_count; +} +d_cpp_option; + +/* Buffer to write preprocessed content to. */ +static obstack d_cpp_buffer; + +/* The first object on d_cpp_buffer, used to free memory. */ +static void *d_cpp_buffer_base; + +/* A hash table of macros that have been #defined. */ +struct cpp_hashnode_hasher : nofree_ptr_hash <cpp_hashnode> +{ + static hashval_t hash (cpp_hashnode *node) + { + return node->ident.hash_value; + } + + static bool equal (cpp_hashnode *node1, cpp_hashnode *node2) + { + return node1->ident.hash_value == node2->ident.hash_value; + } +}; + +static hash_table <cpp_hashnode_hasher> *d_cpp_macros; + +/* Callback routines for the parser. */ + +static void +cb_define (cpp_reader *, location_t, cpp_hashnode *node) +{ + cpp_hashnode **slot = d_cpp_macros->find_slot (node, NO_INSERT); + + if (slot == NULL) + { + slot = d_cpp_macros->find_slot (node, INSERT); + gcc_assert (slot != NULL && *slot == NULL); + } + + *slot = node; +} + +static void +cb_undef (cpp_reader *, location_t, cpp_hashnode *node) +{ + if (cpp_hashnode **slot = d_cpp_macros->find_slot (node, NO_INSERT)) + d_cpp_macros->clear_slot (slot); +} + +/* Called when a line of output is started. TOKEN is the first token + of the line, and at end of file will be CPP_EOF. */ + +static void +cb_line_change (cpp_reader *, const cpp_token *token, int parsing_args) +{ + if (token->type == CPP_EOF || parsing_args) + return; + + /* The ImportC parser understands #line markers, append one to buffer. */ + static unsigned prev_line = 1; + static const char *prev_file = ""; + + if (token->src_loc == UNKNOWN_LOCATION) + return; + + unsigned src_line = LOCATION_LINE (token->src_loc); + const char *src_file = LOCATION_FILE (token->src_loc); + + /* Elide a line marker if the difference is just a few extra newlines. */ + if (src_line >= prev_line && src_line < prev_line + 8 + && strcmp (src_file, prev_file) == 0) + { + while (src_line > prev_line) + { + obstack_1grow (&d_cpp_buffer, '\n'); + prev_line++; + } + } + else + { + size_t to_file_len = strlen (src_file); + unsigned char *to_file_quoted = + (unsigned char *) alloca (to_file_len * 4 + 1); + + /* cpp_quote_string does not nul-terminate, so we have to do it + ourselves. */ + unsigned char *p = cpp_quote_string (to_file_quoted, + (const unsigned char *) src_file, + to_file_len); + *p = '\0'; + + char *xformat = xasprintf ("# %u \"%s\"\n", src_line, to_file_quoted); + obstack_grow (&d_cpp_buffer, xformat, strlen (xformat)); + free (xformat); + + prev_line = src_line; + prev_file = src_file; + } +} + +/* Callback from cpp_error for PFILE to print diagnostics from the + preprocessor. The diagnostic is of type LEVEL, with REASON set + to the reason code if LEVEL is represents a warning, at location + RICHLOC; MSG is the translated message and AP the arguments. + Returns true if a diagnostic was emitted, false otherwise. */ + +ATTRIBUTE_GCC_DIAG(5,0) +static bool +cb_cpp_diagnostic (cpp_reader *, enum cpp_diagnostic_level level, + enum cpp_warning_reason, rich_location *richloc, + const char *msg, va_list *ap) +{ + diagnostic_t dlevel; + bool save_warn_system_headers = global_dc->m_warn_system_headers; + + switch (level) + { + case CPP_DL_WARNING_SYSHDR: + global_dc->m_warn_system_headers = 1; + /* Fall through. */ + case CPP_DL_WARNING: + dlevel = DK_WARNING; + break; + case CPP_DL_PEDWARN: + dlevel = DK_PEDWARN; + break; + case CPP_DL_ERROR: + dlevel = DK_ERROR; + break; + case CPP_DL_ICE: + dlevel = DK_ICE; + break; + case CPP_DL_NOTE: + dlevel = DK_NOTE; + break; + case CPP_DL_FATAL: + dlevel = DK_FATAL; + break; + default: + gcc_unreachable (); + } + + diagnostic_info diagnostic; + diagnostic_set_info_translated (&diagnostic, msg, ap, + richloc, dlevel); + bool ret = diagnostic_report_diagnostic (global_dc, &diagnostic); + if (level == CPP_DL_WARNING_SYSHDR) + global_dc->m_warn_system_headers = save_warn_system_headers; + return ret; +} + +/* Wrapper around cpp_get_token to skip CPP_PADDING tokens and not consume + CPP_EOF. Used by d_lex_availability_macro. */ + +static const cpp_token * +get_token_no_padding (cpp_reader *pfile) +{ + for (;;) + { + const cpp_token *ret = cpp_peek_token (pfile, 0); + if (ret->type == CPP_EOF) + return ret; + + ret = cpp_get_token (pfile); + if (ret->type != CPP_PADDING) + return ret; + } +} + +/* Helper for consuming __has_{attribute,builtin,feature,extension}. */ + +static void +d_lex_availability_macro (cpp_reader *pfile, const char *builtin) +{ + const cpp_token *token = get_token_no_padding (pfile); + if (token->type != CPP_OPEN_PAREN) + { + cpp_error (pfile, CPP_DL_ERROR, + "missing %<(%> after %<__has_%s%>", builtin); + return; + } + + token = get_token_no_padding (pfile); + if (token->type != CPP_NAME) + { + cpp_error (pfile, CPP_DL_ERROR, + "macro %<__has_%s%> requires an identifier", builtin); + if (token->type == CPP_CLOSE_PAREN) + return; + } + + /* Consume tokens up to the closing parenthesis. */ + for (unsigned nparen = 1; ; token = get_token_no_padding (pfile)) + { + if (token->type == CPP_OPEN_PAREN) + ++nparen; + else if (token->type == CPP_CLOSE_PAREN) + --nparen; + else if (token->type == CPP_EOF) + { + cpp_error (pfile, CPP_DL_ERROR, + "missing %<)%> after %<__has_%s%>", builtin); + return; + } + if (!nparen) + return; + } +} + +/* Callback for has_attribute. */ + +static int +cb_has_attribute (cpp_reader *pfile, bool) +{ + d_lex_availability_macro (pfile, "attribute"); + return 0; +} + +/* Callback for has_builtin. */ + +static int +cb_has_builtin (cpp_reader *pfile) +{ + d_lex_availability_macro (pfile, "builtin"); + return 0; +} + +/* Callback for has_feature. */ + +static int +cb_has_feature (cpp_reader *pfile, bool feature) +{ + d_lex_availability_macro (pfile, feature ? "feature" : "extension"); + return 0; +} + +/* Write the final definition of a CPP macro NODE defined in PFILE to the + OutBuffer DEFINES for the ImportC parser to collect and translate into D. */ + +static void +d_cpp_append_macro (cpp_hashnode *node, cpp_reader *pfile, OutBuffer &defines) +{ + /* The ImportC parser only handles simple expressions such as numbers and + strings, as well as straightforward function-like macros. Filter out any + other kind of macro definition. */ + if (!cpp_macro_p (node) || node->value.macro->kind != cmk_macro) + return; + + cpp_macro *macro = node->value.macro; + bool print = false; + + /* Look for `#define MACRO string_or_number'. */ + if (!macro->fun_like && macro->count == 1 + && cpp_token_val_index (¯o->exp.tokens[0]) == CPP_TOKEN_FLD_STR) + print = true; + + /* Look for `#define MACRO ( expression )'. */ + if (!macro->fun_like && macro->count > 2 + && macro->exp.tokens[0].type == CPP_OPEN_PAREN + && macro->exp.tokens[macro->count - 1].type == CPP_CLOSE_PAREN) + print = true; + + /* Look for `#define MACRO() expression'. */ + if (macro->fun_like && !macro->variadic && macro->count > 0) + { + print = true; + for (unsigned int i = 0; i < macro->count; i++) + { + /* Don't emit if macro contains CPP-specific tokens, or anything that + looks like it might be a statement. */ + if (macro->exp.tokens[i].type == CPP_HASH + || macro->exp.tokens[i].type == CPP_PASTE + || macro->exp.tokens[i].type == CPP_SEMICOLON) + { + print = false; + break; + } + } + } + + if (!print) + return; + + const char *text = (const char *) cpp_macro_definition (pfile, node); + defines.write ("#define ", 8); + defines.write (text, strlen (text)); + /* Each #define line is 0 terminated. */ + defines.writeByte ('\0'); +} + +/* Initialize the cpp_callbacks structure of PFILE. */ + +static void +d_cpp_init_callbacks (cpp_reader *pfile) +{ + cpp_callbacks *cb = cpp_get_callbacks (pfile); + + cb->diagnostic = cb_cpp_diagnostic; + cb->line_change = cb_line_change; + cb->define = cb_define; + cb->undef = cb_undef; + cb->has_attribute = cb_has_attribute; + cb->has_builtin = cb_has_builtin; + cb->has_feature = cb_has_feature; + + if (!d_cpp_macros) + d_cpp_macros = hash_table <cpp_hashnode_hasher>::create_ggc (100); +} + +/* Implements lang_hooks.init_options for ImportC, called from d_init_options. + Initialize libcpp-related options before calling the option handlers. */ + +void +d_cpp_init_options (unsigned int decoded_options_count) +{ + d_cpp_option.multilib = NULL; + d_cpp_option.prefix = NULL; + d_cpp_option.sysroot = TARGET_SYSTEM_ROOT; + + d_cpp_option.stdinc = true; + d_cpp_option.verbose = false; + + d_cpp_option.deferred_opt = XNEWVEC (d_cpp_deferred_opt_t, + decoded_options_count); + d_cpp_option.deferred_opt_count = 0; +} + +/* Implements lang_hooks.init_options_struct for ImportC, called from + d_init_options_struct. Handles ImportC specific options. + Return false if we didn't do anything. */ + +bool +d_cpp_handle_option (size_t scode, const char *arg) +{ + opt_code code = (opt_code) scode; + bool result = true; + + switch (code) + { + default: + result = false; + break; + + case OPT_idirafter: + add_path (xstrdup (arg), INC_AFTER, 0, true); + break; + + case OPT_imultilib: + d_cpp_option.multilib = arg; + break; + + case OPT_iprefix: + d_cpp_option.prefix = arg; + break; + + case OPT_isysroot: + d_cpp_option.sysroot = arg; + break; + + case OPT_iquote: + case OPT_isystem: + add_path (xstrdup (arg), INC_BRACKET, 0, true); + break; + + case OPT_nostdinc: + d_cpp_option.stdinc = false; + break; + + case OPT_v: + d_cpp_option.verbose = true; + break; + + case OPT_D: + case OPT_U: + case OPT_imacros: + case OPT_include: + d_cpp_option.deferred_opt[d_cpp_option.deferred_opt_count].code = code; + d_cpp_option.deferred_opt[d_cpp_option.deferred_opt_count].arg = arg; + d_cpp_option.deferred_opt_count++; + break; + } + + return result; +} + +/* Initialize and return a libcpp parser for preprocessing C input sources. */ + +static cpp_reader * +d_cpp_init_parser (void) +{ + cpp_reader *pfile = cpp_create_reader (CLK_GNUC11, NULL, line_table); + gcc_assert (pfile); + + /* The cpp_options-structure defines far more flags than those set here. + If any other is implemented, see c-opt.c (sanitize_cpp_opts) for + inter-option dependencies that may need to be enforced. */ + cpp_options *cpp_option = cpp_get_options (pfile); + gcc_assert (cpp_option); + + cpp_option->cpp_pedantic = pedantic; + + cpp_post_options (pfile); + + d_cpp_init_callbacks (pfile); + + /* The handler `register_include_chains' can only be called once. */ + static bool registered_chains = false; + + if (registered_chains) + cpp_set_include_chains (pfile, get_added_cpp_dirs (INC_QUOTE), + get_added_cpp_dirs (INC_BRACKET), + get_added_cpp_dirs (INC_EMBED), false); + else + { + register_include_chains (pfile, d_cpp_option.sysroot, + d_cpp_option.prefix, d_cpp_option.multilib, + d_cpp_option.stdinc, false, + d_cpp_option.verbose); + registered_chains = true; + } + + return pfile; +} + +/* Pass an object-like macro and a value to define it to. */ + +static void +d_cpp_define (cpp_reader *pfile, const char *macro, const char *expansion) +{ + size_t mlen = strlen (macro); + size_t elen = strlen (expansion); + char *buf = (char *) alloca (mlen + elen + 2); + + sprintf (buf, "%s=%s", macro, expansion); + cpp_define (pfile, buf); +} + +/* Register front-end and target-specific CPP built-ins in PFILE. */ + +static void +d_cpp_define_builtins (cpp_reader *pfile) +{ + /* Initialize CPP built-ins. */ + cpp_change_file (pfile, LC_RENAME, "<built-in>"); + cpp_force_token_locations (pfile, BUILTINS_LOCATION); + + cpp_init_builtins (pfile, 0); + define_language_independent_builtin_macros (pfile); + + /* Support the __declspec keyword by turning them into attributes. */ + if (TARGET_DECLSPEC) + d_cpp_define (pfile, "__declspec(x)", "__attribute__((x))"); + + /* ImportC parser only recognizes C11 keywords where there are non-standard + alternative keywords. Redefine extensions to their ANSI equivalent. + This list was taken from an inspection of c-family/c-common.cc. */ + d_cpp_define (pfile, "__alignof", "_Alignof"); + d_cpp_define (pfile, "__alignof__", "_Alignof"); + d_cpp_define (pfile, "__const", "const"); + d_cpp_define (pfile, "__const__", "const"); + d_cpp_define (pfile, "__complex", "_Complex"); + d_cpp_define (pfile, "__complex__", "_Complex"); + d_cpp_define (pfile, "__inline", "inline"); + d_cpp_define (pfile, "__inline__", "inline"); + d_cpp_define (pfile, "__restrict", "restrict"); + d_cpp_define (pfile, "__restrict__", "restrict"); + d_cpp_define (pfile, "__signed", "signed"); + d_cpp_define (pfile, "__signed__", "signed"); + d_cpp_define (pfile, "__thread", "_Thread_local"); + d_cpp_define (pfile, "__typeof", "typeof"); + d_cpp_define (pfile, "__typeof__", "typeof"); + d_cpp_define (pfile, "__volatile", "volatile"); + d_cpp_define (pfile, "__volatile__", "volatile"); + + /* Built-in macros for stddef.h and stdint.h. */ + d_cpp_define (pfile, "__SIZE_TYPE__", SIZE_TYPE); + d_cpp_define (pfile, "__PTRDIFF_TYPE__", PTRDIFF_TYPE); + d_cpp_define (pfile, "__WCHAR_TYPE__", MODIFIED_WCHAR_TYPE); + if (strcmp (WINT_TYPE, "wchar_t") == 0) + d_cpp_define (pfile, "__WINT_TYPE__", WCHAR_TYPE); + else + d_cpp_define (pfile, "__WINT_TYPE__", WINT_TYPE); + d_cpp_define (pfile, "__INTMAX_TYPE__", INTMAX_TYPE); + d_cpp_define (pfile, "__UINTMAX_TYPE__", UINTMAX_TYPE); + d_cpp_define (pfile, "__CHAR8_TYPE__", CHAR8_TYPE); + d_cpp_define (pfile, "__CHAR16_TYPE__", CHAR16_TYPE); + d_cpp_define (pfile, "__CHAR32_TYPE__", CHAR32_TYPE); + if (SIG_ATOMIC_TYPE) + d_cpp_define (pfile, "__SIG_ATOMIC_TYPE__", SIG_ATOMIC_TYPE); + if (INT8_TYPE) + d_cpp_define (pfile, "__INT8_TYPE__", INT8_TYPE); + if (INT16_TYPE) + d_cpp_define (pfile, "__INT16_TYPE__", INT16_TYPE); + if (INT32_TYPE) + d_cpp_define (pfile, "__INT32_TYPE__", INT32_TYPE); + if (INT64_TYPE) + d_cpp_define (pfile, "__INT64_TYPE__", INT64_TYPE); + if (UINT8_TYPE) + d_cpp_define (pfile, "__UINT8_TYPE__", UINT8_TYPE); + if (UINT16_TYPE) + d_cpp_define (pfile, "__UINT16_TYPE__", UINT16_TYPE); + if (UINT32_TYPE) + d_cpp_define (pfile, "__UINT32_TYPE__", UINT32_TYPE); + if (UINT64_TYPE) + d_cpp_define (pfile, "__UINT64_TYPE__", UINT64_TYPE); + if (INT_LEAST8_TYPE) + d_cpp_define (pfile, "__INT_LEAST8_TYPE__", INT_LEAST8_TYPE); + if (INT_LEAST16_TYPE) + d_cpp_define (pfile, "__INT_LEAST16_TYPE__", INT_LEAST16_TYPE); + if (INT_LEAST32_TYPE) + d_cpp_define (pfile, "__INT_LEAST32_TYPE__", INT_LEAST32_TYPE); + if (INT_LEAST64_TYPE) + d_cpp_define (pfile, "__INT_LEAST64_TYPE__", INT_LEAST64_TYPE); + if (UINT_LEAST8_TYPE) + d_cpp_define (pfile, "__UINT_LEAST8_TYPE__", UINT_LEAST8_TYPE); + if (UINT_LEAST16_TYPE) + d_cpp_define (pfile, "__UINT_LEAST16_TYPE__", UINT_LEAST16_TYPE); + if (UINT_LEAST32_TYPE) + d_cpp_define (pfile, "__UINT_LEAST32_TYPE__", UINT_LEAST32_TYPE); + if (UINT_LEAST64_TYPE) + d_cpp_define (pfile, "__UINT_LEAST64_TYPE__", UINT_LEAST64_TYPE); + if (INT_FAST8_TYPE) + d_cpp_define (pfile, "__INT_FAST8_TYPE__", INT_FAST8_TYPE); + if (INT_FAST16_TYPE) + d_cpp_define (pfile, "__INT_FAST16_TYPE__", INT_FAST16_TYPE); + if (INT_FAST32_TYPE) + d_cpp_define (pfile, "__INT_FAST32_TYPE__", INT_FAST32_TYPE); + if (INT_FAST64_TYPE) + d_cpp_define (pfile, "__INT_FAST64_TYPE__", INT_FAST64_TYPE); + if (UINT_FAST8_TYPE) + d_cpp_define (pfile, "__UINT_FAST8_TYPE__", UINT_FAST8_TYPE); + if (UINT_FAST16_TYPE) + d_cpp_define (pfile, "__UINT_FAST16_TYPE__", UINT_FAST16_TYPE); + if (UINT_FAST32_TYPE) + d_cpp_define (pfile, "__UINT_FAST32_TYPE__", UINT_FAST32_TYPE); + if (UINT_FAST64_TYPE) + d_cpp_define (pfile, "__UINT_FAST64_TYPE__", UINT_FAST64_TYPE); + if (INTPTR_TYPE) + d_cpp_define (pfile, "__INTPTR_TYPE__", INTPTR_TYPE); + if (UINTPTR_TYPE) + d_cpp_define (pfile, "__UINTPTR_TYPE__", UINTPTR_TYPE); + + /* C-only extensions recognized by the parser. */ + d_cpp_define (pfile, "__attribute", "__attribute__"); + + /* `asm' is a D keyword. */ + d_cpp_define (pfile, "__asm", "asm"); + d_cpp_define (pfile, "__asm__", "asm"); + + /* `__extension__' suppresses warnings, there aren't any in ImportC. */ + d_cpp_define (pfile, "__extension__", ""); + + /* Initialize GDC specific built-ins. */ + d_cpp_define (pfile, "__IMPORTC__", "1"); + d_cpp_define (pfile, "_LANGUAGE_D", "1"); + + cpp_stop_forcing_token_locations (pfile); +} + +/* Handle deferred options from command-line, and apply them to PFILE. */ + +static void +d_cpp_deferred_options (cpp_reader *pfile) +{ + cpp_change_file (pfile, LC_RENAME, "<command-line>"); + + for (int i = 0; i < d_cpp_option.deferred_opt_count; i++) + { + d_cpp_deferred_opt_t *opt = &d_cpp_option.deferred_opt[i]; + + if (opt->code == OPT_D) + cpp_define (pfile, opt->arg); + else if (opt->code == OPT_U) + cpp_undef (pfile, opt->arg); + } + + /* Handle -imacros after -D, and -U. */ + for (int i = 0; i < d_cpp_option.deferred_opt_count; i++) + { + d_cpp_deferred_opt_t *opt = &d_cpp_option.deferred_opt[i]; + + if (opt->code == OPT_imacros + && cpp_push_include (pfile, opt->arg)) + cpp_scan_nooutput (pfile); + } + + /* Handle -include after -imacros and target-specific includes. */ + for (int i = 0; i < d_cpp_option.deferred_opt_count; i++) + { + d_cpp_deferred_opt_t *opt = &d_cpp_option.deferred_opt[i]; + + if (opt->code == OPT_include) + cpp_push_include (pfile, opt->arg); + } +} + +/* Preprocess the C file SRCFILE, returning the text of the preprocessed file + as a DArray. Any `#define' lines encountered are appended to DEFINES. + LOC is the source location where this callback is requested from. */ + +DArray<unsigned char> +d_cpp_preprocess (FileName srcfile, Loc, OutBuffer &defines) +{ + if (global.params.v.verbose) + message("importc %s", srcfile.toChars ()); + + cpp_reader *pfile = d_cpp_init_parser (); + + /* Initialize the buffer to return from this function. */ + if (!d_cpp_buffer_base) + { + gcc_obstack_init (&d_cpp_buffer); + d_cpp_buffer_base = obstack_alloc (&d_cpp_buffer, 0); + } + else + { + obstack_free (&d_cpp_buffer, d_cpp_buffer_base); + d_cpp_buffer_base = obstack_alloc (&d_cpp_buffer, 0); + } + + /* Parse the C file. */ + if (!cpp_read_main_file (pfile, srcfile.toChars ())) + { + errorcount++; + return DArray<unsigned char> (); + } + + d_cpp_define_builtins (pfile); + + /* Handle deferred options from command-line. */ + d_cpp_deferred_options (pfile); + cpp_change_file (pfile, LC_RENAME, srcfile.toChars ()); + + /* Do the preprocessing. */ + bool avoid_paste = false; + const cpp_token *cpp_source = NULL; + const cpp_token *cpp_prev = NULL; + + for (;;) + { + const cpp_token *token = cpp_get_token (pfile); + + if (token->type == CPP_PADDING) + { + avoid_paste = true; + if (cpp_source == NULL + || (!(cpp_source->flags & PREV_WHITE) + && token->val.source == NULL)) + cpp_source = token->val.source; + + continue; + } + + if (token->type == CPP_EOF) + break; + + /* Output a space if and only if necessary. */ + if (avoid_paste) + { + if (cpp_source == NULL) + cpp_source = token; + + if (cpp_source->flags & PREV_WHITE + || (cpp_prev && cpp_avoid_paste (pfile, cpp_prev, token)) + || (cpp_prev == NULL && token->type == CPP_HASH)) + obstack_1grow (&d_cpp_buffer, ' '); + } + else if (token->flags & PREV_WHITE) + obstack_1grow (&d_cpp_buffer, ' '); + + avoid_paste = false; + cpp_source = NULL; + cpp_prev = token; + + unsigned char *text = cpp_token_as_text (pfile, token); + obstack_grow (&d_cpp_buffer, text, strlen ((const char *) text)); + } + + /* Reached EOF, now dump all macro definitions to `defines'. */ + for (hash_table <cpp_hashnode_hasher>::iterator iter = d_cpp_macros->begin (); + iter != d_cpp_macros->end (); ++iter) + d_cpp_append_macro (*iter, pfile, defines); + + d_cpp_macros->empty (); + + /* Clean-up libcpp state so that multiple invocations of d_cpp_preprocess + won't conflict with each other. */ + cpp_finish (pfile, NULL); + cpp_destroy (pfile); + + char *result = (char *) obstack_finish (&d_cpp_buffer); + return DArray<unsigned char> (strlen (result), (unsigned char *) result); +} diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index ebbbe715daca..a07a84c68182 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -41,7 +41,9 @@ class Parameter; struct BaseClass; struct Scope; struct Loc; +struct OutBuffer; +template <typename TYPE> struct DArray; template <typename TYPE> struct Array; typedef Array <Expression *> Expressions; @@ -647,6 +649,11 @@ extern struct lang_decl *build_lang_decl (Declaration *); extern tree d_pushdecl (tree); extern void d_keep (tree); +/* In d-preprocess.cc. */ +extern void d_cpp_init_options (unsigned int); +extern bool d_cpp_handle_option (size_t, const char *); +extern DArray<unsigned char> d_cpp_preprocess (FileName, Loc, OutBuffer &); + /* In decl.cc. */ extern const char *d_mangle_decl (Dsymbol *); extern tree mangle_internal_decl (Dsymbol *, const char *, const char *); diff --git a/gcc/d/lang-specs.h b/gcc/d/lang-specs.h index 64e7a5f25988..15de8302e16b 100644 --- a/gcc/d/lang-specs.h +++ b/gcc/d/lang-specs.h @@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see {".dd", "@d", 0, 1, 0 }, {".di", "@d", 0, 1, 0 }, {"@d", - "%{!E:d21 %i %(cc1_options) %I %{nostdinc} %{i*} %{I*} %{J*} \ + "%{!E:d21 %i %(cc1_options) %I %{nostdinc} %{i*} %{D*&U*} %{I*} %{J*} \ %{H} %{Hd*} %{Hf*} %{MD:-MD %b.deps} %{MMD:-MMD %b.deps} \ %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} \ %{X:-Xf %b.json} %{Xf*} \ diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index 298ff5843ef2..7c6f5c06a0e7 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -42,6 +42,10 @@ D NoDriverArg Separate Alias(MD) D NoDriverArg Separate Alias(MMD) ; Documented in C +D +D Joined Separate +; Documented in C + H D ; Different from documented use in C. @@ -98,6 +102,10 @@ MQ D Joined Separate ; Documented in C +U +D Joined Separate +; Documented in C + Waddress D Warning Var(warn_address) LangEnabledBy(D, Wextra) ; Documented in C @@ -487,14 +495,30 @@ fweak-templates D Var(flag_weak_templates) Init(1) Emit template instantiations as weak symbols. +idirafter +D Joined Separate +; Documented in C + +imacros +D Joined Separate MissingArgError(missing filename after %qs) +; Documented in C + imultilib D Joined Separate ; Documented in C +include +D Joined Separate MissingArgError(missing filename after %qs) +; Documented in C + iprefix D Joined Separate ; Documented in C +iquote +D Joined Separate +; Documented in C + isysroot D Joined Separate ; Documented in C