diff options
| -rw-r--r-- | Documentation/IR.md | 356 | ||||
| -rw-r--r-- | Documentation/IR.rst | 411 | ||||
| -rw-r--r-- | Documentation/conf.py | 1 | ||||
| -rw-r--r-- | Documentation/doc-guide.rst | 4 | ||||
| -rw-r--r-- | Documentation/index.rst | 2 | ||||
| -rwxr-xr-x | Documentation/sphinx/ir.py | 75 | ||||
| -rw-r--r-- | builtin.c | 95 | ||||
| -rw-r--r-- | ident-list.h | 1 | ||||
| -rw-r--r-- | lib.c | 1 | ||||
| -rw-r--r-- | pre-process.c | 47 | ||||
| -rw-r--r-- | symbol.c | 9 | ||||
| -rw-r--r-- | symbol.h | 4 | ||||
| -rw-r--r-- | validation/builtin-overflow.c | 246 | ||||
| -rw-r--r-- | validation/preprocessor/has-builtin.c | 43 |
14 files changed, 933 insertions, 362 deletions
diff --git a/Documentation/IR.md b/Documentation/IR.md deleted file mode 100644 index 03fa3f80..00000000 --- a/Documentation/IR.md +++ /dev/null @@ -1,356 +0,0 @@ -# Sparse's Intermediate Representation - - -## Instruction -This document briefly describes which field of struct instruction is -used by which operation. - -Some of those fields are used by almost all instructions, -some others are specific to only one or a few instructions. -The common ones are: -- .src1, .src2, .src3: (pseudo_t) operands of binops or ternary ops. -- .src: (pseudo_t) operand of unary ops (alias for .src1). -- .target: (pseudo_t) result of unary, binary & ternary ops, is sometimes used - otherwise by some others instructions. -- .cond: (pseudo_t) input operands for condition (alias .src/.src1) -- .type: (symbol*) usually the type of .result, sometimes of the operands - -### Terminators -#### OP_RET -Return from subroutine. -- .src : returned value (NULL if void) -- .type: type of .src - -#### OP_BR -Unconditional branch -- .bb_true: destination basic block - -#### OP_CBR -Conditional branch -- .cond: condition -- .type: type of .cond, must be an integral type -- .bb_true, .bb_false: destination basic blocks - -#### OP_SWITCH -Switch / multi-branch -- .cond: condition -- .type: type of .cond, must be an integral type -- .multijmp_list: pairs of case-value - destination basic block - -#### OP_COMPUTEDGOTO -Computed goto / branch to register -- .src: address to branch to (void*) -- .multijmp_list: list of possible destination basic blocks - -### Arithmetic binops -They all follow the same signature: -- .src1, .src1: operands (types must be compatible with .target) -- .target: result of the operation (must be an integral type) -- .type: type of .target - -#### OP_ADD -Integer addition. - -#### OP_SUB -Integer subtraction. - -#### OP_MUL -Integer multiplication. - -#### OP_DIVU -Integer unsigned division. - -#### OP_DIVS -Integer signed division. - -#### OP_MODU -Integer unsigned remainder. - -#### OP_MODS -Integer signed remainder. - -#### OP_SHL -Shift left (integer only) - -#### OP_LSR -Logical Shift right (integer only) - -#### OP_ASR -Arithmetic Shift right (integer only) - -### Floating-point binops -They all follow the same signature: -- .src1, .src1: operands (types must be compatible with .target) -- .target: result of the operation (must be a floating-point type) -- .type: type of .target - -#### OP_FADD -Floating-point addition. - -#### OP_FSUB -Floating-point subtraction. - -#### OP_FMUL -Floating-point multiplication. - -#### OP_FDIV -Floating-point division. - -### Logical ops -They all follow the same signature: -- .src1, .src2: operands (types must be compatible with .target) -- .target: result of the operation -- .type: type of .target, must be an integral type - -#### OP_AND -#### OP_OR -#### OP_XOR - -### Boolean ops -#### OP_AND_BOOL -#### OP_OR_BOOL - -### Integer compares -They all have the following signature: -- .src1, .src2: operands (types must be compatible) -- .target: result of the operation (0/1 valued integer) -- .type: type of .target, must be an integral type - -#### OP_SET_EQ -Compare equal. - -#### OP_SET_NE -Compare not-equal. - -#### OP_SET_LE -Compare less-than-or-equal (signed). - -#### OP_SET_GE -Compare greater-than-or-equal (signed). - -#### OP_SET_LT -Compare less-than (signed). - -#### OP_SET_GT -Compare greater-than (signed). - -#### OP_SET_B -Compare less-than (unsigned). - -#### OP_SET_A -Compare greater-than (unsigned). - -#### OP_SET_BE -Compare less-than-or-equal (unsigned). - -#### OP_SET_AE -Compare greater-than-or-equal (unsigned). - -### Floating-point compares -They all have the same signature as the integer compares. -The usual 6 operations exist in two versions: 'ordered' and -'unordered'. Theses operations first check if any operand is a -NaN and if it is the case the ordered compares return false -and then unordered return true, otherwise the result of the -comparison, now garanted to be done on non-NaNs, is returned. - -#### OP_FCMP_OEQ -Floating-point compare ordered equal - -#### OP_FCMP_ONE -Floating-point compare ordered not-equal - -#### OP_FCMP_OLE -Floating-point compare ordered less-than-or-equal - -#### OP_FCMP_OGE -Floating-point compare ordered greater-or-equal - -#### OP_FCMP_OLT -Floating-point compare ordered less-than - -#### OP_FCMP_OGT -Floating-point compare ordered greater-than - - -#### OP_FCMP_UEQ -Floating-point compare unordered equal - -#### OP_FCMP_UNE -Floating-point compare unordered not-equal - -#### OP_FCMP_ULE -Floating-point compare unordered less-than-or-equal - -#### OP_FCMP_UGE -Floating-point compare unordered greater-or-equal - -#### OP_FCMP_ULT -Floating-point compare unordered less-than - -#### OP_FCMP_UGT -Floating-point compare unordered greater-than - - -#### OP_FCMP_ORD -Floating-point compare ordered: return true if both operands are ordered -(none of the operands are a NaN) and false otherwise. - -#### OP_FCMP_UNO -Floating-point compare unordered: return false if no operands is ordered -and true otherwise. - -### Unary ops -#### OP_NOT -Logical not. -- .src: operand (type must be compatible with .target) -- .target: result of the operation -- .type: type of .target, must be an integral type - -#### OP_NEG -Integer negation. -- .src: operand (type must be compatible with .target) -- .target: result of the operation (must be an integral type) -- .type: type of .target - -#### OP_FNEG -Floating-point negation. -- .src: operand (type must be compatible with .target) -- .target: result of the operation (must be a floating-point type) -- .type: type of .target - -#### OP_COPY -Copy (only needed after out-of-SSA). -- .src: operand (type must be compatible with .target) -- .target: result of the operation -- .type: type of .target - -### Type conversions -They all have the following signature: -- .src: source value -- .orig_type: type of .src -- .target: result value -- .type: type of .target - -#### OP_CAST -Cast to unsigned integer (and to void pointer). - -#### OP_SCAST -Cast to signed integer. - -#### OP_FPCAST -Cast to floating-point. - -#### OP_PTRCAST -Cast to pointer. - -### Ternary ops -#### OP_SEL -- .src1: condition, must be of integral type -- .src2, .src3: operands (types must be compatible with .target) -- .target: result of the operation -- .type: type of .target - -#### OP_RANGE -Range/bounds checking (only used for an unused sparse extension). -- .src1: value to be checked -- .src2, src3: bound of the value (must be constants?) -- .type: type of .src[123]? - -### Memory ops -#### OP_LOAD -Load. -- .src: base address to load from -- .offset: address offset -- .target: loaded value -- .type: type of .target - -#### OP_STORE -Store. -- .src: base address to store to -- .offset: address offset -- .target: value to be stored -- .type: type of .target - -### Others -#### OP_SYMADDR -Create a pseudo corresponding to the address of a symbol. -- .symbol: (pseudo_t) input symbol (alias .src) -- .target: symbol's address - -#### OP_SETFVAL -Create a pseudo corresponding to a floating-point literal. -- .fvalue: the literal's value (long double) -- .target: the corresponding pseudo -- .type: type of the literal & .target - -#### OP_SETVAL -Create a pseudo corresponding to a string literal or a label-as-value. -The value is given as an expression EXPR_STRING or EXPR_LABEL. -- .val: (expression) input expression -- .target: the resulting value -- .type: type of .target, the value - -#### OP_PHI -Phi-node (for SSA form). -- .phi_list: phi-operands (type must be compatible with .target) -- .target: "result" -- .type: type of .target - -#### OP_PHISOURCE -Phi-node source. -Like OP_COPY but exclusively used to give a defining instructions -(and thus also a type) to *all* OP_PHI operands. -- .phi_src: operand (type must be compatible with .target, alias .src) -- .target: the "result" PSEUDO_PHI -- .type: type of .target -- .phi_users: list of phi instructions using the target pseudo - -#### OP_CALL -Function call. -- .func: (pseudo_t) the function (can be a symbol or a "register", alias .src)) -- .arguments: (pseudo_list) list of the associated arguments -- .target: function return value (if any) -- .type: type of .target -- .fntypes: (symbol_list) list of the function's types: the first enrty is the full function type, the next ones are the type of each arguments - -#### OP_INLINED_CALL -Only used as an annotation to show that the instructions just above -correspond to a function that have been inlined. -- .func: (pseudo_t) the function (must be a symbol, alias .src)) -- .arguments: list of pseudos that where the function's arguments -- .target: function return value (if any) -- .type: type of .target - -#### OP_SLICE -Extract a "slice" from an aggregate. -- .base: (pseudo_t) aggregate (alias .src) -- .from, .len: offet & size of the "slice" within the aggregate -- .target: result -- .type: type of .target - -#### OP_ASM -Inlined assembly code. -- .string: asm template -- .asm_rules: asm constraints, rules - -### Sparse tagging (line numbers, context, whatever) -#### OP_CONTEXT -Currently only used for lock/unlock tracking. -- .context_expr: unused -- .increment: (1 for locking, -1 for unlocking) -- .check: (ignore the instruction if 0) - -### Misc ops -#### OP_ENTRY -Function entry point (no associated semantic). - -#### OP_BADOP -Invalid operation (should never be generated). - -#### OP_NOP -No-op (should never be generated). - -#### OP_DEATHNOTE -Annotation telling the pseudo will be death after the next -instruction (other than some other annotation, that is). diff --git a/Documentation/IR.rst b/Documentation/IR.rst new file mode 100644 index 00000000..67ef06a5 --- /dev/null +++ b/Documentation/IR.rst @@ -0,0 +1,411 @@ +.. default-domain:: ir + +Sparse's Intermediate Representation +==================================== + +Instructions +~~~~~~~~~~~~ + +This document briefly describes which field of struct instruction is +used by which operation. + +Some of those fields are used by almost all instructions, +some others are specific to only one or a few instructions. +The common ones are: + +* .src1, .src2, .src3: (pseudo_t) operands of binops or ternary ops. +* .src: (pseudo_t) operand of unary ops (alias for .src1). +* .target: (pseudo_t) result of unary, binary & ternary ops, is + sometimes used otherwise by some others instructions. +* .cond: (pseudo_t) input operands for condition (alias .src/.src1) +* .type: (symbol*) usually the type of .result, sometimes of the operands + +Terminators +----------- +.. op:: OP_RET + Return from subroutine. + + * .src : returned value (NULL if void) + * .type: type of .src + +.. op:: OP_BR + Unconditional branch + + * .bb_true: destination basic block + +.. op:: OP_CBR + Conditional branch + + * .cond: condition + * .type: type of .cond, must be an integral type + * .bb_true, .bb_false: destination basic blocks + +.. op:: OP_SWITCH + Switch / multi-branch + + * .cond: condition + * .type: type of .cond, must be an integral type + * .multijmp_list: pairs of case-value - destination basic block + +.. op:: OP_COMPUTEDGOTO + Computed goto / branch to register + + * .src: address to branch to (void*) + * .multijmp_list: list of possible destination basic blocks + +Arithmetic binops +----------------- +They all follow the same signature: + * .src1, .src1: operands (types must be compatible with .target) + * .target: result of the operation (must be an integral type) + * .type: type of .target + +.. op:: OP_ADD + Integer addition. + +.. op:: OP_SUB + Integer subtraction. + +.. op:: OP_MUL + Integer multiplication. + +.. op:: OP_DIVU + Integer unsigned division. + +.. op:: OP_DIVS + Integer signed division. + +.. op:: OP_MODU + Integer unsigned remainder. + +.. op:: OP_MODS + Integer signed remainder. + +.. op:: OP_SHL + Shift left (integer only) + +.. op:: OP_LSR + Logical Shift right (integer only) + +.. op:: OP_ASR + Arithmetic Shift right (integer only) + +Floating-point binops +--------------------- +They all follow the same signature: + * .src1, .src1: operands (types must be compatible with .target) + * .target: result of the operation (must be a floating-point type) + * .type: type of .target + +.. op:: OP_FADD + Floating-point addition. + +.. op:: OP_FSUB + Floating-point subtraction. + +.. op:: OP_FMUL + Floating-point multiplication. + +.. op:: OP_FDIV + Floating-point division. + +Logical ops +----------- +They all follow the same signature: + * .src1, .src2: operands (types must be compatible with .target) + * .target: result of the operation + * .type: type of .target, must be an integral type + +.. op:: OP_AND + Logical AND + +.. op:: OP_OR + Logical OR + +.. op:: OP_XOR + Logical XOR + +Boolean ops +----------- +.. op:: OP_AND_BOOL + Boolean AND + +.. op:: OP_OR_BOOL + Boolean OR + +Integer compares +---------------- +They all have the following signature: + * .src1, .src2: operands (types must be compatible) + * .target: result of the operation (0/1 valued integer) + * .type: type of .target, must be an integral type + +.. op:: OP_SET_EQ + Compare equal. + +.. op:: OP_SET_NE + Compare not-equal. + +.. op:: OP_SET_LE + Compare less-than-or-equal (signed). + +.. op:: OP_SET_GE + Compare greater-than-or-equal (signed). + +.. op:: OP_SET_LT + Compare less-than (signed). + +.. op:: OP_SET_GT + Compare greater-than (signed). + +.. op:: OP_SET_B + Compare less-than (unsigned). + +.. op:: OP_SET_A + Compare greater-than (unsigned). + +.. op:: OP_SET_BE + Compare less-than-or-equal (unsigned). + +.. op:: OP_SET_AE + Compare greater-than-or-equal (unsigned). + +Floating-point compares +----------------------- +They all have the same signature as the integer compares. + +The usual 6 operations exist in two versions: 'ordered' and +'unordered'. These operations first check if any operand is a +NaN and if it is the case the ordered compares return false +and then unordered return true, otherwise the result of the +comparison, now guaranteed to be done on non-NaNs, is returned. + +.. op:: OP_FCMP_OEQ + Floating-point compare ordered equal + +.. op:: OP_FCMP_ONE + Floating-point compare ordered not-equal + +.. op:: OP_FCMP_OLE + Floating-point compare ordered less-than-or-equal + +.. op:: OP_FCMP_OGE + Floating-point compare ordered greater-or-equal + +.. op:: OP_FCMP_OLT + Floating-point compare ordered less-than + +.. op:: OP_FCMP_OGT + Floating-point compare ordered greater-than + + +.. op:: OP_FCMP_UEQ + Floating-point compare unordered equal + +.. op:: OP_FCMP_UNE + Floating-point compare unordered not-equal + +.. op:: OP_FCMP_ULE + Floating-point compare unordered less-than-or-equal + +.. op:: OP_FCMP_UGE + Floating-point compare unordered greater-or-equal + +.. op:: OP_FCMP_ULT + Floating-point compare unordered less-than + +.. op:: OP_FCMP_UGT + Floating-point compare unordered greater-than + + +.. op:: OP_FCMP_ORD + Floating-point compare ordered: return true if both operands are ordered + (none of the operands are a NaN) and false otherwise. + +.. op:: OP_FCMP_UNO + Floating-point compare unordered: return false if no operands is ordered + and true otherwise. + +Unary ops +--------- +.. op:: OP_NOT + Logical not. + + * .src: operand (type must be compatible with .target) + * .target: result of the operation + * .type: type of .target, must be an integral type + +.. op:: OP_NEG + Integer negation. + + * .src: operand (type must be compatible with .target) + * .target: result of the operation (must be an integral type) + * .type: type of .target + +.. op:: OP_FNEG + Floating-point negation. + + * .src: operand (type must be compatible with .target) + * .target: result of the operation (must be a floating-point type) + * .type: type of .target + +.. op:: OP_COPY + Copy (only needed after out-of-SSA). + + * .src: operand (type must be compatible with .target) + * .target: result of the operation + * .type: type of .target + +Type conversions +---------------- +They all have the following signature: + * .src: source value + * .orig_type: type of .src + * .target: result value + * .type: type of .target + +.. op:: OP_CAST + Cast to unsigned integer (and to void pointer). + +.. op:: OP_SCAST + Cast to signed integer. + +.. op:: OP_FPCAST + Cast to floating-point. + +.. op:: OP_PTRCAST + Cast to pointer. + +Ternary ops +----------- +.. op:: OP_SEL + * .src1: condition, must be of integral type + * .src2, .src3: operands (types must be compatible with .target) + * .target: result of the operation + * .type: type of .target + +.. op:: OP_RANGE + Range/bounds checking (only used for an unused sparse extension). + + * .src1: value to be checked + * .src2, src3: bound of the value (must be constants?) + * .type: type of .src[123]? + +Memory ops +---------- +.. op:: OP_LOAD + Load. + + * .src: base address to load from + * .offset: address offset + * .target: loaded value + * .type: type of .target + +.. op:: OP_STORE + Store. + + * .src: base address to store to + * .offset: address offset + * .target: value to be stored + * .type: type of .target + +Others +------ +.. op:: OP_SYMADDR + Create a pseudo corresponding to the address of a symbol. + + * .symbol: (pseudo_t) input symbol (alias .src) + * .target: symbol's address + +.. op:: OP_SETFVAL + Create a pseudo corresponding to a floating-point literal. + + * .fvalue: the literal's value (long double) + * .target: the corresponding pseudo + * .type: type of the literal & .target + +.. op:: OP_SETVAL + Create a pseudo corresponding to a string literal or a label-as-value. + The value is given as an expression EXPR_STRING or EXPR_LABEL. + + * .val: (expression) input expression + * .target: the resulting value + * .type: type of .target, the value + +.. op:: OP_PHI + Phi-node (for SSA form). + + * .phi_list: phi-operands (type must be compatible with .target) + * .target: "result" + * .type: type of .target + +.. op:: OP_PHISOURCE + Phi-node source. + Like OP_COPY but exclusively used to give a defining instructions + (and thus also a type) to *all* OP_PHI operands. + + * .phi_src: operand (type must be compatible with .target, alias .src) + * .target: the "result" PSEUDO_PHI + * .type: type of .target + * .phi_users: list of phi instructions using the target pseudo + +.. op:: OP_CALL + Function call. + + * .func: (pseudo_t) the function (can be a symbol or a "register", + alias .src)) + * .arguments: (pseudo_list) list of the associated arguments + * .target: function return value (if any) + * .type: type of .target + * .fntypes: (symbol_list) list of the function's types: the first + entry is the full function type, the next ones are the type of + each arguments + +.. op:: OP_INLINED_CALL + Only used as an annotation to show that the instructions just above + correspond to a function that have been inlined. + + * .func: (pseudo_t) the function (must be a symbol, alias .src)) + * .arguments: list of pseudos that where the function's arguments + * .target: function return value (if any) + * .type: type of .target + +.. op:: OP_SLICE + Extract a "slice" from an aggregate. + + * .base: (pseudo_t) aggregate (alias .src) + * .from, .len: offet & size of the "slice" within the aggregate + * .target: result + * .type: type of .target + +.. op:: OP_ASM + Inlined assembly code. + + * .string: asm template + * .asm_rules: asm constraints, rules + +Sparse tagging (line numbers, context, whatever) +------------------------------------------------ +.. op:: OP_CONTEXT + Currently only used for lock/unlock tracking. + + * .context_expr: unused + * .increment: (1 for locking, -1 for unlocking) + * .check: (ignore the instruction if 0) + +Misc ops +-------- +.. op:: OP_ENTRY + Function entry point (no associated semantic). + +.. op:: OP_BADOP + Invalid operation (should never be generated). + +.. op:: OP_NOP + No-op (should never be generated). + +.. op:: OP_DEATHNOTE + Annotation telling the pseudo will be death after the next + instruction (other than some other annotation, that is). + +.. # vim: tabstop=4 diff --git a/Documentation/conf.py b/Documentation/conf.py index f7a68014..aae9d39b 100644 --- a/Documentation/conf.py +++ b/Documentation/conf.py @@ -29,6 +29,7 @@ needs_sphinx = '1.3' sys.path.insert(0, os.path.abspath('sphinx')) extensions = [ 'cdoc' + , 'ir' ] # support .md with python2 & python3 diff --git a/Documentation/doc-guide.rst b/Documentation/doc-guide.rst index 80ec82c2..8133cb3a 100644 --- a/Documentation/doc-guide.rst +++ b/Documentation/doc-guide.rst @@ -149,3 +149,7 @@ will be displayed like this: It's strongly encouraged to use this function instead of open coding a simple ``++``. + +Intermediate Representation +--------------------------- +.. c:autodoc:: Documentation/sphinx/ir.py diff --git a/Documentation/index.rst b/Documentation/index.rst index da006710..9825c8cd 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -20,8 +20,8 @@ Developer documentation test-suite dev-options - IR api + IR doc-guide How to contribute diff --git a/Documentation/sphinx/ir.py b/Documentation/sphinx/ir.py new file mode 100755 index 00000000..3028200a --- /dev/null +++ b/Documentation/sphinx/ir.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# SPDX_License-Identifier: MIT +# +# Copyright (C) 2018 Luc Van Oostenryck <luc.vanoostenryck@gmail.com> +# + +""" +/// +// To document the instructions used in the intermediate representation +// a new domain is defined: 'ir' with a directive:: +// +// .. op: <OP_NAME> +// <description of OP_NAME> +// ... +// +// This is equivalent to using a definition list but with the name +// also placed in the index (with 'IR instruction' as descriptions). + +""" + +import docutils +import sphinx + +class IROpDirective(docutils.parsers.rst.Directive): + + # use the first line of content as the argument, this allow + # to not have to write a blanck line after the directive + final_argument_whitespace = True + required_argument = 0 + #optional_arguments = 0 + has_content = True + + objtype = None + + def run(self): + self.env = self.state.document.settings.env + + source = self.state.document + lineno = self.lineno + text = self.content + name = text[0] + + node = docutils.nodes.section() + node['ids'].append(name) + node.document = source + + index = '.. index:: pair: %s; IR instruction' % name + content = docutils.statemachine.ViewList() + content.append(index, source, lineno) + content.append('' , source, lineno) + content.append(name , source, lineno) + content.append('' , source, lineno) + self.state.nested_parse(content, self.content_offset, node) + + defnode = docutils.nodes.definition() + self.state.nested_parse(text[1:], self.content_offset, defnode) + node.append(defnode) + + return [node] + +class IRDomain(sphinx.domains.Domain): + + """IR domain.""" + name = 'ir' + +def setup(app): + app.add_domain(IRDomain) + app.add_directive_to_domain('ir', 'op', IROpDirective) + + return { + 'version': '1.0', + 'parallel_read_safe': True, + } + +# vim: tabstop=4 @@ -82,7 +82,7 @@ error: return 0; } -static int arguments_choose(struct expression *expr) +static int args_triadic(struct expression *expr) { return eval_args(expr, 3); } @@ -195,8 +195,8 @@ static struct symbol_op expect_op = { }; static struct symbol_op choose_op = { + .args = args_triadic, .evaluate = evaluate_choose, - .args = arguments_choose, }; /* The argument is constant and valid if the cost is zero */ @@ -251,6 +251,71 @@ static struct symbol_op fp_unop_op = { }; +static int evaluate_overflow_gen(struct expression *expr, int ptr) +{ + struct expression *arg; + int n = 0; + + /* there will be exactly 3; we'd already verified that */ + FOR_EACH_PTR(expr->args, arg) { + struct symbol *type; + + n++; + if (!arg || !(type = arg->ctype)) + return 0; + // 1st & 2nd args must be a basic integer type + // 3rd arg must be a pointer to such a type. + if (n == 3 && ptr) { + if (type->type == SYM_NODE) + type = type->ctype.base_type; + if (!type) + return 0; + if (type->type != SYM_PTR) + goto err; + type = type->ctype.base_type; + if (!type) + return 0; + } + if (type->type == SYM_NODE) + type = type->ctype.base_type; + if (!type) + return 0; + if (type->ctype.base_type != &int_type || type == &bool_ctype) + goto err; + } END_FOR_EACH_PTR(arg); + + // the builtin returns a bool + expr->ctype = &bool_ctype; + return 1; + +err: + sparse_error(arg->pos, "invalid type for argument %d:", n); + info(arg->pos, " %s", show_typename(arg->ctype)); + expr->ctype = &bad_ctype; + return 0; +} + +static int evaluate_overflow(struct expression *expr) +{ + return evaluate_overflow_gen(expr, 1); +} + +static struct symbol_op overflow_op = { + .args = args_triadic, + .evaluate = evaluate_overflow, +}; + +static int evaluate_overflow_p(struct expression *expr) +{ + return evaluate_overflow_gen(expr, 0); +} + +static struct symbol_op overflow_p_op = { + .args = args_triadic, + .evaluate = evaluate_overflow_p, +}; + + /* * Builtin functions */ @@ -275,6 +340,12 @@ static struct sym_init { { "__builtin_isnan", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, { "__builtin_isnormal", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, { "__builtin_signbit", &builtin_fn_type, MOD_TOPLEVEL, &fp_unop_op }, + { "__builtin_add_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op }, + { "__builtin_sub_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op }, + { "__builtin_mul_overflow", &builtin_fn_type, MOD_TOPLEVEL, &overflow_op }, + { "__builtin_add_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op }, + { "__builtin_sub_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op }, + { "__builtin_mul_overflow_p", &builtin_fn_type, MOD_TOPLEVEL, &overflow_p_op }, { NULL, NULL, 0 } }; @@ -289,6 +360,7 @@ void init_builtins(int stream) sym->ctype.base_type = ptr->base_type; sym->ctype.modifiers = ptr->modifiers; sym->op = ptr->op; + sym->builtin = 1; } } @@ -302,6 +374,7 @@ static void declare_builtin(const char *name, struct symbol *rtype, int variadic sym->ctype.base_type = fun; sym->ctype.modifiers = MOD_TOPLEVEL; + sym->builtin = 1; fun->ctype.base_type = rtype; fun->variadic = variadic; @@ -397,9 +470,18 @@ void declare_builtins(void) declare_builtin("__builtin_realloc", &ptr_ctype, 0, &ptr_ctype, size_t_ctype, NULL); declare_builtin("__builtin_return_address", &ptr_ctype, 0, &uint_ctype, NULL); declare_builtin("__builtin_rindex", &string_ctype, 0, &const_string_ctype, &int_ctype, NULL); + declare_builtin("__builtin_sadd_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL); + declare_builtin("__builtin_saddl_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL); + declare_builtin("__builtin_saddll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL); declare_builtin("__builtin_signbit", &int_ctype, 1, NULL); + declare_builtin("__builtin_smul_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL); + declare_builtin("__builtin_smull_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL); + declare_builtin("__builtin_smulll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL); declare_builtin("__builtin_snprintf", &int_ctype, 1, &string_ctype, size_t_ctype, &const_string_ctype, NULL); declare_builtin("__builtin_sprintf", &int_ctype, 1, &string_ctype, &const_string_ctype, NULL); + declare_builtin("__builtin_ssub_overflow", &bool_ctype, 0, &int_ctype, &int_ctype, &int_ptr_ctype, NULL); + declare_builtin("__builtin_ssubl_overflow", &bool_ctype, 0, &long_ctype, &long_ctype, &long_ptr_ctype, NULL); + declare_builtin("__builtin_ssubll_overflow", &bool_ctype, 0, &llong_ctype, &llong_ctype, &llong_ptr_ctype, NULL); declare_builtin("__builtin_stpcpy", &string_ctype, 0, &const_string_ctype, &const_string_ctype, NULL); declare_builtin("__builtin_stpncpy", &string_ctype, 0, &const_string_ctype, &const_string_ctype, size_t_ctype, NULL); declare_builtin("__builtin_strcasecmp", &int_ctype, 0, &const_string_ctype, &const_string_ctype, NULL); @@ -422,7 +504,16 @@ void declare_builtins(void) declare_builtin("__builtin_strspn", size_t_ctype, 0, &const_string_ctype, &const_string_ctype, NULL); declare_builtin("__builtin_strstr", &string_ctype, 0, &const_string_ctype, &const_string_ctype, NULL); declare_builtin("__builtin_trap", &void_ctype, 0, NULL); + declare_builtin("__builtin_uadd_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL); + declare_builtin("__builtin_uaddl_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL); + declare_builtin("__builtin_uaddll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL); + declare_builtin("__builtin_umul_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL); + declare_builtin("__builtin_umull_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL); + declare_builtin("__builtin_umulll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL); declare_builtin("__builtin_unreachable", &void_ctype, 0, NULL); + declare_builtin("__builtin_usub_overflow", &bool_ctype, 0, &uint_ctype, &uint_ctype, &uint_ptr_ctype, NULL); + declare_builtin("__builtin_usubl_overflow", &bool_ctype, 0, &ulong_ctype, &ulong_ctype, &ulong_ptr_ctype, NULL); + declare_builtin("__builtin_usubll_overflow", &bool_ctype, 0, &ullong_ctype, &ullong_ctype, &ullong_ptr_ctype, NULL); declare_builtin("__builtin_va_arg_pack_len", size_t_ctype, 0, NULL); declare_builtin("__builtin_vprintf", &int_ctype, 0, &const_string_ctype, va_list_ctype, NULL); declare_builtin("__builtin_vsnprintf", &int_ctype, 0, &string_ctype, size_t_ctype, &const_string_ctype, va_list_ctype, NULL); diff --git a/ident-list.h b/ident-list.h index 5394f587..a37a4a1b 100644 --- a/ident-list.h +++ b/ident-list.h @@ -59,6 +59,7 @@ IDENT_RESERVED(__label__); * sparse. */ IDENT(defined); IDENT(once); +IDENT(__has_builtin); __IDENT(pragma_ident, "__pragma__", 0); __IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0); __IDENT(__func___ident, "__func__", 0); @@ -1241,6 +1241,7 @@ static void create_builtin_stream(void) add_pre_buffer("#add_system \"%s/include\"\n", gcc_base_dir); add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir); + add_pre_buffer("#define __has_builtin(x) 0\n"); add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n"); add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n"); add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n"); diff --git a/pre-process.c b/pre-process.c index e1550cdb..da4b7acd 100644 --- a/pre-process.c +++ b/pre-process.c @@ -146,13 +146,23 @@ static int token_defined(struct token *token) return 0; } -static void replace_with_defined(struct token *token) +static void replace_with_bool(struct token *token, bool val) { static const char *string[] = { "0", "1" }; - int defined = token_defined(token); token_type(token) = TOKEN_NUMBER; - token->number = string[defined]; + token->number = string[val]; +} + +static void replace_with_defined(struct token *token) +{ + replace_with_bool(token, token_defined(token)); +} + +static void replace_with_has_builtin(struct token *token) +{ + struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL); + replace_with_bool(token, sym && sym->builtin); } static void expand_line(struct token *token) @@ -1578,6 +1588,10 @@ static int expression_value(struct token **where) state = 1; beginning = list; break; + } else if (p->ident == &__has_builtin_ident) { + state = 4; + beginning = list; + break; } if (!expand_one_symbol(list)) continue; @@ -1608,6 +1622,33 @@ static int expression_value(struct token **where) sparse_error(p->pos, "missing ')' after \"defined\""); *list = p->next; continue; + + // __has_builtin(xyz) + case 4: + if (match_op(p, '(')) { + state = 5; + } else { + sparse_error(p->pos, "missing '(' after \"__has_builtin\""); + state = 0; + } + *beginning = p; + break; + case 5: + if (token_type(p) != TOKEN_IDENT) { + sparse_error(p->pos, "identifier expected"); + state = 0; + break; + } + if (!match_op(p->next, ')')) + sparse_error(p->pos, "missing ')' after \"__has_builtin\""); + state = 6; + replace_with_has_builtin(p); + *beginning = p; + break; + case 6: + state = 0; + *list = p->next; + continue; } list = &p->next; } @@ -697,6 +697,9 @@ struct symbol bool_ctype, void_ctype, type_ctype, string_ctype, ptr_ctype, lazy_ptr_ctype, incomplete_ctype, label_ctype, bad_ctype, null_ctype; +struct symbol int_ptr_ctype, uint_ptr_ctype; +struct symbol long_ptr_ctype, ulong_ptr_ctype; +struct symbol llong_ptr_ctype, ullong_ptr_ctype; struct symbol float32_ctype, float32x_ctype; struct symbol float64_ctype, float64x_ctype; struct symbol float128_ctype; @@ -779,6 +782,12 @@ static const struct ctype_declare { { &null_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype }, { &label_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype }, { &lazy_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &void_ctype }, + { &int_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &int_ctype }, + { &uint_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &uint_ctype }, + { &long_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &long_ctype }, + { &ulong_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &ulong_ctype }, + { &llong_ptr_ctype, SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &llong_ctype }, + { &ullong_ptr_ctype,SYM_PTR, 0, &bits_in_pointer, &pointer_alignment, &ullong_ctype }, { &const_void_ctype, SYM_NODE, MOD_CONST, NULL, NULL, &void_ctype }, { &const_char_ctype, SYM_NODE, MOD_CONST, &bits_in_char, &max_int_alignment, &char_ctype }, @@ -174,6 +174,7 @@ struct symbol { designated_init:1, forced_arg:1, accessed:1, + builtin:1, transparent_union:1; struct expression *array_size; struct ctype ctype; @@ -268,6 +269,9 @@ extern struct symbol bool_ctype, void_ctype, type_ctype, string_ctype, ptr_ctype, lazy_ptr_ctype, incomplete_ctype, label_ctype, bad_ctype, null_ctype; +extern struct symbol int_ptr_ctype, uint_ptr_ctype; +extern struct symbol long_ptr_ctype, ulong_ptr_ctype; +extern struct symbol llong_ptr_ctype, ullong_ptr_ctype; extern struct symbol float32_ctype, float32x_ctype; extern struct symbol float64_ctype, float64x_ctype; extern struct symbol float128_ctype; diff --git a/validation/builtin-overflow.c b/validation/builtin-overflow.c new file mode 100644 index 00000000..867eb42f --- /dev/null +++ b/validation/builtin-overflow.c @@ -0,0 +1,246 @@ +enum e { OK }; +typedef _Bool bool; + +static int test(int i, long l, long long ll, enum e e, bool b, void *p) +{ + int rc = 0; + + // should be OK + rc += __builtin_add_overflow(i, i, &i); + rc += __builtin_add_overflow(l, i, &i); + rc += __builtin_add_overflow(i, l, &i); + rc += __builtin_add_overflow(i, i, &l); + rc += __builtin_add_overflow(ll, i, &i); + rc += __builtin_add_overflow(i, ll, &i); + rc += __builtin_add_overflow(i, i, &ll); + + rc += __builtin_add_overflow_p(i, i, i); + rc += __builtin_add_overflow_p(l, i, i); + rc += __builtin_add_overflow_p(i, l, i); + rc += __builtin_add_overflow_p(i, i, l); + rc += __builtin_add_overflow_p(ll, i, i); + rc += __builtin_add_overflow_p(i, ll, i); + rc += __builtin_add_overflow_p(i, i, ll); + + rc += __builtin_sub_overflow(i, i, &i); + rc += __builtin_sub_overflow(l, i, &i); + rc += __builtin_sub_overflow(i, l, &i); + rc += __builtin_sub_overflow(i, i, &l); + rc += __builtin_sub_overflow(ll, i, &i); + rc += __builtin_sub_overflow(i, ll, &i); + rc += __builtin_sub_overflow(i, i, &ll); + + rc += __builtin_sub_overflow_p(i, i, i); + rc += __builtin_sub_overflow_p(l, i, i); + rc += __builtin_sub_overflow_p(i, l, i); + rc += __builtin_sub_overflow_p(i, i, l); + rc += __builtin_sub_overflow_p(ll, i, i); + rc += __builtin_sub_overflow_p(i, ll, i); + rc += __builtin_sub_overflow_p(i, i, ll); + + rc += __builtin_mul_overflow(i, i, &i); + rc += __builtin_mul_overflow(l, i, &i); + rc += __builtin_mul_overflow(i, l, &i); + rc += __builtin_mul_overflow(i, i, &l); + rc += __builtin_mul_overflow(ll, i, &i); + rc += __builtin_mul_overflow(i, ll, &i); + rc += __builtin_mul_overflow(i, i, &ll); + + rc += __builtin_mul_overflow_p(i, i, i); + rc += __builtin_mul_overflow_p(l, i, i); + rc += __builtin_mul_overflow_p(i, l, i); + rc += __builtin_mul_overflow_p(i, i, l); + rc += __builtin_mul_overflow_p(ll, i, i); + rc += __builtin_mul_overflow_p(i, ll, i); + rc += __builtin_mul_overflow_p(i, i, ll); + + // should be KO + rc += __builtin_add_overflow(); + rc += __builtin_add_overflow(i); + rc += __builtin_add_overflow(i, i); + rc += __builtin_add_overflow(i, i, &i, i); + rc += __builtin_add_overflow(e, i, &i); + rc += __builtin_add_overflow(i, e, &i); + rc += __builtin_add_overflow(i, i, &e); + rc += __builtin_add_overflow(b, i, &i); + rc += __builtin_add_overflow(i, b, &i); + rc += __builtin_add_overflow(i, i, &b); + rc += __builtin_add_overflow(i, i, p); + + rc += __builtin_add_overflow_p(); + rc += __builtin_add_overflow_p(i); + rc += __builtin_add_overflow_p(i, i); + rc += __builtin_add_overflow_p(i, i, i, i); + rc += __builtin_add_overflow_p(e, i, i); + rc += __builtin_add_overflow_p(i, e, i); + rc += __builtin_add_overflow_p(i, i, e); + rc += __builtin_add_overflow_p(b, i, i); + rc += __builtin_add_overflow_p(i, b, i); + rc += __builtin_add_overflow_p(i, i, b); + rc += __builtin_add_overflow_p(i, i, p); + + rc += __builtin_sub_overflow(); + rc += __builtin_sub_overflow(i); + rc += __builtin_sub_overflow(i, i); + rc += __builtin_sub_overflow(i, i, &i, i); + rc += __builtin_sub_overflow(e, i, &i); + rc += __builtin_sub_overflow(i, e, &i); + rc += __builtin_sub_overflow(i, i, &e); + rc += __builtin_sub_overflow(b, i, &i); + rc += __builtin_sub_overflow(i, b, &i); + rc += __builtin_sub_overflow(i, i, &b); + rc += __builtin_sub_overflow(i, i, p); + + rc += __builtin_sub_overflow_p(); + rc += __builtin_sub_overflow_p(i); + rc += __builtin_sub_overflow_p(i, i); + rc += __builtin_sub_overflow_p(i, i, i, i); + rc += __builtin_sub_overflow_p(e, i, i); + rc += __builtin_sub_overflow_p(i, e, i); + rc += __builtin_sub_overflow_p(i, i, e); + rc += __builtin_sub_overflow_p(b, i, i); + rc += __builtin_sub_overflow_p(i, b, i); + rc += __builtin_sub_overflow_p(i, i, b); + rc += __builtin_sub_overflow_p(i, i, p); + + rc += __builtin_mul_overflow(); + rc += __builtin_mul_overflow(i); + rc += __builtin_mul_overflow(i, i); + rc += __builtin_mul_overflow(i, i, &i, i); + rc += __builtin_mul_overflow(e, i, &i); + rc += __builtin_mul_overflow(i, e, &i); + rc += __builtin_mul_overflow(i, i, &e); + rc += __builtin_mul_overflow(b, i, &i); + rc += __builtin_mul_overflow(i, b, &i); + rc += __builtin_mul_overflow(i, i, &b); + rc += __builtin_mul_overflow(i, i, p); + + rc += __builtin_mul_overflow_p(); + rc += __builtin_mul_overflow_p(i); + rc += __builtin_mul_overflow_p(i, i); + rc += __builtin_mul_overflow_p(i, i, i, i); + rc += __builtin_mul_overflow_p(e, i, i); + rc += __builtin_mul_overflow_p(i, e, i); + rc += __builtin_mul_overflow_p(i, i, e); + rc += __builtin_mul_overflow_p(b, i, i); + rc += __builtin_mul_overflow_p(i, b, i); + rc += __builtin_mul_overflow_p(i, i, b); + rc += __builtin_mul_overflow_p(i, i, p); + + return rc; +} + +/* + * check-name: builtin-overflow + * + * check-error-start +builtin-overflow.c:58:37: error: not enough arguments for __builtin_add_overflow +builtin-overflow.c:59:37: error: not enough arguments for __builtin_add_overflow +builtin-overflow.c:60:37: error: not enough arguments for __builtin_add_overflow +builtin-overflow.c:61:37: error: too many arguments for __builtin_add_overflow +builtin-overflow.c:62:38: error: invalid type for argument 1: +builtin-overflow.c:62:38: int enum e [signed] e +builtin-overflow.c:63:41: error: invalid type for argument 2: +builtin-overflow.c:63:41: int enum e [signed] e +builtin-overflow.c:64:45: error: invalid type for argument 3: +builtin-overflow.c:64:45: int enum e *<noident> +builtin-overflow.c:65:38: error: invalid type for argument 1: +builtin-overflow.c:65:38: bool [unsigned] [usertype] b +builtin-overflow.c:66:41: error: invalid type for argument 2: +builtin-overflow.c:66:41: bool [unsigned] [usertype] b +builtin-overflow.c:67:45: error: invalid type for argument 3: +builtin-overflow.c:67:45: bool *<noident> +builtin-overflow.c:68:44: error: invalid type for argument 3: +builtin-overflow.c:68:44: void *p +builtin-overflow.c:70:39: error: not enough arguments for __builtin_add_overflow_p +builtin-overflow.c:71:39: error: not enough arguments for __builtin_add_overflow_p +builtin-overflow.c:72:39: error: not enough arguments for __builtin_add_overflow_p +builtin-overflow.c:73:39: error: too many arguments for __builtin_add_overflow_p +builtin-overflow.c:74:40: error: invalid type for argument 1: +builtin-overflow.c:74:40: int enum e [signed] [addressable] e +builtin-overflow.c:75:43: error: invalid type for argument 2: +builtin-overflow.c:75:43: int enum e [signed] [addressable] e +builtin-overflow.c:76:46: error: invalid type for argument 3: +builtin-overflow.c:76:46: int enum e [signed] [addressable] e +builtin-overflow.c:77:40: error: invalid type for argument 1: +builtin-overflow.c:77:40: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:78:43: error: invalid type for argument 2: +builtin-overflow.c:78:43: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:79:46: error: invalid type for argument 3: +builtin-overflow.c:79:46: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:80:46: error: invalid type for argument 3: +builtin-overflow.c:80:46: void *p +builtin-overflow.c:82:37: error: not enough arguments for __builtin_sub_overflow +builtin-overflow.c:83:37: error: not enough arguments for __builtin_sub_overflow +builtin-overflow.c:84:37: error: not enough arguments for __builtin_sub_overflow +builtin-overflow.c:85:37: error: too many arguments for __builtin_sub_overflow +builtin-overflow.c:86:38: error: invalid type for argument 1: +builtin-overflow.c:86:38: int enum e [signed] [addressable] e +builtin-overflow.c:87:41: error: invalid type for argument 2: +builtin-overflow.c:87:41: int enum e [signed] [addressable] e +builtin-overflow.c:88:45: error: invalid type for argument 3: +builtin-overflow.c:88:45: int enum e *<noident> +builtin-overflow.c:89:38: error: invalid type for argument 1: +builtin-overflow.c:89:38: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:90:41: error: invalid type for argument 2: +builtin-overflow.c:90:41: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:91:45: error: invalid type for argument 3: +builtin-overflow.c:91:45: bool *<noident> +builtin-overflow.c:92:44: error: invalid type for argument 3: +builtin-overflow.c:92:44: void *p +builtin-overflow.c:94:39: error: not enough arguments for __builtin_sub_overflow_p +builtin-overflow.c:95:39: error: not enough arguments for __builtin_sub_overflow_p +builtin-overflow.c:96:39: error: not enough arguments for __builtin_sub_overflow_p +builtin-overflow.c:97:39: error: too many arguments for __builtin_sub_overflow_p +builtin-overflow.c:98:40: error: invalid type for argument 1: +builtin-overflow.c:98:40: int enum e [signed] [addressable] e +builtin-overflow.c:99:43: error: invalid type for argument 2: +builtin-overflow.c:99:43: int enum e [signed] [addressable] e +builtin-overflow.c:100:46: error: invalid type for argument 3: +builtin-overflow.c:100:46: int enum e [signed] [addressable] e +builtin-overflow.c:101:40: error: invalid type for argument 1: +builtin-overflow.c:101:40: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:102:43: error: invalid type for argument 2: +builtin-overflow.c:102:43: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:103:46: error: invalid type for argument 3: +builtin-overflow.c:103:46: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:104:46: error: invalid type for argument 3: +builtin-overflow.c:104:46: void *p +builtin-overflow.c:106:37: error: not enough arguments for __builtin_mul_overflow +builtin-overflow.c:107:37: error: not enough arguments for __builtin_mul_overflow +builtin-overflow.c:108:37: error: not enough arguments for __builtin_mul_overflow +builtin-overflow.c:109:37: error: too many arguments for __builtin_mul_overflow +builtin-overflow.c:110:38: error: invalid type for argument 1: +builtin-overflow.c:110:38: int enum e [signed] [addressable] e +builtin-overflow.c:111:41: error: invalid type for argument 2: +builtin-overflow.c:111:41: int enum e [signed] [addressable] e +builtin-overflow.c:112:45: error: invalid type for argument 3: +builtin-overflow.c:112:45: int enum e *<noident> +builtin-overflow.c:113:38: error: invalid type for argument 1: +builtin-overflow.c:113:38: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:114:41: error: invalid type for argument 2: +builtin-overflow.c:114:41: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:115:45: error: invalid type for argument 3: +builtin-overflow.c:115:45: bool *<noident> +builtin-overflow.c:116:44: error: invalid type for argument 3: +builtin-overflow.c:116:44: void *p +builtin-overflow.c:118:39: error: not enough arguments for __builtin_mul_overflow_p +builtin-overflow.c:119:39: error: not enough arguments for __builtin_mul_overflow_p +builtin-overflow.c:120:39: error: not enough arguments for __builtin_mul_overflow_p +builtin-overflow.c:121:39: error: too many arguments for __builtin_mul_overflow_p +builtin-overflow.c:122:40: error: invalid type for argument 1: +builtin-overflow.c:122:40: int enum e [signed] [addressable] e +builtin-overflow.c:123:43: error: invalid type for argument 2: +builtin-overflow.c:123:43: int enum e [signed] [addressable] e +builtin-overflow.c:124:46: error: invalid type for argument 3: +builtin-overflow.c:124:46: int enum e [signed] [addressable] e +builtin-overflow.c:125:40: error: invalid type for argument 1: +builtin-overflow.c:125:40: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:126:43: error: invalid type for argument 2: +builtin-overflow.c:126:43: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:127:46: error: invalid type for argument 3: +builtin-overflow.c:127:46: bool [unsigned] [addressable] [usertype] b +builtin-overflow.c:128:46: error: invalid type for argument 3: +builtin-overflow.c:128:46: void *p + * check-error-end + */ diff --git a/validation/preprocessor/has-builtin.c b/validation/preprocessor/has-builtin.c new file mode 100644 index 00000000..03272fc9 --- /dev/null +++ b/validation/preprocessor/has-builtin.c @@ -0,0 +1,43 @@ +#ifndef __has_builtin +__has_builtin()??? Quesako? +#define __has_builtin(x) 0 +#else +"has __has_builtin(), yeah!" +#endif + +#if __has_builtin(nothing) +#error "not a builtin!" +#endif + +#if __has_builtin(__builtin_offsetof) \ + || __has_builtin(__builtin_types_compatible_p) +#error "builtin ops are not builtin functions!" +#endif + +#if __has_builtin(__builtin_va_list) \ + || __has_builtin(__builtin_ms_va_list) +#error "builtin types are not builtin functions!" +#endif + +#if __has_builtin(__builtin_abs) +abs +#endif + +#if __has_builtin(__builtin_constant_p) +constant_p +#endif + +123 __has_builtin(abc) def + +/* + * check-name: has-builtin + * check-command: sparse -E $file + * + * check-output-start + +"has __has_builtin(), yeah!" +abs +constant_p +123 0 def + * check-output-end + */ |
