tests for __func__ and friends
[cparser] / parser.c
index ab73613..32a2a9d 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -53,7 +53,8 @@ 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 */
        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. */
@@ -108,6 +109,8 @@ static const symbol_t *sym_selectany  = NULL;
 static const symbol_t *sym_thread     = NULL;
 static const symbol_t *sym_uuid       = NULL;
 static const symbol_t *sym_deprecated = NULL;
+static const symbol_t *sym_restrict   = NULL;
+static const symbol_t *sym_noalias    = NULL;
 
 /** The token anchor set */
 static unsigned char token_anchor_set[T_LAST_TOKEN];
@@ -143,7 +146,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  \
@@ -171,6 +174,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
 
@@ -280,7 +284,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_CHARACTER_CONSTANT]      = sizeof(const_expression_t),
                [EXPR_WIDE_CHARACTER_CONSTANT] = sizeof(const_expression_t),
                [EXPR_STRING_LITERAL]          = sizeof(string_literal_expression_t),
-               [EXPR_WIDE_STRING_LITERAL]   = sizeof(wide_string_literal_expression_t),
+               [EXPR_WIDE_STRING_LITERAL]     = sizeof(wide_string_literal_expression_t),
                [EXPR_COMPOUND_LITERAL]        = sizeof(compound_literal_expression_t),
                [EXPR_CALL]                    = sizeof(call_expression_t),
                [EXPR_UNARY_FIRST]             = sizeof(unary_expression_t),
@@ -293,6 +297,8 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_CLASSIFY_TYPE]           = sizeof(classify_type_expression_t),
                [EXPR_FUNCTION]                = sizeof(string_literal_expression_t),
                [EXPR_PRETTY_FUNCTION]         = sizeof(string_literal_expression_t),
+               [EXPR_FUNCSIG]                 = sizeof(string_literal_expression_t),
+               [EXPR_FUNCDNAME]               = sizeof(string_literal_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),
@@ -936,32 +942,42 @@ static string_t parse_string_literals(void)
        return result;
 }
 
+/**
+ * Parse one GNU attribute.
+ */
+static void parse_gnu_attribute(void)
+{
+       eat(T___attribute__);
+       expect('(');
+       expect('(');
+       while(true) {
+               if(token.type != T_IDENTIFIER)
+                       break;
+               symbol_t *sym = token.v.symbol;
+               if(sym == sym_deprecated) {
+               }
+               next_token();
+               if(token.type == '(')
+                       eat_until_matching_token('(');
+               if(token.type != ',')
+                       break;
+               next_token();
+       }
+       expect(')');
+       expect(')');
+end_error:
+       return;
+}
+
+/**
+ * Parse GNU attributes.
+ */
 static void parse_attributes(void)
 {
        while(true) {
                switch(token.type) {
                case T___attribute__: {
-                       next_token();
-
-                       expect('(');
-                       int depth = 1;
-                       while(depth > 0) {
-                               switch(token.type) {
-                               case T_EOF:
-                                       errorf(HERE, "EOF while parsing attribute");
-                                       break;
-                               case '(':
-                                       next_token();
-                                       depth++;
-                                       break;
-                               case ')':
-                                       next_token();
-                                       depth--;
-                                       break;
-                               default:
-                                       next_token();
-                               }
-                       }
+                       parse_gnu_attribute();
                        break;
                }
                case T_asm:
@@ -1213,7 +1229,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-");
                }
@@ -1473,6 +1489,13 @@ static void skip_initializers(void)
        }
 }
 
+static initializer_t *create_empty_initializer(void)
+{
+       static initializer_t empty_initializer
+               = { .list = { { INITIALIZER_LIST }, 0 } };
+       return &empty_initializer;
+}
+
 /**
  * Parse a part of an initialiser for a struct or union,
  */
@@ -1482,7 +1505,7 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
 {
        if(token.type == '}') {
                /* empty initializer */
-               return NULL;
+               return create_empty_initializer();
        }
 
        type_t *orig_type = path->top_type;
@@ -1497,7 +1520,7 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                 * initializers in this case. */
                if(!is_type_valid(type)) {
                        skip_initializers();
-                       return NULL;
+                       return create_empty_initializer();
                }
        }
 
@@ -1723,7 +1746,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env)
                        break;
 
                default:
-                       panic("invalid initializer type");
+                       internal_errorf(HERE, "invalid initializer type");
                }
 
                expression_t *cnst       = allocate_expression_zero(EXPR_CONST);
@@ -1986,9 +2009,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;
 
