small changes
[cparser] / parser.c
index 4c4dfe7..f7bfe53 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -48,13 +48,27 @@ typedef struct {
        unsigned short namespc;
 } stack_entry_t;
 
+typedef struct gnu_attribute_t gnu_attribute_t;
+struct gnu_attribute_t {
+       gnu_attribute_kind_t kind;
+       gnu_attribute_t     *next;
+       bool                 invalid;
+       bool                 have_arguments;
+       union {
+               size_t   value;
+               string_t string;
+       } u;
+};
+
 typedef struct declaration_specifiers_t  declaration_specifiers_t;
 struct declaration_specifiers_t {
        source_position_t  source_position;
        unsigned char      declared_storage_class;
        unsigned char      alignment;         /**< Alignment, 0 if not set. */
-       bool               is_inline;
+       unsigned int       is_inline : 1;
+       unsigned int       deprecated : 1;
        decl_modifiers_t   decl_modifiers;    /**< MS __declspec extended modifier mask */
+       gnu_attribute_t   *gnu_attributes;    /**< list of GNU attributes */
        const char        *deprecated_string; /**< can be set if declaration was marked deprecated. */
        symbol_t          *get_property_sym;  /**< the name of the get property if set. */
        symbol_t          *put_property_sym;  /**< the name of the put property if set. */
@@ -145,7 +159,7 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_restrict:        \
        case T_volatile:        \
        case T_inline:          \
-       case T_forceinline:
+       case T__forceinline:
 
 #ifdef PROVIDE_COMPLEX
 #define COMPLEX_SPECIFIERS  \
@@ -173,6 +187,7 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_enum:              \
        case T___typeof__:        \
        case T___builtin_va_list: \
+       case T__declspec:         \
        COMPLEX_SPECIFIERS        \
        IMAGINARY_SPECIFIERS
 
@@ -235,39 +250,6 @@ static size_t get_statement_struct_size(statement_kind_t kind)
        return sizes[kind];
 }
 
-/**
- * Allocate a statement node of given kind and initialize all
- * fields with zero.
- */
-static statement_t *allocate_statement_zero(statement_kind_t kind)
-{
-       size_t       size = get_statement_struct_size(kind);
-       statement_t *res  = allocate_ast_zero(size);
-
-       res->base.kind = kind;
-       return res;
-}
-
-/**
- * Creates a new invalid statement.
- */
-static statement_t *create_invalid_statement(void)
-{
-       statement_t *statement          = allocate_statement_zero(STATEMENT_INVALID);
-       statement->base.source_position = token.source_position;
-       return statement;
-}
-
-/**
- * Allocate a new empty statement.
- */
-static statement_t *create_empty_statement(void)
-{
-       statement_t *statement          = allocate_statement_zero(STATEMENT_EMPTY);
-       statement->base.source_position = token.source_position;
-       return statement;
-}
-
 /**
  * Returns the size of an expression node.
  *
@@ -293,8 +275,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_SIZEOF]                  = sizeof(typeprop_expression_t),
                [EXPR_ALIGNOF]                 = sizeof(typeprop_expression_t),
                [EXPR_CLASSIFY_TYPE]           = sizeof(classify_type_expression_t),
-               [EXPR_FUNCTION]                = sizeof(string_literal_expression_t),
-               [EXPR_PRETTY_FUNCTION]         = sizeof(string_literal_expression_t),
+               [EXPR_FUNCNAME]                = sizeof(funcname_expression_t),
                [EXPR_BUILTIN_SYMBOL]          = sizeof(builtin_symbol_expression_t),
                [EXPR_BUILTIN_CONSTANT_P]      = sizeof(builtin_constant_expression_t),
                [EXPR_BUILTIN_PREFETCH]        = sizeof(builtin_prefetch_expression_t),
@@ -314,6 +295,19 @@ static size_t get_expression_struct_size(expression_kind_t kind)
        return sizes[kind];
 }
 
+/**
+ * Allocate a statement node of given kind and initialize all
+ * fields with zero.
+ */
+static statement_t *allocate_statement_zero(statement_kind_t kind)
+{
+       size_t       size = get_statement_struct_size(kind);
+       statement_t *res  = allocate_ast_zero(size);
+
+       res->base.kind = kind;
+       return res;
+}
+
 /**
  * Allocate an expression node of given kind and initialize all
  * fields with zero.
@@ -328,6 +322,36 @@ static expression_t *allocate_expression_zero(expression_kind_t kind)
        return res;
 }
 
+/**
+ * Creates a new invalid expression.
+ */
+static expression_t *create_invalid_expression(void)
+{
+       expression_t *expression         = allocate_expression_zero(EXPR_INVALID);
+       expression->base.source_position = token.source_position;
+       return expression;
+}
+
+/**
+ * Creates a new invalid statement.
+ */
+static statement_t *create_invalid_statement(void)
+{
+       statement_t *statement          = allocate_statement_zero(STATEMENT_INVALID);
+       statement->base.source_position = token.source_position;
+       return statement;
+}
+
+/**
+ * Allocate a new empty statement.
+ */
+static statement_t *create_empty_statement(void)
+{
+       statement_t *statement          = allocate_statement_zero(STATEMENT_EMPTY);
+       statement->base.source_position = token.source_position;
+       return statement;
+}
+
 /**
  * Returns the size of a type node.
  *
@@ -825,55 +849,68 @@ static expression_t *create_implicit_cast(expression_t *expression,
 /** Implements the rules from ยง 6.5.16.1 */
 static type_t *semantic_assign(type_t *orig_type_left,
                             const expression_t *const right,
-                            const char *context)
+                            const char *context,
+                            source_position_t source_position)
 {
        type_t *const orig_type_right = right->base.type;
        type_t *const type_left       = skip_typeref(orig_type_left);
        type_t *const type_right      = skip_typeref(orig_type_right);
 
-       if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
-           (is_type_pointer(type_left) && is_null_pointer_constant(right)) ||
-           (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
-               && is_type_pointer(type_right))) {
-               return orig_type_left;
-       }
+       if(is_type_pointer(type_left)) {
+               if(is_null_pointer_constant(right)) {
+                       return orig_type_left;
+               } else if(is_type_pointer(type_right)) {
+                       type_t *points_to_left
+                               = skip_typeref(type_left->pointer.points_to);
+                       type_t *points_to_right
+                               = skip_typeref(type_right->pointer.points_to);
+
+                       /* the left type has all qualifiers from the right type */
+                       unsigned missing_qualifiers
+                               = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers;
+                       if(missing_qualifiers != 0) {
+                               errorf(source_position,
+                                               "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointed-to type", type_left, context, type_right, missing_qualifiers);
+                               return orig_type_left;
+                       }
 
-       if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
-               type_t *points_to_left  = skip_typeref(type_left->pointer.points_to);
-               type_t *points_to_right = skip_typeref(type_right->pointer.points_to);
+                       points_to_left  = get_unqualified_type(points_to_left);
+                       points_to_right = get_unqualified_type(points_to_right);
 
-               /* the left type has all qualifiers from the right type */
-               unsigned missing_qualifiers
-                       = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers;
-               if(missing_qualifiers != 0) {
-                       errorf(HERE, "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointed-to type", type_left, context, type_right, missing_qualifiers);
-                       return orig_type_left;
-               }
+                       if (is_type_atomic(points_to_left, ATOMIC_TYPE_VOID) ||
+                                       is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)) {
+                               return orig_type_left;
+                       }
 
-               points_to_left  = get_unqualified_type(points_to_left);
-               points_to_right = get_unqualified_type(points_to_right);
+                       if (!types_compatible(points_to_left, points_to_right)) {
+                               warningf(source_position,
+                                       "destination type '%T' in %s is incompatible with '%E' of type '%T'",
+                                       orig_type_left, context, right, orig_type_right);
+                       }
 
-               if (is_type_atomic(points_to_left, ATOMIC_TYPE_VOID) ||
-                               is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)) {
+                       return orig_type_left;
+               } else if(is_type_integer(type_right)) {
+                       warningf(source_position,
+                                       "%s makes pointer '%T' from integer '%T' without a cast",
+                                       context, orig_type_left, orig_type_right);
                        return orig_type_left;
                }
