#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "cpplib.h"
#include "tree.h"
#include "c-pragma.h"
#include "c-tree.h"
#include "c-incpath.h"
#include "toplev.h"
#include "tm_p.h"
#include "cppdefault.h"
#include "prefix.h"
#include "options.h"
#include "flags.h"
#include "opts.h"
#include "varray.h"
#define BAD(gmsgid) do { warning (gmsgid); return; } while (0)
#define BAD2(msgid, arg) do { warning (msgid, arg); return; } while (0)
static bool using_frameworks = false;
static void directive_with_named_function (const char *, void (*sec_f)(void));
static void push_field_alignment (int, int, int);
static void pop_field_alignment (void);
static const char *find_subframework_file (const char *, const char *);
static void add_system_framework_path (char *);
static const char *find_subframework_header (cpp_reader *pfile, const char *header,
cpp_dir **dirp);
typedef struct align_stack
{
int alignment;
unsigned long mac68k;
unsigned long natural;
struct align_stack * prev;
} align_stack;
static struct align_stack * field_align_stack = NULL;
static void
push_field_alignment (int bit_alignment,
int mac68k_alignment, int natural_alignment)
{
align_stack *entry = (align_stack *) xmalloc (sizeof (align_stack));
entry->alignment = maximum_field_alignment;
entry->mac68k = TARGET_ALIGN_MAC68K;
entry->natural = TARGET_ALIGN_NATURAL;
entry->prev = field_align_stack;
field_align_stack = entry;
maximum_field_alignment = bit_alignment;
if (mac68k_alignment)
rs6000_alignment_flags |= MASK_ALIGN_MAC68K;
else
rs6000_alignment_flags &= ~MASK_ALIGN_MAC68K;
if (natural_alignment)
rs6000_alignment_flags |= MASK_ALIGN_NATURAL;
else
rs6000_alignment_flags &= ~MASK_ALIGN_NATURAL;
}
static void
pop_field_alignment (void)
{
if (field_align_stack)
{
align_stack *entry = field_align_stack;
maximum_field_alignment = entry->alignment;
if (entry->mac68k)
rs6000_alignment_flags |= MASK_ALIGN_MAC68K;
else
rs6000_alignment_flags &= ~MASK_ALIGN_MAC68K;
if (entry->natural)
rs6000_alignment_flags |= MASK_ALIGN_NATURAL;
else
rs6000_alignment_flags &= ~MASK_ALIGN_NATURAL;
field_align_stack = entry->prev;
free (entry);
}
else
error ("too many #pragma options align=reset");
}
void
darwin_pragma_ignore (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
}
void
darwin_pragma_fenv (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
flag_trapping_math = 1;
}
void
darwin_pragma_options (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
const char *arg;
tree t, x;
if (c_lex (&t) != CPP_NAME)
BAD ("malformed '#pragma options', ignoring");
arg = IDENTIFIER_POINTER (t);
if (strcmp (arg, "align"))
BAD ("malformed '#pragma options', ignoring");
if (c_lex (&t) != CPP_EQ)
BAD ("malformed '#pragma options', ignoring");
if (c_lex (&t) != CPP_NAME)
BAD ("malformed '#pragma options', ignoring");
if (c_lex (&x) != CPP_EOF)
warning ("junk at end of '#pragma options'");
arg = IDENTIFIER_POINTER (t);
if (!strcmp (arg, "mac68k"))
{
if (POINTER_SIZE == 64)
warning ("mac68k alignment pragma is deprecated for 64-bit Darwin");
push_field_alignment (0, 1, 0);
}
else if (!strcmp (arg, "native"))
push_field_alignment (0, 0, 0);
else if (!strcmp (arg, "natural"))
push_field_alignment (0, 0, 1);
else if (!strcmp (arg, "packed"))
push_field_alignment (8, 0, 0);
else if (!strcmp (arg, "power"))
push_field_alignment (0, 0, 0);
else if (!strcmp (arg, "reset"))
pop_field_alignment ();
else
warning ("malformed '#pragma options align={mac68k|power|natural|reset}', ignoring");
}
void
darwin_pragma_pack (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
tree x, id = 0;
int align = -1;
enum cpp_ttype token;
enum { set, push, pop } action;
if (c_lex (&x) != CPP_OPEN_PAREN)
BAD ("missing '(' after '#pragma pack' - ignored");
token = c_lex (&x);
if (token == CPP_CLOSE_PAREN)
{
action = pop;
align = 0;
}
else if (token == CPP_NUMBER)
{
align = TREE_INT_CST_LOW (x);
action = push;
if (c_lex (&x) != CPP_CLOSE_PAREN)
BAD ("malformed '#pragma pack' - ignored");
}
else if (token == CPP_NAME)
{
#define GCC_BAD_ACTION do { if (action == push) \
BAD ("malformed '#pragma pack(push[, id], <n>)' - ignored"); \
else \
BAD ("malformed '#pragma pack(pop[, id])' - ignored"); \
} while (0)
const char *op = IDENTIFIER_POINTER (x);
if (!strcmp (op, "push"))
action = push;
else if (!strcmp (op, "pop"))
action = pop;
else
BAD2 ("unknown action '%s' for '#pragma pack' - ignored", op);
token = c_lex (&x);
if (token != CPP_COMMA && action == push)
GCC_BAD_ACTION;
if (token == CPP_COMMA)
{
token = c_lex (&x);
if (token == CPP_NAME)
{
id = x;
if (action == push && c_lex (&x) != CPP_COMMA)
GCC_BAD_ACTION;
token = c_lex (&x);
}
if (action == push)
{
if (token == CPP_NUMBER)
{
align = TREE_INT_CST_LOW (x);
token = c_lex (&x);
}
else
GCC_BAD_ACTION;
}
}
if (token != CPP_CLOSE_PAREN)
GCC_BAD_ACTION;
#undef GCC_BAD_ACTION
}
else
BAD ("malformed '#pragma pack' - ignored");
if (c_lex (&x) != CPP_EOF)
warning ("junk at end of '#pragma pack'");
if (action != pop)
{
switch (align)
{
case 0:
case 1:
case 2:
case 4:
case 8:
case 16:
align *= BITS_PER_UNIT;
break;
default:
BAD2 ("alignment must be a small power of two, not %d", align);
}
}
switch (action)
{
case pop: pop_field_alignment (); break;
case push: push_field_alignment (align, 0, 0); break;
case set: break;
}
}
void
darwin_pragma_unused (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
tree decl, x;
int tok;
if (c_lex (&x) != CPP_OPEN_PAREN)
BAD ("missing '(' after '#pragma unused', ignoring");
while (1)
{
tok = c_lex (&decl);
if (tok == CPP_NAME && decl)
{
tree local = lookup_name (decl);
if (local && (TREE_CODE (local) == PARM_DECL
|| TREE_CODE (local) == VAR_DECL))
TREE_USED (local) = 1;
tok = c_lex (&x);
if (tok != CPP_COMMA)
break;
}
}
if (tok != CPP_CLOSE_PAREN)
BAD ("missing ')' after '#pragma unused', ignoring");
if (c_lex (&x) != CPP_EOF)
warning ("junk at end of '#pragma unused'");
}
void
darwin_pragma_reverse_bitfields (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
const char* arg;
tree t;
if (c_lex (&t) != CPP_NAME)
BAD ("malformed '#pragma reverse_bitfields', ignoring");
arg = IDENTIFIER_POINTER (t);
if (!strcmp (arg, "on"))
darwin_reverse_bitfields = true;
else if (!strcmp (arg, "off") || !strcmp (arg, "reset"))
darwin_reverse_bitfields = false;
else
warning ("malformed '#pragma reverse_bitfields {on|off|reset}', ignoring");
if (c_lex (&t) != CPP_EOF)
warning ("junk at end of '#pragma reverse_bitfields'");
}
varray_type va_opt;
static void
push_opt_level (int level, int size)
{
if (!va_opt)
VARRAY_INT_INIT (va_opt, 5, "va_opt");
VARRAY_PUSH_INT (va_opt, size << 16 | level);
}
static void
pop_opt_level (void)
{
int level;
if (!va_opt)
VARRAY_INT_INIT (va_opt, 5, "va_opt");
if (!VARRAY_ACTIVE_SIZE (va_opt))
{
warning ("optimization pragma stack underflow");
return;
}
level = VARRAY_TOP_INT (va_opt);
VARRAY_POP (va_opt);
optimize_size = level >> 16;
optimize = level & 0xffff;
}
void
darwin_pragma_opt_level (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
tree t;
enum cpp_ttype argtype = c_lex (&t);
if (argtype == CPP_NAME)
{
const char* arg = IDENTIFIER_POINTER (t);
if (strcmp (arg, "reset") != 0)
BAD ("malformed '#pragma optimization_level [GCC] {0|1|2|3|reset}', ignoring");
pop_opt_level ();
}
else if (argtype == CPP_NUMBER)
{
if (TREE_CODE (t) != INTEGER_CST
|| INT_CST_LT (t, integer_zero_node)
|| TREE_INT_CST_HIGH (t) != 0)
BAD ("malformed '#pragma optimization_level [GCC] {0|1|2|3|reset}', ignoring");
push_opt_level (optimize, optimize_size);
optimize = TREE_INT_CST_LOW (t);
if (optimize > 3)
optimize = 3;
optimize_size = 0;
}
else
BAD ("malformed '#pragma optimization_level [GCC] {0|1|2|3|reset}', ignoring");
set_flags_from_O (false);
reset_optimization_options (optimize, optimize_size);
if (c_lex (&t) != CPP_EOF)
warning ("junk at end of '#pragma optimization_level'");
}
void
darwin_pragma_opt_size (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
const char* arg;
tree t;
if (c_lex (&t) != CPP_NAME)
BAD ("malformed '#pragma optimize_for_size { on | off | reset}', ignoring");
arg = IDENTIFIER_POINTER (t);
if (!strcmp (arg, "on"))
{
push_opt_level (optimize, optimize_size);
optimize_size = 1;
optimize = 2;
}
else if (!strcmp (arg, "off"))
optimize_size = 0;
else if (!strcmp (arg, "reset"))
pop_opt_level ();
else
BAD ("malformed '#pragma optimize_for_size { on | off | reset }', ignoring");
set_flags_from_O (false);
reset_optimization_options (optimize, optimize_size);
if (c_lex (&t) != CPP_EOF)
warning ("junk at end of '#pragma optimize_for_size'");
}
static struct {
size_t len;
const char *name;
cpp_dir* dir;
} *frameworks_in_use;
static int num_frameworks = 0;
static int max_frameworks = 0;
static void
add_framework (const char *name, size_t len, cpp_dir *dir)
{
char *dir_name;
int i;
for (i = 0; i < num_frameworks; ++i)
{
if (len == frameworks_in_use[i].len
&& strncmp (name, frameworks_in_use[i].name, len) == 0)
{
return;
}
}
if (i >= max_frameworks)
{
max_frameworks = i*2;
max_frameworks += i == 0;
frameworks_in_use = xrealloc (frameworks_in_use,
max_frameworks*sizeof(*frameworks_in_use));
}
dir_name = xmalloc (len + 1);
memcpy (dir_name, name, len);
dir_name[len] = '\0';
frameworks_in_use[num_frameworks].name = dir_name;
frameworks_in_use[num_frameworks].len = len;
frameworks_in_use[num_frameworks].dir = dir;
++num_frameworks;
}
static struct cpp_dir*
find_framework (const char *name, size_t len)
{
int i;
for (i = 0; i < num_frameworks; ++i)
{
if (len == frameworks_in_use[i].len
&& strncmp (name, frameworks_in_use[i].name, len) == 0)
{
return frameworks_in_use[i].dir;
}
}
return 0;
}
struct framework_header {const char * dirName; int dirNameLen; };
static struct framework_header framework_header_dirs[] = {
{ "Headers", 7 },
{ "PrivateHeaders", 14 },
{ NULL, 0 }
};
static char *
framework_construct_pathname (const char *fname, cpp_dir *dir)
{
char *buf;
size_t fname_len, frname_len;
cpp_dir *fast_dir;
char *frname;
struct stat st;
int i;
buf = strchr (fname, '/');
if (buf)
fname_len = buf - fname;
else
return 0;
fast_dir = find_framework (fname, fname_len);
if (fast_dir && dir != fast_dir)
return 0;
frname = xmalloc (strlen (fname) + dir->len + 2
+ strlen(".framework/") + strlen("PrivateHeaders"));
strncpy (&frname[0], dir->name, dir->len);
frname_len = dir->len;
if (frname_len && frname[frname_len-1] != '/')
frname[frname_len++] = '/';
strncpy (&frname[frname_len], fname, fname_len);
frname_len += fname_len;
strncpy (&frname[frname_len], ".framework/", strlen (".framework/"));
frname_len += strlen (".framework/");
if (fast_dir == 0)
{
frname[frname_len-1] = 0;
if (stat (frname, &st) == 0)
{
add_framework (fname, fname_len, dir);
}
else
{
free (frname);
return 0;
}
frname[frname_len-1] = '/';
}
for (i = 0; framework_header_dirs[i].dirName; i++)
{
strncpy (&frname[frname_len],
framework_header_dirs[i].dirName,
framework_header_dirs[i].dirNameLen);
strcpy (&frname[frname_len + framework_header_dirs[i].dirNameLen],
&fname[fname_len]);
if (stat (frname, &st) == 0)
return frname;
}
free (frname);
return 0;
}
static const char*
find_subframework_file (const char *fname, const char *pname)
{
char *sfrname;
const char *dot_framework = ".framework/";
char *bufptr;
int sfrname_len, i, fname_len;
struct cpp_dir *fast_dir;
static struct cpp_dir subframe_dir;
struct stat st;
bufptr = strchr (fname, '/');
if (bufptr == 0)
return 0;
fname_len = bufptr - fname;
fast_dir = find_framework (fname, fname_len);
bufptr = strstr (pname, dot_framework);
if (!bufptr)
return 0;
sfrname = (char *) xmalloc (strlen (pname) + strlen (fname) + 2 +
strlen ("Frameworks/") + strlen (".framework/")
+ strlen ("PrivateHeaders"));
bufptr += strlen (dot_framework);
sfrname_len = bufptr - pname;
strncpy (&sfrname[0], pname, sfrname_len);
strncpy (&sfrname[sfrname_len], "Frameworks/", strlen ("Frameworks/"));
sfrname_len += strlen("Frameworks/");
strncpy (&sfrname[sfrname_len], fname, fname_len);
sfrname_len += fname_len;
strncpy (&sfrname[sfrname_len], ".framework/", strlen (".framework/"));
sfrname_len += strlen (".framework/");
for (i = 0; framework_header_dirs[i].dirName; i++)
{
strncpy (&sfrname[sfrname_len],
framework_header_dirs[i].dirName,
framework_header_dirs[i].dirNameLen);
strcpy (&sfrname[sfrname_len + framework_header_dirs[i].dirNameLen],
&fname[fname_len]);
if (stat (sfrname, &st) == 0)
{
if (fast_dir != &subframe_dir)
{
if (fast_dir)
warning ("subframework include %s conflicts with framework include",
fname);
else
add_framework (fname, fname_len, &subframe_dir);
}
return sfrname;
}
}
free (sfrname);
return 0;
}
static void
add_system_framework_path (char *path)
{
int cxx_aware = 1;
cpp_dir *p;
p = xmalloc (sizeof (cpp_dir));
p->next = NULL;
p->name = path;
p->sysp = 1 + !cxx_aware;
p->construct = framework_construct_pathname;
using_frameworks = 1;
add_cpp_dir_path (p, SYSTEM);
}
void
add_framework_path (char *path)
{
cpp_dir *p;
p = xmalloc (sizeof (cpp_dir));
p->next = NULL;
p->name = path;
p->sysp = 0;
p->construct = framework_construct_pathname;
using_frameworks = 1;
add_cpp_dir_path (p, BRACKET);
}
static const char *framework_defaults [] =
{
"/System/Library/Frameworks",
"/Library/Frameworks",
};
void
darwin_register_objc_includes (const char *sysroot, const char *iprefix,
int stdinc)
{
const char *fname;
size_t len;
if (!stdinc)
return;
fname = GCC_INCLUDE_DIR "-gnu-runtime";
if (c_dialect_objc () && !flag_next_runtime)
{
char *str;
if (iprefix && (len = cpp_GCC_INCLUDE_DIR_len) != 0 && !sysroot
&& !strncmp (fname, cpp_GCC_INCLUDE_DIR, len))
{
str = concat (iprefix, fname + len, NULL);
add_path (str, SYSTEM, false, false);
}
if (sysroot)
str = concat (sysroot, fname, NULL);
else
str = update_path (fname, "");
add_path (str, SYSTEM, false, false);
}
}
void
darwin_register_frameworks (const char *sysroot,
const char *iprefix ATTRIBUTE_UNUSED, int stdinc)
{
if (stdinc)
{
size_t i;
for (i=0; i<sizeof (framework_defaults)/sizeof(const char *); ++i)
{
char *str;
if (sysroot)
str = concat (sysroot, xstrdup (framework_defaults [i]), NULL);
else
str = xstrdup (framework_defaults[i]);
add_system_framework_path (str);
}
}
if (using_frameworks)
cpp_get_callbacks (parse_in)->missing_header = find_subframework_header;
}
static const char*
find_subframework_header (cpp_reader *pfile, const char *header, cpp_dir **dirp)
{
const char *fname = header;
struct cpp_buffer *b;
const char *n;
for (b = cpp_get_buffer (pfile);
b && cpp_get_file (b) && cpp_get_path (cpp_get_file (b));
b = cpp_get_prev (b))
{
n = find_subframework_file (fname, cpp_get_path (cpp_get_file (b)));
if (n)
{
*dirp = cpp_get_dir (cpp_get_file (b));
return n;
}
}
return 0;
}
extern void mod_init_section (void), mod_term_section (void);
static void directive_with_named_function (const char *pragma_name,
void (*section_function) (void))
{
tree decl;
int tok;
tok = c_lex (&decl);
if (tok == CPP_NAME && decl)
{
extern FILE *asm_out_file;
section_function ();
fprintf (asm_out_file, "\t.long _%s\n", IDENTIFIER_POINTER (decl));
if (c_lex (&decl) != CPP_EOF)
warning ("junk at end of #pragma %s <function_name>\n", pragma_name);
}
else
warning ("function name expected after #pragma %s\n", pragma_name);
}
void
darwin_pragma_call_on_load (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
warning("Pragma CALL_ON_LOAD is deprecated; use constructor attribute instead");
directive_with_named_function ("CALL_ON_LOAD", mod_init_section);
}
void
darwin_pragma_call_on_unload (cpp_reader *pfile ATTRIBUTE_UNUSED)
{
warning("Pragma CALL_ON_UNLOAD is deprecated; use destructor attribute instead");
directive_with_named_function ("CALL_ON_UNLOAD", mod_term_section);
}
static const char *
version_as_macro (void)
{
static char result[] = "1000";
if (strncmp (darwin_macosx_version_min, "10.", 3) != 0)
goto fail;
if (! ISDIGIT (darwin_macosx_version_min[3]))
goto fail;
result[2] = darwin_macosx_version_min[3];
if (darwin_macosx_version_min[4] != '\0')
{
if (darwin_macosx_version_min[4] != '.')
goto fail;
if (! ISDIGIT (darwin_macosx_version_min[5]))
goto fail;
if (darwin_macosx_version_min[6] != '\0')
goto fail;
result[3] = darwin_macosx_version_min[5];
}
else
result[3] = '0';
return result;
fail:
error ("Unknown value %qs of -mmacosx-version-min",
darwin_macosx_version_min);
return "1000";
}
#define builtin_define(TXT) cpp_define (pfile, TXT)
void
darwin_cpp_builtins (cpp_reader *pfile)
{
builtin_define ("__MACH__");
builtin_define ("__APPLE__");
if (darwin_macosx_version_min)
builtin_define_with_value ("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__",
version_as_macro(), false);
if (darwin_constant_cfstrings)
builtin_define ("__CONSTANT_CFSTRINGS__");
if (darwin_pascal_strings)
{
builtin_define ("__PASCAL_STRINGS__");
}
if (flag_objc_gc)
{
builtin_define ("__strong=__attribute__((objc_gc(strong)))");
builtin_define ("__weak=__attribute__((objc_gc(weak)))");
builtin_define ("__OBJC_GC__");
}
else
{
builtin_define ("__strong=");
builtin_define ("__weak=");
}
if (flag_pic)
builtin_define ("__PIC__");
}