@@ -2044,11 +2072,16 @@ static bool check_elignment_value(long long intvalue) {
 
 static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *specifiers)
 {
-       symbol_t         *symbol;
        decl_modifiers_t *modifiers = &specifiers->decl_modifiers;
 
-       while(token.type == T_IDENTIFIER) {
-               symbol = token.v.symbol;
+       while(true) {
+               if(token.type == T_restrict) {
+                       next_token();
+                       DET_MOD(restrict, DM_RESTRICT);
+                       goto end_loop;
+               } else if(token.type != T_IDENTIFIER)
+                       break;
+               symbol_t *symbol = token.v.symbol;
                if(symbol == sym_align) {
                        next_token();
                        expect('(');
@@ -2143,8 +2176,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;
@@ -2154,12 +2189,16 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe
                                }
                                expect(')');
                        }
+               } else if(symbol == sym_noalias) {
+                       next_token();
+                       DET_MOD(noalias, DM_NOALIAS);
                } else {
                        warningf(HERE, "Unknown modifier %Y ignored", token.v.symbol);
                        next_token();
                        if(token.type == '(')
                                skip_until(')');
                }
+end_loop:
                if (token.type == ',')
                        next_token();
        }
@@ -2195,7 +2234,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(')');
@@ -2235,6 +2274,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 */
@@ -2261,11 +2305,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;
 
@@ -2393,6 +2442,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;
@@ -2458,6 +2553,7 @@ finish_specifiers:
        }
 
        type->base.qualifiers = type_qualifiers;
+       /* FIXME: check type qualifiers here */
 
        type_t *result = typehash_insert(type);
        if(newtype && result != type) {
@@ -2479,6 +2575,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;
@@ -2846,7 +2948,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
        for( ; iter != NULL; iter = iter->next) {
                switch(iter->kind) {
                case CONSTRUCT_INVALID:
-                       panic("invalid type construction found");
+                       internal_errorf(HERE, "invalid type construction found");
                case CONSTRUCT_FUNCTION: {
                        construct_function_type_t *construct_function_type
                                = (construct_function_type_t*) iter;
@@ -2935,6 +3037,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;
@@ -4084,7 +4187,7 @@ static type_t *get_builtin_symbol_type(symbol_t *symbol)
        case T___builtin_va_end:
                return make_function_1_type(type_void, type_valist);
        default:
-               panic("not implemented builtin symbol found");
+               internal_errorf(HERE, "not implemented builtin symbol found");
        }
 }
 
@@ -4199,6 +4302,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;
 }
 
@@ -4341,7 +4460,6 @@ 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");
@@ -4353,6 +4471,34 @@ static expression_t *parse_pretty_function_keyword(void)
        return expression;
 }
 
+static expression_t *parse_funcsig_keyword(void)
+{
+       next_token();
+
+       if (current_function == NULL) {
+               errorf(HERE, "'__FUNCSIG__' used outside of a function");
+       }
+
+       expression_t *expression = allocate_expression_zero(EXPR_FUNCSIG);
+       expression->base.type    = type_char_ptr;
+
+       return expression;
+}
+
+static expression_t *parse_funcdname_keyword(void)
+{
+       next_token();
+
+       if (current_function == NULL) {
+               errorf(HERE, "'__FUNCDNAME__' used outside of a function");
+       }
+
+       expression_t *expression = allocate_expression_zero(EXPR_FUNCDNAME);
+       expression->base.type    = type_char_ptr;
+
+       return expression;
+}
+
 static designator_t *parse_designator(void)
 {
        designator_t *result    = allocate_ast_zero(sizeof(result[0]));
@@ -4593,7 +4739,7 @@ static expression_t *parse_compare_builtin(void)
                expression = allocate_expression_zero(EXPR_BINARY_ISUNORDERED);
                break;
        default:
-               panic("invalid compare builtin found");
+               internal_errorf(HERE, "invalid compare builtin found");
                break;
        }
        expression->base.source_position = HERE;
@@ -4651,7 +4797,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);
@@ -4684,6 +4830,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();
@@ -4701,7 +4849,7 @@ 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();
        }
@@ -4902,6 +5050,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;
@@ -5677,6 +5826,8 @@ static bool expression_has_effect(const expression_t *const expr)
 
                case EXPR_FUNCTION:                  return false;
                case EXPR_PRETTY_FUNCTION:           return false;
+               case EXPR_FUNCSIG:                   return false;
+               case EXPR_FUNCDNAME:                 return false;
                case EXPR_BUILTIN_SYMBOL:            break; /* handled in EXPR_CALL */
                case EXPR_BUILTIN_CONSTANT_P:        return false;
                case EXPR_BUILTIN_PREFETCH:          return true;
@@ -5755,7 +5906,7 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_BINARY_ISUNORDERED:        return false;
        }
 
-       panic("unexpected expression");
+       internal_errorf(HERE, "unexpected expression");
 }
 
 static void semantic_comma(binary_expression_t *expression)
@@ -7052,6 +7203,8 @@ void init_parser(void)
                sym_thread     = symbol_table_insert("thread");
                sym_uuid       = symbol_table_insert("uuid");
                sym_deprecated = symbol_table_insert("deprecated");
+               sym_restrict   = symbol_table_insert("restrict");
+               sym_noalias    = symbol_table_insert("noalias");
        }
        memset(token_anchor_set, 0, sizeof(token_anchor_set));