-
-               if (!types_compatible(points_to_left, points_to_right)) {
-                       warningf(right->base.source_position,
-                               "destination type '%T' in %s is incompatible with '%E' of type '%T'",
-                               orig_type_left, context, right, orig_type_right);
-               }
-
+       } else if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
+           (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
+               && is_type_pointer(type_right))) {
                return orig_type_left;
-       }
-
-       if ((is_type_compound(type_left)  && is_type_compound(type_right))
+       } else if ((is_type_compound(type_left)  && is_type_compound(type_right))
                        || (is_type_builtin(type_left) && is_type_builtin(type_right))) {
                type_t *const unqual_type_left  = get_unqualified_type(type_left);
                type_t *const unqual_type_right = get_unqualified_type(type_right);
                if (types_compatible(unqual_type_left, unqual_type_right)) {
                        return orig_type_left;
                }
+       } else if (is_type_integer(type_left) && is_type_pointer(type_right)) {
+               warningf(source_position,
+                               "%s makes integer '%T' from pointer '%T' without a cast",
+                               context, orig_type_left, orig_type_right);
+               return orig_type_left;
        }
 
        if (!is_type_valid(type_left))
@@ -938,32 +975,589 @@ static string_t parse_string_literals(void)
        return result;
 }
 
-static void parse_attributes(void)
+static const char *gnu_attribute_names[GNU_AK_LAST] = {
+       [GNU_AK_CONST]                  = "const",
+       [GNU_AK_VOLATILE]               = "volatile",
+       [GNU_AK_CDECL]                  = "cdecl",
+       [GNU_AK_STDCALL]                = "stdcall",
+       [GNU_AK_FASTCALL]               = "fastcall",
+       [GNU_AK_DEPRECATED]             = "deprecated",
+       [GNU_AK_NOINLINE]               = "noinline",
+       [GNU_AK_NORETURN]               = "noreturn",
+       [GNU_AK_NAKED]                  = "naked",
+       [GNU_AK_PURE]                   = "pure",
+       [GNU_AK_ALWAYS_INLINE]          = "always_inline",
+       [GNU_AK_MALLOC]                 = "malloc",
+       [GNU_AK_WEAK]                   = "weak",
+       [GNU_AK_CONSTRUCTOR]            = "constructor",
+       [GNU_AK_DESTRUCTOR]             = "destructor",
+       [GNU_AK_NOTHROW]                = "nothrow",
+       [GNU_AK_TRANSPARENT_UNION]      = "transparent_union",
+       [GNU_AK_COMMON]                 = "coommon",
+       [GNU_AK_NOCOMMON]               = "nocommon",
+       [GNU_AK_PACKED]                 = "packed",
+       [GNU_AK_SHARED]                 = "shared",
+       [GNU_AK_NOTSHARED]              = "notshared",
+       [GNU_AK_USED]                   = "used",
+       [GNU_AK_UNUSED]                 = "unused",
+       [GNU_AK_NO_INSTRUMENT_FUNCTION] = "no_instrument_function",
+       [GNU_AK_WARN_UNUSED_RESULT]     = "warn_unused_result",
+       [GNU_AK_LONGCALL]               = "longcall",
+       [GNU_AK_SHORTCALL]              = "shortcall",
+       [GNU_AK_LONG_CALL]              = "long_call",
+       [GNU_AK_SHORT_CALL]             = "short_call",
+       [GNU_AK_FUNCTION_VECTOR]        = "function_vector",
+       [GNU_AK_INTERRUPT]                              = "interrupt",
+       [GNU_AK_INTERRUPT_HANDLER]      = "interrupt_handler",
+       [GNU_AK_NMI_HANDLER]            = "nmi_handler",
+       [GNU_AK_NESTING]                = "nesting",
+       [GNU_AK_NEAR]                   = "near",
+       [GNU_AK_FAR]                    = "far",
+       [GNU_AK_SIGNAL]                 = "signal",
+       [GNU_AK_EIGTHBIT_DATA]          = "eightbit_data",
+       [GNU_AK_TINY_DATA]              = "tiny_data",
+       [GNU_AK_SAVEALL]                = "saveall",
+       [GNU_AK_FLATTEN]                = "flatten",
+       [GNU_AK_SSEREGPARM]             = "sseregparm",
+       [GNU_AK_EXTERNALLY_VISIBLE]     = "externally_visible",
+       [GNU_AK_RETURN_TWICE]           = "return_twice",
+       [GNU_AK_MAY_ALIAS]              = "may_alias",
+       [GNU_AK_MS_STRUCT]              = "ms_struct",
+       [GNU_AK_GCC_STRUCT]             = "gcc_struct",
+       [GNU_AK_ALIGNED]                = "aligned",
+       [GNU_AK_ALIAS]                  = "alias",
+       [GNU_AK_SECTION]                = "section",
+       [GNU_AK_FORMAT]                 = "format",
+       [GNU_AK_FORMAT_ARG]             = "format_arg",
+       [GNU_AK_WEAKREF]                = "weakref",
+       [GNU_AK_NONNULL]                = "nonnull",
+       [GNU_AK_TLS_MODEL]              = "tls_model",
+       [GNU_AK_VISIBILITY]             = "visibility",
+       [GNU_AK_REGPARM]                = "regparm",
+       [GNU_AK_MODEL]                  = "model",
+       [GNU_AK_TRAP_EXIT]              = "trap_exit",
+       [GNU_AK_SP_SWITCH]              = "sp_switch",
+       [GNU_AK_SENTINEL]               = "sentinel"
+};
+
+/**
+ * compare two string, ignoring double underscores on the second.
+ */
+static int strcmp_underscore(const char *s1, const char *s2) {
+       if(s2[0] == '_' && s2[1] == '_') {
+               s2 += 2;
+               size_t l1 = strlen(s1);
+               if(l1 + 2 != strlen(s2)) {
+                       /* not equal */
+                       return 1;
+               }
+               return strncmp(s1, s2, l1);
+       }
+       return strcmp(s1, s2);
+}
+
+/**
+ * Allocate a new gnu temporal attribute.
+ */
+static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind) {
+       gnu_attribute_t *attribute = obstack_alloc(&temp_obst, sizeof(*attribute));
+       attribute->kind           = kind;
+       attribute->next           = NULL;
+       attribute->invalid        = false;
+       attribute->have_arguments = false;
+}
+
+/**
+ * parse one constant expression argument.
+ */
+static void parse_gnu_attribute_const_arg(gnu_attribute_t *attribute) {
+       expression_t *expression;
+       add_anchor_token(')');
+       expression = parse_constant_expression();
+       rem_anchor_token(')');
+       expect(')');
+       (void)expression;
+       return;
+end_error:
+       attribute->invalid = true;
+}
+
+/**
+ * parse a list of constant expressions arguments.
+ */
+static void parse_gnu_attribute_const_arg_list(gnu_attribute_t *attribute) {
+       expression_t *expression;
+       add_anchor_token(')');
+       add_anchor_token(',');
+       while(true){
+               expression = parse_constant_expression();
+               if(token.type != ',')
+                       break;
+               next_token();
+       }
+       rem_anchor_token(',');
+       rem_anchor_token(')');
+       expect(')');
+       (void)expression;
+       return;
+end_error:
+       attribute->invalid = true;
+}
+
+/**
+ * parse one string literal argument.
+ */
+static void parse_gnu_attribute_string_arg(gnu_attribute_t *attribute, string_t *string) {
+       add_anchor_token('(');
+       if(token.type != T_STRING_LITERAL) {
+               parse_error_expected("while parsing attribute directive", T_STRING_LITERAL);
+               goto end_error;
+       }
+       *string = parse_string_literals();
+       rem_anchor_token('(');
+       expect(')');
+       return;
+end_error:
+       attribute->invalid = true;
+}
+
+/**
+ * parse one tls model.
+ */
+static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute) {
+       static const char *tls_models[] = {
+               "global-dynamic",
+               "local-dynamic",
+               "initial-exec",
+               "local-exec"
+       };
+       string_t string = { NULL, 0 };
+       parse_gnu_attribute_string_arg(attribute, &string);
+       if(string.begin != NULL) {
+               for(size_t i = 0; i < 4; ++i) {
+                       if(strcmp(tls_models[i], string.begin) == 0) {
+                               attribute->u.value = i;
+                               return;
+                       }
+               }
+       }
+       errorf(HERE, "'%s' is an unrecognized tls model", string.begin);
+       attribute->invalid = true;
+}
+
+/**
+ * parse one tls model.
+ */
+static void parse_gnu_attribute_visibility_arg(gnu_attribute_t *attribute) {
+       static const char *visibilities[] = {
+               "default",
+               "protected",
+               "hidden",
+               "internal"
+       };
+       string_t string = { NULL, 0 };
+       parse_gnu_attribute_string_arg(attribute, &string);
+       if(string.begin != NULL) {
+               for(size_t i = 0; i < 4; ++i) {
+                       if(strcmp(visibilities[i], string.begin) == 0) {
+                               attribute->u.value = i;
+                               return;
+                       }
+               }
+       }
+       errorf(HERE, "'%s' is an unrecognized visibility", string.begin);
+       attribute->invalid = true;
+}
+
+/**
+ * parse one (code) model.
+ */
+static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute) {
+       static const char *visibilities[] = {
+               "small",
+               "medium",
+               "large"
+       };
+       string_t string = { NULL, 0 };
+       parse_gnu_attribute_string_arg(attribute, &string);
+       if(string.begin != NULL) {
+               for(int i = 0; i < 3; ++i) {
+                       if(strcmp(visibilities[i], string.begin) == 0) {
+                               attribute->u.value = i;
+                               return;
+                       }
+               }
+       }
+       errorf(HERE, "'%s' is an unrecognized model", string.begin);
+       attribute->invalid = true;
+}
+
+/**
+ * parse one interrupt argument.
+ */
+static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute) {
+       static const char *interrupts[] = {
+               "IRQ",
+               "FIQ",
+               "SWI",
+               "ABORT",
+               "UNDEF"
+       };
+       string_t string = { NULL, 0 };
+       parse_gnu_attribute_string_arg(attribute, &string);
+       if(string.begin != NULL) {
+               for(size_t i = 0; i < 5; ++i) {
+                       if(strcmp(interrupts[i], string.begin) == 0) {
+                               attribute->u.value = i;
+                               return;
+                       }
+               }
+       }
+       errorf(HERE, "'%s' is an interrupt", string.begin);
+       attribute->invalid = true;
+}
+
+/**
+ * parse ( identifier, const expression, const expression )
+ */
+static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute) {
+       static const char *format_names[] = {
+               "printf",
+               "scanf",
+               "strftime",
+               "strfmon"
+       };
+       int i;
+
+       if(token.type != T_IDENTIFIER) {
+               parse_error_expected("while parsing format attribute directive", T_IDENTIFIER);
+               goto end_error;
+       }
+       const char *name = token.v.symbol->string;
+       for(i = 0; i < 4; ++i) {
+               if(strcmp_underscore(format_names[i], name) == 0)
+                       break;
+       }
+       if(i >= 4) {
+               if(warning.attribute)
+                       warningf(HERE, "'%s' is an unrecognized format function type", name);
+       }
+       next_token();
+
+       expect(',');
+       add_anchor_token(')');
+       add_anchor_token(',');
+       parse_constant_expression();
+       rem_anchor_token(',');
+       rem_anchor_token('(');
+
+       expect(',');
+       add_anchor_token(')');
+       parse_constant_expression();
+       rem_anchor_token('(');
+       expect(')');
+       return;
+end_error:
+       attribute->u.value = true;
+}
+
+/**
+ * Parse one GNU attribute.
+ *
+ * Note that attribute names can be specified WITH or WITHOUT
+ * double underscores, ie const or __const__.
+ *
+ * The following attributes are parsed without arguments
+ *  const
+ *  volatile
+ *  cdecl
+ *  stdcall
+ *  fastcall
+ *  deprecated
+ *  noinline
+ *  noreturn
+ *  naked
+ *  pure
+ *  always_inline
+ *  malloc
+ *  weak
+ *  constructor
+ *  destructor
+ *  nothrow
+ *  transparent_union
+ *  common
+ *  nocommon
+ *  packed
+ *  shared
+ *  notshared
+ *  used
+ *  unused
+ *  no_instrument_function
+ *  warn_unused_result
+ *  longcall
+ *  shortcall
+ *  long_call
+ *  short_call
+ *  function_vector
+ *  interrupt_handler
+ *  nmi_handler
+ *  nesting
+ *  near
+ *  far
+ *  signal
+ *  eightbit_data
+ *  tiny_data
+ *  saveall
+ *  flatten
+ *  sseregparm
+ *  externally_visible
+ *  return_twice
+ *  may_alias
+ *  ms_struct
+ *  gcc_struct
+ *
+ * The following attributes are parsed with arguments
+ *  aligned( const expression )
+ *  alias( string literal )
+ *  section( string literal )
+ *  format( identifier, const expression, const expression )
+ *  format_arg( const expression )
+ *  tls_model( string literal )
+ *  visibility( string literal )
+ *  regparm( const expression )
+ *  model( string leteral )
+ *  trap_exit( const expression )
+ *  sp_switch( string literal )
+ *
+ * The following attributes might have arguments
+ *  weak_ref( string literal )
+ *  non_null( const expression // ',' )
+ *  interrupt( string literal )
+ *  sentinel( constant expression )
+ */
+static void parse_gnu_attribute(gnu_attribute_t **attributes)
 {
-       while(true) {
-               switch(token.type) {
-               case T___attribute__: {
+       gnu_attribute_t *head = *attributes;
+       gnu_attribute_t *last = *attributes;
+       gnu_attribute_t *attribute;
+
+       eat(T___attribute__);
+       expect('(');
+       expect('(');
+
+       if(token.type != ')') {
+               /* find the end of the list */
+               if(last != NULL) {
+                       while(last->next != NULL)
+                               last = last->next;
+               }
+
+               /* non-empty attribute list */
+               while(true) {
+                       const char *name;
+                       if(token.type == T_const) {
+                               name = "const";
+                       } else if(token.type == T_volatile) {
+                               name = "volatile";
+                       } else if(token.type == T_cdecl) {
+                               /* __attribute__((cdecl)), WITH ms mode */
+                               name = "cdecl";
+                       } else if(token.type != T_IDENTIFIER) {
+                               parse_error_expected("while parsing GNU attribute", T_IDENTIFIER);
+                               break;
+                       }
+                       const symbol_t *sym = token.v.symbol;
+                       name = sym->string;
                        next_token();
 
-                       expect('(');
-                       int depth = 1;
-                       while(depth > 0) {
-                               switch(token.type) {
-                               case T_EOF:
-                                       errorf(HERE, "EOF while parsing attribute");
+                       int i;
+                       for(i = 0; i < GNU_AK_LAST; ++i) {
+                               if(strcmp_underscore(gnu_attribute_names[i], name) == 0)
                                        break;
-                               case '(':
+                       }
+                       gnu_attribute_kind_t kind = (gnu_attribute_kind_t)i;
+
+                       attribute = NULL;
+                       if(kind == GNU_AK_LAST) {
+                               if(warning.attribute)
+                                       warningf(HERE, "'%s' attribute directive ignored", name);
+
+                               /* skip possible arguments */
+                               if(token.type == '(') {
+                                       eat_until_matching_token(')');
+                               }
+                       } else {
+                               /* check for arguments */
+                               attribute = allocate_gnu_attribute(kind);
+                               if(token.type == '(') {
                                        next_token();
-                                       depth++;
+                                       if(token.type == ')') {
+                                               /* empty args are allowed */
+                                               next_token();
+                                       } else
+                                               attribute->have_arguments = true;
+                               }
+
+                               switch(kind) {
+                               case GNU_AK_CONST:
+                               case GNU_AK_VOLATILE:
+                               case GNU_AK_CDECL:
+                               case GNU_AK_STDCALL:
+                               case GNU_AK_FASTCALL:
+                               case GNU_AK_DEPRECATED:
+                               case GNU_AK_NOINLINE:
+                               case GNU_AK_NORETURN:
+                               case GNU_AK_NAKED:
+                               case GNU_AK_PURE:
+                               case GNU_AK_ALWAYS_INLINE:
+                               case GNU_AK_MALLOC:
+                               case GNU_AK_WEAK:
+                               case GNU_AK_CONSTRUCTOR:
+                               case GNU_AK_DESTRUCTOR:
+                               case GNU_AK_NOTHROW:
+                               case GNU_AK_TRANSPARENT_UNION:
+                               case GNU_AK_COMMON:
+                               case GNU_AK_NOCOMMON:
+                               case GNU_AK_PACKED:
+                               case GNU_AK_SHARED:
+                               case GNU_AK_NOTSHARED:
+                               case GNU_AK_USED:
+                               case GNU_AK_UNUSED:
+                               case GNU_AK_NO_INSTRUMENT_FUNCTION:
+                               case GNU_AK_WARN_UNUSED_RESULT:
+                               case GNU_AK_LONGCALL:
+                               case GNU_AK_SHORTCALL:
+                               case GNU_AK_LONG_CALL:
+                               case GNU_AK_SHORT_CALL:
+                               case GNU_AK_FUNCTION_VECTOR:
+                               case GNU_AK_INTERRUPT_HANDLER:
+                               case GNU_AK_NMI_HANDLER:
+                               case GNU_AK_NESTING:
+                               case GNU_AK_NEAR:
+                               case GNU_AK_FAR:
+                               case GNU_AK_SIGNAL:
+                               case GNU_AK_EIGTHBIT_DATA:
+                               case GNU_AK_TINY_DATA:
+                               case GNU_AK_SAVEALL:
+                               case GNU_AK_FLATTEN:
+                               case GNU_AK_SSEREGPARM:
+                               case GNU_AK_EXTERNALLY_VISIBLE:
+                               case GNU_AK_RETURN_TWICE:
+                               case GNU_AK_MAY_ALIAS:
+                               case GNU_AK_MS_STRUCT:
+                               case GNU_AK_GCC_STRUCT:
+                                       if(attribute->have_arguments) {
+                                               /* should have no arguments */
+                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+                                               eat_until_matching_token('(');
+                                               /* we have already consumed '(', so we stop before ')', eat it */
+                                               eat(')');
+                                               attribute->invalid = true;
+                                       }
                                        break;
-                               case ')':
-                                       next_token();
-                                       depth--;
+
+                               case GNU_AK_ALIGNED:
+                               case GNU_AK_FORMAT_ARG:
+                               case GNU_AK_REGPARM:
+                               case GNU_AK_TRAP_EXIT:
+                                       if(!attribute->have_arguments) {
+                                               /* should have arguments */
+                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+                                               attribute->invalid = true;
+                                       } else
+                                               parse_gnu_attribute_const_arg(attribute);
                                        break;
-                               default:
-                                       next_token();
+                               case GNU_AK_ALIAS:
+                               case GNU_AK_SECTION:
+                               case GNU_AK_SP_SWITCH:
+                                       if(!attribute->have_arguments) {
+                                               /* should have arguments */
+                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+                                               attribute->invalid = true;
+                                       } else
+                                               parse_gnu_attribute_string_arg(attribute, &attribute->u.string);
+                                       break;
+                               case GNU_AK_FORMAT:
+                                       if(!attribute->have_arguments) {
+                                               /* should have arguments */
+                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+                                               attribute->invalid = true;
+                                       } else
+                                               parse_gnu_attribute_format_args(attribute);
+                                       break;
+                               case GNU_AK_WEAKREF:
+                                       /* may have one string argument */
+                                       if(attribute->have_arguments)
+                                               parse_gnu_attribute_string_arg(attribute, &attribute->u.string);
+                                       break;
+                               case GNU_AK_NONNULL:
+                                       if(attribute->have_arguments)
+                                               parse_gnu_attribute_const_arg_list(attribute);
+                                       break;
+                               case GNU_AK_TLS_MODEL:
+                                       if(!attribute->have_arguments) {
+                                               /* should have arguments */
+                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+                                       } else
+                                               parse_gnu_attribute_tls_model_arg(attribute);
+                                       break;
+                               case GNU_AK_VISIBILITY:
+                                       if(!attribute->have_arguments) {
+                                               /* should have arguments */
+                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+                                       } else
+                                               parse_gnu_attribute_visibility_arg(attribute);
+                                       break;
+                               case GNU_AK_MODEL:
+                                       if(!attribute->have_arguments) {
+                                               /* should have arguments */
+                                               errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
+                                       } else
+                                               parse_gnu_attribute_model_arg(attribute);
+                               case GNU_AK_INTERRUPT:
+                                       /* may have one string argument */
+                                       if(attribute->have_arguments)
+                                               parse_gnu_attribute_interrupt_arg(attribute);
+                                       break;
+                               case GNU_AK_SENTINEL:
+                                       /* may have one string argument */
+                                       if(attribute->have_arguments)
+                                               parse_gnu_attribute_const_arg(attribute);
+                                       break;
+                               case GNU_AK_LAST:
+                                       /* already handled */
+                                       break;
+                               }
+                       }
+                       if(attribute != NULL) {
+                               if(last != NULL) {
+                                       last->next = attribute;
+                                       last       = attribute;
+                               } else {
+                                       head = last = attribute;
                                }
                        }
+
+                       if(token.type != ',')
+                               break;
+                       next_token();
+               }
+       }
+       expect(')');
+       expect(')');
+end_error:
+       *attributes = head;
+}
+
+/**
+ * Parse GNU attributes.
+ */
+static void parse_attributes(gnu_attribute_t **attributes)
+{
+       while(true) {
+               switch(token.type) {
+               case T___attribute__: {
+                       parse_gnu_attribute(attributes);
                        break;
                }
                case T_asm:
@@ -984,9 +1578,9 @@ static void parse_attributes(void)
                }
        }
 
-end_error:
 attributes_finished:
-       ;
+end_error:
+       return;
 }
 
 static designator_t *parse_designation(void)
@@ -1101,7 +1695,8 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
                }
        }
 
-       type_t *const res_type = semantic_assign(type, expression, "initializer");
+       type_t *const res_type = semantic_assign(type, expression, "initializer",
+                       expression->base.source_position);
        if (res_type == NULL)
                return NULL;
 
@@ -1149,8 +1744,8 @@ static initializer_t *parse_scalar_initializer(type_t *type,
 
        if(initializer == NULL) {
                errorf(expression->base.source_position,
-                      "expression '%E' doesn't match expected type '%T'",
-                      expression, type);
+                      "expression '%E' (type '%T') doesn't match expected type '%T'",
+                      expression, expression->base.type, type);
                /* TODO */
                return NULL;
        }
@@ -1215,7 +1810,7 @@ static __attribute__((unused)) void debug_print_type_path(
                        }
                        fprintf(stderr, ".%s", entry->v.compound_entry->symbol->string);
                } else if(is_type_array(type)) {
-                       fprintf(stderr, "[%u]", entry->v.index);
+                       fprintf(stderr, "[%zd]", entry->v.index);
                } else {
                        fprintf(stderr, "-INVALID-");
                }
@@ -1756,6 +2351,7 @@ static declaration_t *append_declaration(declaration_t *declaration);
 
 static declaration_t *parse_compound_type_specifier(bool is_struct)
 {
+       gnu_attribute_t *attributes = NULL;
        if(is_struct) {
                eat(T_struct);
        } else {
@@ -1766,8 +2362,7 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
        declaration_t *declaration = NULL;
 
        if (token.type == T___attribute__) {
-               /* TODO */
-               parse_attributes();
+               parse_attributes(&attributes);
        }
 
        if(token.type == T_IDENTIFIER) {
@@ -1814,7 +2409,7 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
                declaration->init.is_defined = true;
 
                parse_compound_type_entries(declaration);
-               parse_attributes();
+               parse_attributes(&attributes);
        }
 
        return declaration;
@@ -1872,11 +2467,11 @@ end_error:
 
 static type_t *parse_enum_specifier(void)
 {
-       eat(T_enum);
-
-       declaration_t *declaration;
-       symbol_t      *symbol;
+       gnu_attribute_t *attributes = NULL;
+       declaration_t   *declaration;
+       symbol_t        *symbol;
 
+       eat(T_enum);
        if(token.type == T_IDENTIFIER) {
                symbol = token.v.symbol;
                next_token();
@@ -1913,7 +2508,7 @@ static type_t *parse_enum_specifier(void)
                declaration->init.is_defined = 1;
 
                parse_enum_entries(type);
-               parse_attributes();
+               parse_attributes(&attributes);
        }
 
        return type;
@@ -1995,9 +2590,14 @@ typedef enum {
        SPECIFIER_FLOAT     = 1 << 8,
        SPECIFIER_BOOL      = 1 << 9,
        SPECIFIER_VOID      = 1 << 10,
+       SPECIFIER_INT8      = 1 << 11,
+       SPECIFIER_INT16     = 1 << 12,
+       SPECIFIER_INT32     = 1 << 13,
+       SPECIFIER_INT64     = 1 << 14,
+       SPECIFIER_INT128    = 1 << 15,
 #ifdef PROVIDE_COMPLEX
-       SPECIFIER_COMPLEX   = 1 << 11,
-       SPECIFIER_IMAGINARY = 1 << 12,
+       SPECIFIER_COMPLEX   = 1 << 16,
+       SPECIFIER_IMAGINARY = 1 << 17,
 #endif
 } specifiers_t;
 
@@ -2157,8 +2757,10 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe
                        expect(')');
                } else if(symbol == sym_deprecated) {
                        next_token();
-                       DET_MOD(deprecated, DM_DEPRECATED);
-               if(token.type == '(') {
+                       if(specifiers->deprecated != 0)
+                               warningf(HERE, "deprecated used more than once");
+                       specifiers->deprecated = 1;
+                       if(token.type == '(') {
                                next_token();
                                if(token.type == T_STRING_LITERAL) {
                                        specifiers->deprecated_string = token.v.string.begin;
@@ -2213,7 +2815,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_STORAGE_CLASS(T_auto,     STORAGE_CLASS_AUTO)
                MATCH_STORAGE_CLASS(T_register, STORAGE_CLASS_REGISTER)
 
-               case T_declspec:
+               case T__declspec:
                        next_token();
                        expect('(');
                        add_anchor_token(')');
@@ -2253,6 +2855,11 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_TYPE_QUALIFIER(T_const,    TYPE_QUALIFIER_CONST);
                MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
                MATCH_TYPE_QUALIFIER(T_volatile, TYPE_QUALIFIER_VOLATILE);
+               MATCH_TYPE_QUALIFIER(T__w64,     TYPE_QUALIFIER_W64);
+               MATCH_TYPE_QUALIFIER(T___ptr32,  TYPE_QUALIFIER_PTR32);
+               MATCH_TYPE_QUALIFIER(T___ptr64,  TYPE_QUALIFIER_PTR64);
+               MATCH_TYPE_QUALIFIER(T___uptr,   TYPE_QUALIFIER_UPTR);
+               MATCH_TYPE_QUALIFIER(T___sptr,   TYPE_QUALIFIER_SPTR);
 
                case T___extension__:
                        /* TODO */
@@ -2279,11 +2886,16 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                MATCH_SPECIFIER(T_signed,     SPECIFIER_SIGNED,    "signed")
                MATCH_SPECIFIER(T_unsigned,   SPECIFIER_UNSIGNED,  "unsigned")
                MATCH_SPECIFIER(T__Bool,      SPECIFIER_BOOL,      "_Bool")
+               MATCH_SPECIFIER(T__int8,      SPECIFIER_INT8,      "_int8")
+               MATCH_SPECIFIER(T__int16,     SPECIFIER_INT16,     "_int16")
+               MATCH_SPECIFIER(T__int32,     SPECIFIER_INT32,     "_int32")
+               MATCH_SPECIFIER(T__int64,     SPECIFIER_INT64,     "_int64")
+               MATCH_SPECIFIER(T__int128,    SPECIFIER_INT128,    "_int128")
 #ifdef PROVIDE_COMPLEX
                MATCH_SPECIFIER(T__Complex,   SPECIFIER_COMPLEX,   "_Complex")
                MATCH_SPECIFIER(T__Imaginary, SPECIFIER_IMAGINARY, "_Imaginary")
 #endif
-               case T_forceinline:
+               case T__forceinline:
                        /* only in microsoft mode */
                        specifiers->decl_modifiers |= DM_FORCEINLINE;
 
@@ -2327,7 +2939,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        break;
 
                case T___attribute__:
-                       parse_attributes();
+                       parse_attributes(&specifiers->gnu_attributes);
                        break;
 
                case T_IDENTIFIER: {
@@ -2411,6 +3023,52 @@ finish_specifiers:
                        | SPECIFIER_INT:
                        atomic_type = ATOMIC_TYPE_ULONGLONG;
                        break;
+
+               case SPECIFIER_UNSIGNED | SPECIFIER_INT8:
+                       atomic_type = unsigned_int8_type_kind;
+                       break;
+
+               case SPECIFIER_UNSIGNED | SPECIFIER_INT16:
+                       atomic_type = unsigned_int16_type_kind;
+                       break;
+
+               case SPECIFIER_UNSIGNED | SPECIFIER_INT32:
+                       atomic_type = unsigned_int32_type_kind;
+                       break;
+
+               case SPECIFIER_UNSIGNED | SPECIFIER_INT64:
+                       atomic_type = unsigned_int64_type_kind;
+                       break;
+
+               case SPECIFIER_UNSIGNED | SPECIFIER_INT128:
+                       atomic_type = unsigned_int128_type_kind;
+                       break;
+
+               case SPECIFIER_INT8:
+               case SPECIFIER_SIGNED | SPECIFIER_INT8:
+                       atomic_type = int8_type_kind;
+                       break;
+
+               case SPECIFIER_INT16:
+               case SPECIFIER_SIGNED | SPECIFIER_INT16:
+                       atomic_type = int16_type_kind;
+                       break;
+
+               case SPECIFIER_INT32:
+               case SPECIFIER_SIGNED | SPECIFIER_INT32:
+                       atomic_type = int32_type_kind;
+                       break;
+
+               case SPECIFIER_INT64:
+               case SPECIFIER_SIGNED | SPECIFIER_INT64:
+                       atomic_type = int64_type_kind;
+                       break;
+
+               case SPECIFIER_INT128:
+               case SPECIFIER_SIGNED | SPECIFIER_INT128:
+                       atomic_type = int128_type_kind;
+                       break;
+
                case SPECIFIER_FLOAT:
                        atomic_type = ATOMIC_TYPE_FLOAT;
                        break;
@@ -2476,6 +3134,7 @@ finish_specifiers:
        }
 
        type->base.qualifiers = type_qualifiers;
+       /* FIXME: check type qualifiers here */
 
        type_t *result = typehash_insert(type);
        if(newtype && result != type) {
@@ -2497,6 +3156,12 @@ static type_qualifiers_t parse_type_qualifiers(void)
                MATCH_TYPE_QUALIFIER(T_const,    TYPE_QUALIFIER_CONST);
                MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
                MATCH_TYPE_QUALIFIER(T_volatile, TYPE_QUALIFIER_VOLATILE);
+               /* microsoft extended type modifiers */
+               MATCH_TYPE_QUALIFIER(T__w64,     TYPE_QUALIFIER_W64);
+               MATCH_TYPE_QUALIFIER(T___ptr32,  TYPE_QUALIFIER_PTR32);
+               MATCH_TYPE_QUALIFIER(T___ptr64,  TYPE_QUALIFIER_PTR64);
+               MATCH_TYPE_QUALIFIER(T___uptr,   TYPE_QUALIFIER_UPTR);
+               MATCH_TYPE_QUALIFIER(T___sptr,   TYPE_QUALIFIER_SPTR);
 
                default:
                        return type_qualifiers;
@@ -2762,6 +3427,7 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration,
         * how to construct the final declarator type */
        construct_type_t *first = NULL;
        construct_type_t *last  = NULL;
+       gnu_attribute_t  *attributes = NULL;
 
        /* pointers */
        while(token.type == '*') {
@@ -2777,7 +3443,7 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration,
        }
 
        /* TODO: find out if this is correct */
-       parse_attributes();
+       parse_attributes(&attributes);
 
        construct_type_t *inner_types = NULL;
 
@@ -2841,7 +3507,7 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration,
        }
 
 declarator_finished:
-       parse_attributes();
+       parse_attributes(&attributes);
 
        /* append inner_types at the end of the list, we don't to set last anymore
         * as it's not needed anymore */
@@ -2953,6 +3619,7 @@ static declaration_t *parse_declarator(
        declaration_t *const declaration    = allocate_declaration_zero();
        declaration->declared_storage_class = specifiers->declared_storage_class;
        declaration->modifiers              = specifiers->decl_modifiers;
+       declaration->deprecated             = specifiers->deprecated;
        declaration->deprecated_string      = specifiers->deprecated_string;
        declaration->get_property_sym       = specifiers->get_property_sym;
        declaration->put_property_sym       = specifiers->put_property_sym;
@@ -3094,16 +3761,14 @@ static declaration_t *internal_record_declaration(
                        const type_t *prev_type = skip_typeref(previous_declaration->type);
                        if (!types_compatible(type, prev_type)) {
                                errorf(declaration->source_position,
-                                      "declaration '%#T' is incompatible with "
-                                      "previous declaration '%#T'",
-                                      orig_type, symbol, previous_declaration->type, symbol);
-                               errorf(previous_declaration->source_position,
-                                      "previous declaration of '%Y' was here", symbol);
+                                      "declaration '%#T' is incompatible with '%#T' (declared %P)",
+                                      orig_type, symbol, previous_declaration->type, symbol,
+                                  previous_declaration->source_position);
                        } else {
                                unsigned old_storage_class = previous_declaration->storage_class;
                                if (old_storage_class == STORAGE_CLASS_ENUM_ENTRY) {
-                                       errorf(declaration->source_position, "redeclaration of enum entry '%Y'", symbol);
-                                       errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+                                       errorf(declaration->source_position, "redeclaration of enum entry '%Y' (declared %P)",
+                                              symbol, previous_declaration->source_position);
                                        return previous_declaration;
                                }
 
@@ -3145,19 +3810,15 @@ static declaration_t *internal_record_declaration(
 warn_redundant_declaration:
                                        if (warning.redundant_decls) {
                                                warningf(declaration->source_position,
-                                                        "redundant declaration for '%Y'", symbol);
-                                               warningf(previous_declaration->source_position,
-                                                        "previous declaration of '%Y' was here",
-                                                        symbol);
+                                                        "redundant declaration for '%Y' (declared %P)",
+                                                        symbol, previous_declaration->source_position);
                                        }
                                } else if (current_function == NULL) {
                                        if (old_storage_class != STORAGE_CLASS_STATIC &&
                                                        new_storage_class == STORAGE_CLASS_STATIC) {
                                                errorf(declaration->source_position,
-                                                      "static declaration of '%Y' follows non-static declaration",
-                                                      symbol);
-                                               errorf(previous_declaration->source_position,
-                                                      "previous declaration of '%Y' was here", symbol);
+                                                      "static declaration of '%Y' follows non-static declaration (declared %P)",
+                                                      symbol, previous_declaration->source_position);
                                        } else {
                                                if (old_storage_class != STORAGE_CLASS_EXTERN && !is_function_definition) {
                                                        goto warn_redundant_declaration;
@@ -3170,14 +3831,13 @@ warn_redundant_declaration:
                                } else {
                                        if (old_storage_class == new_storage_class) {
                                                errorf(declaration->source_position,
-                                                      "redeclaration of '%Y'", symbol);
+                                                      "redeclaration of '%Y' (declared %P)",
+                                                      symbol, previous_declaration->source_position);
                                        } else {
                                                errorf(declaration->source_position,
-                                                      "redeclaration of '%Y' with different linkage",
-                                                      symbol);
+                                                      "redeclaration of '%Y' with different linkage (declared %P)",
+                                                      symbol, previous_declaration->source_position);
                                        }
-                                       errorf(previous_declaration->source_position,
-                                              "previous declaration of '%Y' was here", symbol);
                                }
                        }
                        return previous_declaration;
@@ -3225,10 +3885,8 @@ static declaration_t *record_function_definition(declaration_t *declaration)
 static void parser_error_multiple_definition(declaration_t *declaration,
                const source_position_t source_position)
 {
-       errorf(source_position, "multiple definition of symbol '%Y'",
-              declaration->symbol);
-       errorf(declaration->source_position,
-              "this is the location of the previous definition.");
+       errorf(source_position, "multiple definition of symbol '%Y' (declared %P)",
+              declaration->symbol, declaration->source_position);
 }
 
 static bool is_declaration_specifier(const token_t *token,
@@ -3794,9 +4452,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
                        if(prev_decl != NULL) {
                                assert(prev_decl->symbol == symbol);
                                errorf(declaration->source_position,
-                                      "multiple declarations of symbol '%Y'", symbol);
-                               errorf(prev_decl->source_position,
-                                      "previous declaration of '%Y' was here", symbol);
+                                      "multiple declarations of symbol '%Y' (declared %P)",
+                                      symbol, prev_decl->source_position);
                        }
                }
 
@@ -3872,16 +4529,6 @@ struct expression_parser_function_t {
 
 expression_parser_function_t expression_parsers[T_LAST_TOKEN];
 
-/**
- * Creates a new invalid expression.
- */
-static expression_t *create_invalid_expression(void)
-{
-       expression_t *expression         = allocate_expression_zero(EXPR_INVALID);
-       expression->base.source_position = token.source_position;
-       return expression;
-}
-
 /**
  * Prints an error message if an expression was expected but not read
  */
@@ -4217,6 +4864,22 @@ static expression_t *parse_reference(void)
        /* this declaration is used */
        declaration->used = true;
 
+       /* check for deprecated functions */
+       if(declaration->deprecated != 0) {
+               const char *prefix = "";
+               if (is_type_function(declaration->type))
+                       prefix = "function ";
+
+               if (declaration->deprecated_string != NULL) {
+                       warningf(source_position,
+                               "%s'%Y' was declared 'deprecated(\"%s\")'", prefix, declaration->symbol,
+                               declaration->deprecated_string);
+               } else {
+                       warningf(source_position,
+                               "%s'%Y' was declared 'deprecated'", prefix, declaration->symbol);
+               }
+       }
+
        return expression;
 }
 
@@ -4350,8 +5013,9 @@ static expression_t *parse_function_keyword(void)
                errorf(HERE, "'__func__' used outside of a function");
        }
 
-       expression_t *expression = allocate_expression_zero(EXPR_FUNCTION);
-       expression->base.type    = type_char_ptr;
+       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
+       expression->base.type     = type_char_ptr;
+       expression->funcname.kind = FUNCNAME_FUNCTION;
 
        return expression;
 }
@@ -4359,14 +5023,44 @@ static expression_t *parse_function_keyword(void)
 static expression_t *parse_pretty_function_keyword(void)
 {
        eat(T___PRETTY_FUNCTION__);
-       /* TODO */
 
        if (current_function == NULL) {
                errorf(HERE, "'__PRETTY_FUNCTION__' used outside of a function");
        }
 
-       expression_t *expression = allocate_expression_zero(EXPR_PRETTY_FUNCTION);
-       expression->base.type    = type_char_ptr;
+       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
+       expression->base.type     = type_char_ptr;
+       expression->funcname.kind = FUNCNAME_PRETTY_FUNCTION;
+
+       return expression;
+}
+
+static expression_t *parse_funcsig_keyword(void)
+{
+       eat(T___FUNCSIG__);
+
+       if (current_function == NULL) {
+               errorf(HERE, "'__FUNCSIG__' used outside of a function");
+       }
+
+       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
+       expression->base.type     = type_char_ptr;
+       expression->funcname.kind = FUNCNAME_FUNCSIG;
+
+       return expression;
+}
+
+static expression_t *parse_funcdname_keyword(void)
+{
+       eat(T___FUNCDNAME__);
+
+       if (current_function == NULL) {
+               errorf(HERE, "'__FUNCDNAME__' used outside of a function");
+       }
+
+       expression_t *expression  = allocate_expression_zero(EXPR_FUNCNAME);
+       expression->base.type     = type_char_ptr;
+       expression->funcname.kind = FUNCNAME_FUNCDNAME;
 
        return expression;
 }
@@ -4669,7 +5363,7 @@ end_error:
  * Parses a MS assume() expression.
  */
 static expression_t *parse_assume(void) {
-       eat(T_assume);
+       eat(T__assume);
 
        expression_t *expression
                = allocate_expression_zero(EXPR_UNARY_ASSUME);
@@ -4686,6 +5380,45 @@ end_error:
        return create_invalid_expression();
 }
 
+/**
+ * Parse a microsoft __noop expression.
+ */
+static expression_t *parse_noop_expression(void) {
+       source_position_t source_position = HERE;
+       eat(T___noop);
+
+       if (token.type == '(') {
+               /* parse arguments */
+               eat('(');
+               add_anchor_token(')');
+               add_anchor_token(',');
+
+               if(token.type != ')') {
+                       while(true) {
+                               (void)parse_assignment_expression();
+                               if(token.type != ',')
+                                       break;
+                               next_token();
+                       }
+               }
+       }
+       rem_anchor_token(',');
+       rem_anchor_token(')');
+       expect(')');
+
+       /* the result is a (int)0 */
+       expression_t *cnst         = allocate_expression_zero(EXPR_CONST);
+       cnst->base.source_position = source_position;
+       cnst->base.type            = type_int;
+       cnst->conste.v.int_value   = 0;
+       cnst->conste.is_ms_noop    = true;
+
+       return cnst;
+
+end_error:
+       return create_invalid_expression();
+}
+
 /**
  * Parses a primary expression.
  */
@@ -4702,6 +5435,8 @@ static expression_t *parse_primary_expression(void)
                case T___FUNCTION__:
                case T___func__:                 return parse_function_keyword();
                case T___PRETTY_FUNCTION__:      return parse_pretty_function_keyword();
+               case T___FUNCSIG__:              return parse_funcsig_keyword();
+               case T___FUNCDNAME__:            return parse_funcdname_keyword();
                case T___builtin_offsetof:       return parse_offsetof();
                case T___builtin_va_start:       return parse_va_start();
                case T___builtin_va_arg:         return parse_va_arg();
@@ -4719,9 +5454,10 @@ static expression_t *parse_primary_expression(void)
                case T___builtin_isunordered:    return parse_compare_builtin();
                case T___builtin_constant_p:     return parse_builtin_constant();
                case T___builtin_prefetch:       return parse_builtin_prefetch();
-               case T_assume:                   return parse_assume();
+               case T__assume:                  return parse_assume();
 
                case '(':                        return parse_brace_expression();
+               case T___noop:                   return parse_noop_expression();
        }
 
        errorf(HERE, "unexpected token %K, expected an expression", &token);
@@ -4920,6 +5656,7 @@ static expression_t *parse_call_expression(unsigned precedence,
 {
        (void) precedence;
        expression_t *result = allocate_expression_zero(EXPR_CALL);
+       result->base.source_position = expression->base.source_position;
 
        call_expression_t *call = &result->call;
        call->function          = expression;
@@ -4977,7 +5714,7 @@ static expression_t *parse_call_expression(unsigned precedence,
                        type_t *expected_type = parameter->type;
                        /* TODO report scope in error messages */
                        expression_t *const arg_expr = argument->expression;
-                       type_t       *const res_type = semantic_assign(expected_type, arg_expr, "function call");
+                       type_t       *const res_type = semantic_assign(expected_type, arg_expr, "function call", arg_expr->base.source_position);
                        if (res_type == NULL) {
                                /* TODO improve error message */
                                errorf(arg_expr->base.source_position,
@@ -5016,22 +5753,6 @@ static expression_t *parse_call_expression(unsigned precedence,
                } else {
                        check_format(&result->call);
                }
-
-               /* check deprecated */
-               if(expression->base.kind == EXPR_REFERENCE) {
-                       const reference_expression_t *ref = (reference_expression_t *)expression;
-                       const declaration_t *declaration = ref->declaration;
-                       if(declaration->modifiers & DM_DEPRECATED) {
-                               if (declaration->deprecated_string != NULL) {
-                                       warningf(result->base.source_position,
-                                               "function '%Y' was declared 'deprecated(%s)'", declaration->symbol,
-                                               declaration->deprecated_string);
-                               } else {
-                                       warningf(result->base.source_position,
-                                               "function '%Y' was declared 'deprecated'", declaration->symbol);
-                               }
-                       }
-               }
        }
 
        return result;
@@ -5085,7 +5806,16 @@ static expression_t *parse_conditional_expression(unsigned precedence,
 
        /* 6.5.15.3 */
        type_t *result_type;
-       if (is_type_arithmetic(true_type) && is_type_arithmetic(false_type)) {
+       if(is_type_atomic(true_type, ATOMIC_TYPE_VOID) ||
+               is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
+               if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID)
+                               || !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
+                       warningf(expression->base.source_position,
+                                       "ISO C forbids conditional expression with only one void side");
+               }
+               result_type = type_void;
+       } else if (is_type_arithmetic(true_type)
+                       && is_type_arithmetic(false_type)) {
                result_type = semantic_arithmetic(true_type, false_type);
 
                true_expression  = create_implicit_cast(true_expression, result_type);
@@ -5094,22 +5824,40 @@ static expression_t *parse_conditional_expression(unsigned precedence,
                conditional->true_expression  = true_expression;
                conditional->false_expression = false_expression;
                conditional->base.type        = result_type;
-       } else if (same_compound_type(true_type, false_type) || (
-           is_type_atomic(true_type, ATOMIC_TYPE_VOID) &&
-           is_type_atomic(false_type, ATOMIC_TYPE_VOID)
-               )) {
+       } else if (same_compound_type(true_type, false_type)) {
                /* just take 1 of the 2 types */
                result_type = true_type;
-       } else if (is_type_pointer(true_type) && is_type_pointer(false_type)
-                       && pointers_compatible(true_type, false_type)) {
-               /* ok */
-               result_type = true_type;
-       } else if (is_type_pointer(true_type)
-                       && is_null_pointer_constant(false_expression)) {
-               result_type = true_type;
-       } else if (is_type_pointer(false_type)
-                       && is_null_pointer_constant(true_expression)) {
-               result_type = false_type;
+       } else if (is_type_pointer(true_type) || is_type_pointer(false_type)) {
+               type_t *pointer_type;
+               type_t *other_type;
+               expression_t *other_expression;
+               if (is_type_pointer(true_type)) {
+                       pointer_type     = true_type;
+                       other_type       = false_type;
+                       other_expression = false_expression;
+               } else {
+                       pointer_type     = false_type;
+                       other_type       = true_type;
+                       other_expression = true_expression;
+               }
+
+               if(is_type_pointer(other_type)) {
+                       if(!pointers_compatible(true_type, false_type)) {
+                               warningf(expression->base.source_position,
+                                               "pointer types '%T' and '%T' in conditional expression are incompatible", true_type, false_type);
+                       }
+                       result_type = true_type;
+               } else if(is_null_pointer_constant(other_expression)) {
+                       result_type = pointer_type;
+               } else if(is_type_integer(other_type)) {
+                       warningf(expression->base.source_position,
+                                       "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type);
+                       result_type = pointer_type;
+               } else {
+                       type_error_incompatible("while parsing conditional",
+                                       expression->base.source_position, true_type, false_type);
+                       result_type = type_error_type;
+               }
        } else {
                /* TODO: one pointer to void*, other some pointer */
 
@@ -5647,7 +6395,7 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
        }
 
        type_t *const res_type = semantic_assign(orig_type_left, expression->right,
-                                                "assignment");
+                       "assignment", left->base.source_position);
        if (res_type == NULL) {
                errorf(expression->base.source_position,
                        "cannot assign to '%T' from '%T'",
@@ -5677,7 +6425,8 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_UNKNOWN:                   break;
                case EXPR_INVALID:                   return true; /* do NOT warn */
                case EXPR_REFERENCE:                 return false;
-               case EXPR_CONST:                     return false;
+               /* suppress the warning for microsoft __noop operations */
+               case EXPR_CONST:                     return expr->conste.is_ms_noop;
                case EXPR_CHARACTER_CONSTANT:        return false;
                case EXPR_WIDE_CHARACTER_CONSTANT:   return false;
                case EXPR_STRING_LITERAL:            return false;
@@ -5709,8 +6458,7 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_CLASSIFY_TYPE:             return false;
                case EXPR_ALIGNOF:                   return false;
 
-               case EXPR_FUNCTION:                  return false;
-               case EXPR_PRETTY_FUNCTION:           return false;
+               case EXPR_FUNCNAME:                  return false;
                case EXPR_BUILTIN_SYMBOL:            break; /* handled in EXPR_CALL */
                case EXPR_BUILTIN_CONSTANT_P:        return false;
                case EXPR_BUILTIN_PREFETCH:          return true;
@@ -6299,9 +7047,8 @@ static statement_t *parse_label_statement(void)
        /* if source position is already set then the label is defined twice,
         * otherwise it was just mentioned in a goto so far */
        if(label->source_position.input_name != NULL) {
-               errorf(HERE, "duplicate label '%Y'", symbol);
-               errorf(label->source_position, "previous definition of '%Y' was here",
-                      symbol);
+               errorf(HERE, "duplicate label '%Y' (declared %P)",
+                      symbol, label->source_position);
        } else {
                label->source_position = token.source_position;
        }
@@ -6685,11 +7432,11 @@ declaration_t *expr_is_variable(const expression_t *expression)
  */
 static statement_t *parse_return(void)
 {
-       eat(T_return);
-
        statement_t *statement          = allocate_statement_zero(STATEMENT_RETURN);
        statement->base.source_position = token.source_position;
 
+       eat(T_return);
+
        expression_t *return_value = NULL;
        if(token.type != ';') {
                return_value = parse_expression();
@@ -6710,7 +7457,7 @@ static statement_t *parse_return(void)
                        return_value = NULL;
                } else {
                        type_t *const res_type = semantic_assign(return_type,
-                               return_value, "'return'");
+                               return_value, "'return'", statement->base.source_position);
                        if (res_type == NULL) {
                                errorf(statement->base.source_position,
                                       "cannot return something of type '%T' in function returning '%T'",