aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
-rw-r--r--.gitignore3
-rw-r--r--Documentation/test-suite33
-rw-r--r--Makefile330
-rw-r--r--allocate.c2
-rw-r--r--allocate.h3
-rw-r--r--builtin.c26
-rwxr-xr-xcgcc25
-rw-r--r--compile-i386.c12
-rw-r--r--evaluate.c290
-rw-r--r--expand.c9
-rw-r--r--expression.c48
-rw-r--r--expression.h77
-rw-r--r--flow.c7
-rw-r--r--gcc-attr-list.h2
-rw-r--r--gdbhelpers12
-rw-r--r--graph.c2
-rw-r--r--ident-list.h2
-rw-r--r--inline.c19
-rw-r--r--lib.c17
-rw-r--r--lib.h1
-rw-r--r--linearize.c42
-rw-r--r--linearize.h2
-rw-r--r--memops.c6
-rw-r--r--parse.c45
-rw-r--r--pre-process.c4
-rw-r--r--ptrlist.h2
-rw-r--r--scope.h1
-rw-r--r--show-parse.c9
-rw-r--r--simplify.c4
-rw-r--r--sparse.113
-rw-r--r--sparse.pc.in9
-rw-r--r--symbol.c4
-rw-r--r--symbol.h88
-rw-r--r--tokenize.c26
-rw-r--r--validation/bad-return-type.c19
-rw-r--r--validation/bitfield-size.c6
-rw-r--r--validation/c11-atomic.c93
-rw-r--r--validation/cast-kinds.c12
-rw-r--r--validation/constexpr-addr-of-static-member.c26
-rw-r--r--validation/constexpr-addr-of-static.c36
-rw-r--r--validation/constexpr-binop.c33
-rw-r--r--validation/constexpr-cast.c25
-rw-r--r--validation/constexpr-compound-literal.c19
-rw-r--r--validation/constexpr-conditional.c34
-rw-r--r--validation/constexpr-init.c60
-rw-r--r--validation/constexpr-labelref.c14
-rw-r--r--validation/constexpr-offsetof.c21
-rw-r--r--validation/constexpr-pointer-arith.c28
-rw-r--r--validation/constexpr-pointer-cast.c13
-rw-r--r--validation/constexpr-preop.c29
-rw-r--r--validation/constexpr-pure-builtin.c23
-rw-r--r--validation/constexpr-string.c9
-rw-r--r--validation/constexpr-types-compatible-p.c8
-rw-r--r--validation/fp2i-cast.c30
-rw-r--r--validation/include-eval.c6
-rw-r--r--validation/include-eval.inc12
-rw-r--r--validation/incomplete-struct.c23
-rw-r--r--validation/kill-load.c2
-rw-r--r--validation/kill-phi-ttsbb.c2
-rw-r--r--validation/kill-store.c2
-rw-r--r--validation/memops-volatile.c15
-rw-r--r--validation/optim/bool-context.c2
-rw-r--r--validation/optim/muldiv-minus-one.c2
-rw-r--r--validation/optim/restrict.c73
-rw-r--r--validation/optim/volatile-side-effect.c13
-rw-r--r--validation/preprocessor/dump-macros-empty.c2
-rw-r--r--validation/preprocessor/dump-macros-multi.c2
-rw-r--r--validation/preprocessor/dump-macros.c2
-rw-r--r--validation/preprocessor/preprocessor23.c4
-rw-r--r--validation/reload-aliasing.c41
-rw-r--r--validation/restrict.c93
-rw-r--r--validation/test-be.c46
-rwxr-xr-xvalidation/test-suite291
-rw-r--r--validation/testsuite-selfcheck1.c10
-rw-r--r--validation/testsuite-selfcheck2.c10
-rw-r--r--validation/testsuite-selfcheck3.c10
-rw-r--r--validation/typeof-mods.c28
77 files changed, 1748 insertions, 656 deletions
diff --git a/.gitignore b/.gitignore
index 44218a2f..bc00736d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,8 +6,6 @@
.*.swp
# generated
-pre-process.h
-sparse.pc
version.h
# programs
@@ -39,6 +37,7 @@ series
# local makefile
local.mk
+.*.mk
# cscope and Qt files
cscope.out
diff --git a/Documentation/test-suite b/Documentation/test-suite
index a288c81a..160fed31 100644
--- a/Documentation/test-suite
+++ b/Documentation/test-suite
@@ -7,13 +7,13 @@ Sparse has a number of test cases in its validation directory. The test-suite
script aims at making automated checking of these tests possible. It works by
embedding tags in C comments in the test cases.
-check-name: (mandatory)
- Name of the test.
+check-name: <name>
+ Name of the test. This is the only mandatory tag.
-check-description: (optional)
+check-description: <description ...>
A description of what the test checks.
-check-command: (optional)
+check-command: <command arg ...>
There are different kinds of tests. Some can validate the sparse
preprocessor, while others will use sparse, cgcc, or even other backends
of the library. check-command allows you to give a custom command to
@@ -22,40 +22,47 @@ check-command: (optional)
run time.
It defaults to "sparse $file".
-check-exit-value: (optional)
+check-arch-ignore: <arch[|...]>
+check-arch-only: <arch[|...]>
+ Ignore the test if the current architecture (as returned by 'uname -m')
+ match or not one of the archs given in the pattern.
+
+check-exit-value: <value>
The expected exit value of check-command. It defaults to 0.
-check-timeout: (optional)
+check-timeout: <timeout>
The maximum expected duration of check-command, in seconds.
It defaults to 1.
-check-output-start / check-output-end (optional)
+check-output-start / check-output-end
The expected output (stdout and stderr) of check-command lies between
those two tags. It defaults to no output.
-check-output-ignore / check-error-ignore (optional)
+check-output-ignore / check-error-ignore
Don't check the expected output (stdout or stderr) of check-command
(usefull when this output is not comparable or if you're only interested
in the exit value).
By default this check is done.
-check-known-to-fail (optional)
+check-known-to-fail
Mark the test as being known to fail.
-check-output-contains: <pattern> (optional)
+check-output-contains: <pattern>
Check that the output (stdout) contains the given pattern.
Several such tags can be given, in which case the output
must contains all the patterns.
-check-output-excludes: <pattern> (optional)
+check-output-excludes: <pattern>
Similar than the above one, but with opposite logic.
Check that the output (stdout) doesn't contain the given pattern.
Several such tags can be given, in which case the output
must contains none of the patterns.
-check-output-pattern-<nbr>-times: <pattern> (optional)
- Similar than the contains/excludes her above, but with full control
+check-output-pattern(<nbr>): <pattern>
+check-output-pattern(<min>,<max>): <pattern>
+ Similar to the '-contains/excludes' here above, but with full control
of the number of times the pattern should occurs in the output.
+ If <min> or <max> is '-' the corresponding check is ignored.
Using test-suite
~~~~~~~~~~~~~~~~
diff --git a/Makefile b/Makefile
index 48e1f508..240929e5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,95 +1,147 @@
-VERSION=0.5.1-rc5
-
-# Generating file version.h if current version has changed
-SPARSE_VERSION:=$(shell git describe 2>/dev/null || echo '$(VERSION)')
-VERSION_H := $(shell cat version.h 2>/dev/null)
-ifneq ($(lastword $(VERSION_H)),"$(SPARSE_VERSION)")
-$(info $(shell echo ' GEN 'version.h))
-$(shell echo '#define SPARSE_VERSION "$(SPARSE_VERSION)"' > version.h)
-endif
+VERSION=0.5.1
+########################################################################
+# The following variables can be overwritten from the command line
OS = linux
CC = gcc
-CFLAGS = -O2 -finline-functions -fno-strict-aliasing -g
+CFLAGS = -O2 -finline-functions -g
CFLAGS += -Wall -Wwrite-strings
-LDFLAGS += -g
LD = gcc
AR = ar
PKG_CONFIG = pkg-config
-CHECKER = ./cgcc -no-compile
-CHECKER_FLAGS =
+CHECKER = CHECK=./sparse ./cgcc -no-compile
+CHECKER_FLAGS = -Wno-vla
-ALL_CFLAGS = $(CFLAGS) $(BASIC_CFLAGS)
-#
+DESTDIR=
+PREFIX ?= $(HOME)
+BINDIR=$(PREFIX)/bin
+MANDIR=$(PREFIX)/share/man
+MAN1DIR=$(MANDIR)/man1
+
+# Allow users to override build settings without dirtying their trees
# For debugging, put this in local.mk:
#
# CFLAGS += -O0 -DDEBUG -g3 -gdwarf-2
#
+SPARSE_LOCAL_CONFIG ?= local.mk
+-include ${SPARSE_LOCAL_CONFIG}
+########################################################################
+
+
+LIB_OBJS :=
+LIB_OBJS += allocate.o
+LIB_OBJS += builtin.o
+LIB_OBJS += char.o
+LIB_OBJS += compat-$(OS).o
+LIB_OBJS += cse.o
+LIB_OBJS += dissect.o
+LIB_OBJS += evaluate.o
+LIB_OBJS += expand.o
+LIB_OBJS += expression.o
+LIB_OBJS += flow.o
+LIB_OBJS += inline.o
+LIB_OBJS += lib.o
+LIB_OBJS += linearize.o
+LIB_OBJS += liveness.o
+LIB_OBJS += memops.o
+LIB_OBJS += parse.o
+LIB_OBJS += pre-process.o
+LIB_OBJS += ptrlist.o
+LIB_OBJS += scope.o
+LIB_OBJS += show-parse.o
+LIB_OBJS += simplify.o
+LIB_OBJS += sort.o
+LIB_OBJS += stats.o
+LIB_OBJS += storage.o
+LIB_OBJS += symbol.o
+LIB_OBJS += target.o
+LIB_OBJS += tokenize.o
+LIB_OBJS += unssa.o
+
+PROGRAMS :=
+PROGRAMS += compile
+PROGRAMS += ctags
+PROGRAMS += example
+PROGRAMS += graph
+PROGRAMS += obfuscate
+PROGRAMS += sparse
+PROGRAMS += test-dissect
+PROGRAMS += test-lexing
+PROGRAMS += test-linearize
+PROGRAMS += test-parsing
+PROGRAMS += test-unssa
-HAVE_LIBXML:=$(shell $(PKG_CONFIG) --exists libxml-2.0 2>/dev/null && echo 'yes')
-HAVE_GCC_DEP:=$(shell touch .gcc-test.c && \
- $(CC) -c -Wp,-MD,.gcc-test.d .gcc-test.c 2>/dev/null && \
- echo 'yes'; rm -f .gcc-test.d .gcc-test.o .gcc-test.c)
+INST_PROGRAMS=sparse cgcc
+INST_MAN1=sparse.1 cgcc.1
-GTK_VERSION:=3.0
-HAVE_GTK:=$(shell $(PKG_CONFIG) --exists gtk+-$(GTK_VERSION) 2>/dev/null && echo 'yes')
-ifneq ($(HAVE_GTK),yes)
- GTK_VERSION:=2.0
- HAVE_GTK:=$(shell $(PKG_CONFIG) --exists gtk+-$(GTK_VERSION) 2>/dev/null && echo 'yes')
-endif
-LLVM_CONFIG:=llvm-config
-HAVE_LLVM:=$(shell $(LLVM_CONFIG) --version >/dev/null 2>&1 && echo 'yes')
+all:
+
+########################################################################
+# common flags/options/...
+
+cflags = -fno-strict-aliasing
GCC_BASE := $(shell $(CC) --print-file-name=)
-BASIC_CFLAGS = -DGCC_BASE=\"$(GCC_BASE)\"
+cflags += -DGCC_BASE=\"$(GCC_BASE)\"
MULTIARCH_TRIPLET := $(shell $(CC) -print-multiarch 2>/dev/null)
-BASIC_CFLAGS += -DMULTIARCH_TRIPLET=\"$(MULTIARCH_TRIPLET)\"
+cflags += -DMULTIARCH_TRIPLET=\"$(MULTIARCH_TRIPLET)\"
-ifeq ($(HAVE_GCC_DEP),yes)
-BASIC_CFLAGS += -Wp,-MD,$(@D)/.$(@F).d
-endif
+########################################################################
+# target specificities
-DESTDIR=
-PREFIX=$(HOME)
-BINDIR=$(PREFIX)/bin
-LIBDIR=$(PREFIX)/lib
-MANDIR=$(PREFIX)/share/man
-MAN1DIR=$(MANDIR)/man1
-INCLUDEDIR=$(PREFIX)/include
-PKGCONFIGDIR=$(LIBDIR)/pkgconfig
+compile: compile-i386.o
+EXTRA_OBJS += compile-i386.o
-PROGRAMS=test-lexing test-parsing obfuscate compile graph sparse \
- test-linearize example test-unssa test-dissect ctags
-INST_PROGRAMS=sparse cgcc
-INST_MAN1=sparse.1 cgcc.1
+# Can we use GCC's generated dependencies?
+HAVE_GCC_DEP:=$(shell touch .gcc-test.c && \
+ $(CC) -c -Wp,-MD,.gcc-test.d .gcc-test.c 2>/dev/null && \
+ echo 'yes'; rm -f .gcc-test.d .gcc-test.o .gcc-test.c)
+ifeq ($(HAVE_GCC_DEP),yes)
+cflags += -Wp,-MD,$(@D)/.$(@F).d
+endif
+# Can we use libxml (needed for c2xml)?
+HAVE_LIBXML:=$(shell $(PKG_CONFIG) --exists libxml-2.0 2>/dev/null && echo 'yes')
ifeq ($(HAVE_LIBXML),yes)
PROGRAMS+=c2xml
INST_PROGRAMS+=c2xml
-c2xml_EXTRA_OBJS = `$(PKG_CONFIG) --libs libxml-2.0`
-LIBXML_CFLAGS := $(shell $(PKG_CONFIG) --cflags libxml-2.0)
+c2xml-ldlibs := $(shell $(PKG_CONFIG) --libs libxml-2.0)
+c2xml-cflags := $(shell $(PKG_CONFIG) --cflags libxml-2.0)
else
$(warning Your system does not have libxml, disabling c2xml)
endif
+# Can we use gtk (needed for test-inspect)
+GTK_VERSION:=3.0
+HAVE_GTK:=$(shell $(PKG_CONFIG) --exists gtk+-$(GTK_VERSION) 2>/dev/null && echo 'yes')
+ifneq ($(HAVE_GTK),yes)
+GTK_VERSION:=2.0
+HAVE_GTK:=$(shell $(PKG_CONFIG) --exists gtk+-$(GTK_VERSION) 2>/dev/null && echo 'yes')
+endif
ifeq ($(HAVE_GTK),yes)
GTK_CFLAGS := $(shell $(PKG_CONFIG) --cflags gtk+-$(GTK_VERSION))
-GTK_LIBS := $(shell $(PKG_CONFIG) --libs gtk+-$(GTK_VERSION))
+ast-view-cflags := $(GTK_CFLAGS)
+ast-model-cflags := $(GTK_CFLAGS)
+ast-inspect-cflags := $(GTK_CFLAGS)
+test-inspect-cflags := $(GTK_CFLAGS)
+test-inspect-ldlibs := $(shell $(PKG_CONFIG) --libs gtk+-$(GTK_VERSION))
+test-inspect: ast-model.o ast-view.o ast-inspect.o
+EXTRA_OBJS += ast-model.o ast-view.o ast-inspect.o
PROGRAMS += test-inspect
INST_PROGRAMS += test-inspect
-test-inspect_EXTRA_DEPS := ast-model.o ast-view.o ast-inspect.o
-test-inspect_OBJS := test-inspect.o $(test-inspect_EXTRA_DEPS)
-$(test-inspect_OBJS) $(test-inspect_OBJS:.o=.sc): CFLAGS += $(GTK_CFLAGS)
-test-inspect_EXTRA_OBJS := $(GTK_LIBS)
else
$(warning Your system does not have gtk3/gtk2, disabling test-inspect)
endif
+# Can we use LLVM (needed for ... sparse-llvm)?
+LLVM_CONFIG:=llvm-config
+HAVE_LLVM:=$(shell $(LLVM_CONFIG) --version >/dev/null 2>&1 && echo 'yes')
ifeq ($(HAVE_LLVM),yes)
+ifeq ($(shell uname -m | grep -q '\(i386\|x86\)' && echo ok),ok)
LLVM_VERSION:=$(shell $(LLVM_CONFIG) --version)
ifeq ($(shell expr "$(LLVM_VERSION)" : '[3-9]\.'),2)
LLVM_PROGS := sparse-llvm
@@ -100,142 +152,96 @@ LLVM_LIBS := $(shell $(LLVM_CONFIG) --libs)
LLVM_LIBS += $(shell $(LLVM_CONFIG) --system-libs 2>/dev/null)
PROGRAMS += $(LLVM_PROGS)
INST_PROGRAMS += sparse-llvm sparsec
-sparse-llvm.o: BASIC_CFLAGS += $(LLVM_CFLAGS)
-sparse-llvm_EXTRA_OBJS := $(LLVM_LIBS) $(LLVM_LDFLAGS)
+sparse-llvm-cflags := $(LLVM_CFLAGS)
+sparse-llvm-ldflags := $(LLVM_LDFLAGS)
+sparse-llvm-ldlibs := $(LLVM_LIBS)
else
$(warning LLVM 3.0 or later required. Your system has version $(LLVM_VERSION) installed.)
endif
else
+$(warning sparse-llvm disabled on $(shell uname -m))
+endif
+else
$(warning Your system does not have llvm, disabling sparse-llvm)
endif
-LIB_H= token.h parse.h lib.h symbol.h scope.h expression.h target.h \
- linearize.h bitmap.h ident-list.h compat.h flow.h allocate.h \
- storage.h ptrlist.h dissect.h
+########################################################################
+LIBS := libsparse.a
+OBJS := $(LIB_OBJS) $(EXTRA_OBJS) $(PROGRAMS:%=%.o)
-LIB_OBJS= target.o parse.o tokenize.o pre-process.o symbol.o lib.o scope.o \
- expression.o show-parse.o evaluate.o expand.o inline.o linearize.o \
- char.o sort.o allocate.o compat-$(OS).o ptrlist.o \
- builtin.o \
- stats.o \
- flow.o cse.o simplify.o memops.o liveness.o storage.o unssa.o dissect.o
+# Pretty print
+V := @
+Q := $(V:1=)
-LIB_FILE= libsparse.a
-SLIB_FILE= libsparse.so
+########################################################################
+all: $(PROGRAMS)
-# If you add $(SLIB_FILE) to this, you also need to add -fpic to BASIC_CFLAGS above.
-# Doing so incurs a noticeable performance hit, and Sparse does not have a
-# stable shared library interface, so this does not occur by default. If you
-# really want a shared library, you may want to build Sparse twice: once
-# without -fpic to get all the Sparse tools, and again with -fpic to get the
-# shared library.
-LIBS=$(LIB_FILE)
+ldflags += $($(@)-ldflags) $(LDFLAGS)
+ldlibs += $($(@)-ldlibs) $(LDLIBS)
+$(PROGRAMS): % : %.o $(LIBS)
+ @echo " LD $@"
+ $(Q)$(LD) $(ldflags) $^ $(ldlibs) -o $@
-#
-# Pretty print
-#
-V = @
-Q = $(V:1=)
-QUIET_CC = $(Q:@=@echo ' CC '$@;)
-QUIET_CHECK = $(Q:@=@echo ' CHECK '$<;)
-QUIET_AR = $(Q:@=@echo ' AR '$@;)
-QUIET_GEN = $(Q:@=@echo ' GEN '$@;)
-QUIET_LINK = $(Q:@=@echo ' LINK '$@;)
-# We rely on the -v switch of install to print 'file -> $install_dir/file'
-QUIET_INST_SH = $(Q:@=echo -n ' INSTALL ';)
-QUIET_INST = $(Q:@=@echo -n ' INSTALL ';)
+libsparse.a: $(LIB_OBJS)
+ @echo " AR $@"
+ $(Q)$(AR) rcs $@ $^
-define INSTALL_EXEC
- $(QUIET_INST)install -v $1 $(DESTDIR)$2/$1 || exit 1;
-endef
+cflags += $($(*)-cflags) $(CPPFLAGS) $(CFLAGS)
+%.o: %.c
+ @echo " CC $@"
+ $(Q)$(CC) $(cflags) -c -o $@ $<
-define INSTALL_FILE
- $(QUIET_INST)install -v -m 644 $1 $(DESTDIR)$2/$1 || exit 1;
+%.sc: %.c sparse
+ @echo " CHECK $<"
+ $(Q) $(CHECKER) $(CHECKER_FLAGS) $(cflags) -c $<
-endef
+selfcheck: $(OBJS:.o=.sc)
-SED_PC_CMD = 's|@version@|$(VERSION)|g; \
- s|@prefix@|$(PREFIX)|g; \
- s|@libdir@|$(LIBDIR)|g; \
- s|@includedir@|$(INCLUDEDIR)|g'
+SPARSE_VERSION:=$(shell git describe 2>/dev/null || echo '$(VERSION)')
+lib.o: version.h
+version.h: FORCE
+ @echo '#define SPARSE_VERSION "$(SPARSE_VERSION)"' > version.h.tmp
+ @if cmp -s version.h version.h.tmp; then \
+ rm version.h.tmp; \
+ else \
+ echo " GEN $@"; \
+ mv version.h.tmp version.h; \
+ fi
-# Allow users to override build settings without dirtying their trees
--include local.mk
+check: all
+ $(Q)cd validation && ./test-suite
+validation/%.t: FORCE
+ @validation/test-suite single $*.c
-all: $(PROGRAMS) sparse.pc
+clean: clean-check
+ @rm -f *.[oa] .*.d $(PROGRAMS) version.h
+clean-check:
+ @echo " CLEAN"
+ @find validation/ \( -name "*.c.output.*" \
+ -o -name "*.c.error.*" \
+ -o -name "*.o" \
+ \) -exec rm {} \;
-all-installable: $(INST_PROGRAMS) $(LIBS) $(LIB_H) sparse.pc
-install: all-installable
+install: $(INST_PROGRAMS) $(INST_MAN1) install-dirs install-bin install-man
+install-dirs:
$(Q)install -d $(DESTDIR)$(BINDIR)
- $(Q)install -d $(DESTDIR)$(LIBDIR)
$(Q)install -d $(DESTDIR)$(MAN1DIR)
- $(Q)install -d $(DESTDIR)$(INCLUDEDIR)/sparse
- $(Q)install -d $(DESTDIR)$(PKGCONFIGDIR)
- $(foreach f,$(INST_PROGRAMS),$(call INSTALL_EXEC,$f,$(BINDIR)))
- $(foreach f,$(INST_MAN1),$(call INSTALL_FILE,$f,$(MAN1DIR)))
- $(foreach f,$(LIBS),$(call INSTALL_FILE,$f,$(LIBDIR)))
- $(foreach f,$(LIB_H),$(call INSTALL_FILE,$f,$(INCLUDEDIR)/sparse))
- $(call INSTALL_FILE,sparse.pc,$(PKGCONFIGDIR))
-
-sparse.pc: sparse.pc.in
- $(QUIET_GEN)sed $(SED_PC_CMD) sparse.pc.in > sparse.pc
-
+install-bin: $(INST_PROGRAMS:%=$(DESTDIR)$(BINDIR)/%)
+install-man: $(INST_MAN1:%=$(DESTDIR)$(MAN1DIR)/%)
-compile_EXTRA_DEPS = compile-i386.o
+$(DESTDIR)$(BINDIR)/%: %
+ @echo " INSTALL $@"
+ $(Q)install $< $@ || exit 1;
+$(DESTDIR)$(MAN1DIR)/%: %
+ @echo " INSTALL $@"
+ $(Q)install -m 644 $< $@ || exit 1;
-$(foreach p,$(PROGRAMS),$(eval $(p): $($(p)_EXTRA_DEPS) $(LIBS)))
-$(PROGRAMS): % : %.o
- $(QUIET_LINK)$(LD) $(LDFLAGS) -o $@ $^ $($@_EXTRA_OBJS)
+.PHONY: FORCE
-$(LIB_FILE): $(LIB_OBJS)
- $(QUIET_AR)$(AR) rcs $@ $(LIB_OBJS)
-
-$(SLIB_FILE): $(LIB_OBJS)
- $(QUIET_LINK)$(CC) $(LDFLAGS) -Wl,-soname,$@ -shared -o $@ $(LIB_OBJS)
-
-DEP_FILES := $(wildcard .*.o.d)
-
-ifneq ($(DEP_FILES),)
-include $(DEP_FILES)
-endif
-
-c2xml.o c2xml.sc: CFLAGS += $(LIBXML_CFLAGS)
-
-pre-process.sc: CHECKER_FLAGS += -Wno-vla
-
-%.o: %.c $(LIB_H)
- $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
-
-%.sc: %.c sparse
- $(QUIET_CHECK) $(CHECKER) $(CHECKER_FLAGS) -c $(ALL_CFLAGS) $<
-
-ALL_OBJS := $(LIB_OBJS) $(foreach p,$(PROGRAMS),$(p).o $($(p)_EXTRA_DEPS))
-selfcheck: $(ALL_OBJS:.o=.sc)
-
-
-clean: clean-check
- rm -f *.[oa] .*.d *.so $(PROGRAMS) $(SLIB_FILE) pre-process.h sparse.pc
-
-dist:
- @if test "$(SPARSE_VERSION)" != "v$(VERSION)" ; then \
- echo 'Update VERSION in the Makefile before running "make dist".' ; \
- exit 1 ; \
- fi
- git archive --format=tar --prefix=sparse-$(VERSION)/ HEAD^{tree} | gzip -9 > sparse-$(VERSION).tar.gz
-
-check: all
- $(Q)cd validation && ./test-suite
-
-clean-check:
- find validation/ \( -name "*.c.output.expected" \
- -o -name "*.c.output.got" \
- -o -name "*.c.output.diff" \
- -o -name "*.c.error.expected" \
- -o -name "*.c.error.got" \
- -o -name "*.c.error.diff" \
- \) -exec rm {} \;
+# GCC's dependencies
+-include $(OBJS:%.o=.%.o.d)
diff --git a/allocate.c b/allocate.c
index daa4ac24..0cc55630 100644
--- a/allocate.c
+++ b/allocate.c
@@ -120,7 +120,7 @@ void *allocate(struct allocator_struct *desc, unsigned int size)
void show_allocations(struct allocator_struct *x)
{
- fprintf(stderr, "%s: %d allocations, %d bytes (%d total bytes, "
+ fprintf(stderr, "%s: %d allocations, %lu bytes (%lu total bytes, "
"%6.2f%% usage, %6.2f average size)\n",
x->name, x->allocations, x->useful_bytes, x->total_bytes,
100 * (double) x->useful_bytes / x->total_bytes,
diff --git a/allocate.h b/allocate.h
index 64bb6dd6..cbddc2aa 100644
--- a/allocate.h
+++ b/allocate.h
@@ -14,7 +14,8 @@ struct allocator_struct {
unsigned int chunking;
void *freelist;
/* statistics */
- unsigned int allocations, total_bytes, useful_bytes;
+ unsigned int allocations;
+ unsigned long total_bytes, useful_bytes;
};
struct allocator_stats {
diff --git a/builtin.c b/builtin.c
index bfadc87f..9f90926c 100644
--- a/builtin.c
+++ b/builtin.c
@@ -28,12 +28,29 @@
#include "symbol.h"
#include "compat/bswap.h"
-static int evaluate_to_integer(struct expression *expr)
+static int evaluate_to_int_const_expr(struct expression *expr)
{
expr->ctype = &int_ctype;
+ expr->flags |= CEF_SET_ICE;
return 1;
}
+static int evaluate_pure_unop(struct expression *expr)
+{
+ struct expression *arg = first_expression(expr->args);
+ int flags = arg->flags;
+
+ /*
+ * Allow such functions with a constant integer expression
+ * argument to be treated as a *constant* integer.
+ * This allow us to use them in switch() { case ...:
+ */
+ flags |= (flags & CEF_ICE) ? CEF_SET_INT : 0;
+ expr->flags = flags;
+ return 1;
+}
+
+
static int evaluate_expect(struct expression *expr)
{
/* Should we evaluate it to return the type of the first argument? */
@@ -153,17 +170,17 @@ static int expand_safe_p(struct expression *expr, int cost)
}
static struct symbol_op constant_p_op = {
- .evaluate = evaluate_to_integer,
+ .evaluate = evaluate_to_int_const_expr,
.expand = expand_constant_p
};
static struct symbol_op safe_p_op = {
- .evaluate = evaluate_to_integer,
+ .evaluate = evaluate_to_int_const_expr,
.expand = expand_safe_p
};
static struct symbol_op warning_op = {
- .evaluate = evaluate_to_integer,
+ .evaluate = evaluate_to_int_const_expr,
.expand = expand_warning
};
@@ -203,6 +220,7 @@ static int expand_bswap(struct expression *expr, int cost)
}
static struct symbol_op bswap_op = {
+ .evaluate = evaluate_pure_unop,
.expand = expand_bswap,
};
diff --git a/cgcc b/cgcc
index 4aeb2da6..1f7b625c 100755
--- a/cgcc
+++ b/cgcc
@@ -236,9 +236,18 @@ sub add_specs {
} elsif ($spec eq 'linux') {
return &add_specs ('unix') .
' -D__linux__=1 -D__linux=1 -Dlinux=linux';
+ } elsif ($spec eq 'gnu/kfreebsd') {
+ return &add_specs ('unix') .
+ ' -D__FreeBSD_kernel__=1';
} elsif ($spec eq 'openbsd') {
return &add_specs ('unix') .
' -D__OpenBSD__=1';
+ } elsif ($spec eq 'freebsd') {
+ return &add_specs ('unix') .
+ ' -D__FreeBSD__=1';
+ } elsif ($spec eq 'netbsd') {
+ return &add_specs ('unix') .
+ ' -D__NetBSD__=1';
} elsif ($spec eq 'darwin') {
return
' -D__APPLE__=1 -D__MACH__=1';
@@ -287,7 +296,6 @@ sub add_specs {
} elsif ($spec eq 'ppc64') {
return (' -D__powerpc__=1 -D__PPC__=1 -D_STRING_ARCH_unaligned=1' .
' -D__powerpc64__=1 -D__PPC64__=1' .
- ' -D_CALL_ELF=2' .
' -m64' .
&float_types (1, 1, 21, [24,8], [53,11], [113,15]));
} elsif ($spec eq 's390x') {
@@ -297,7 +305,14 @@ sub add_specs {
&define_size_t ("long unsigned int") .
' -D__SIZEOF_POINTER__=' . ($m64 ? '8' : '4'));
} elsif ($spec eq 'arm') {
- return (' -D__arm__=1 -m32' .
+ chomp (my $gccmachine = `$cc -dumpmachine`);
+ my $cppsymbols = ' -D__arm__=1 -m32';
+
+ if ($gccmachine eq 'arm-linux-gnueabihf') {
+ $cppsymbols .= ' -D__ARM_PCS_VFP=1';
+ }
+
+ return ($cppsymbols .
&float_types (1, 1, 36, [24,8], [53,11], [53, 11]));
} elsif ($spec eq 'aarch64') {
return (' -D__aarch64__=1 -m64' .
@@ -318,14 +333,14 @@ sub add_specs {
} elsif ($arch =~ /^(ppc)$/i) {
return &add_specs ('ppc');
} elsif ($arch =~ /^(ppc64)$/i) {
- return &add_specs ('ppc64') . ' -mbig-endian';
+ return &add_specs ('ppc64') . ' -mbig-endian -D_CALL_ELF=1';
} elsif ($arch =~ /^(ppc64le)$/i) {
- return &add_specs ('ppc64') . ' -mlittle-endian';
+ return &add_specs ('ppc64') . ' -mlittle-endian -D_CALL_ELF=2';
} elsif ($arch =~ /^(s390x)$/i) {
return &add_specs ('s390x');
} elsif ($arch =~ /^(sparc64)$/i) {
return &add_specs ('sparc64');
- } elsif ($arch =~ /^(arm)$/i) {
+ } elsif ($arch =~ /^arm(?:v[78]l)?$/i) {
return &add_specs ('arm');
} elsif ($arch =~ /^(aarch64)$/i) {
return &add_specs ('aarch64');
diff --git a/compile-i386.c b/compile-i386.c
index 44b72ec3..7b7ace92 100644
--- a/compile-i386.c
+++ b/compile-i386.c
@@ -57,6 +57,7 @@
#include "target.h"
#include "compile.h"
#include "bitmap.h"
+#include "version.h"
struct textbuf {
unsigned int len; /* does NOT include terminating null */
@@ -691,7 +692,7 @@ void emit_unit_begin(const char *basename)
void emit_unit_end(void)
{
textbuf_emit(&unit_post_text);
- printf("\t.ident\t\"sparse silly x86 backend (built %s)\"\n", __DATE__);
+ printf("\t.ident\t\"sparse silly x86 backend (version %s)\"\n", SPARSE_VERSION);
}
/* conditionally switch sections */
@@ -997,11 +998,7 @@ static void sort_array(struct expression *expr)
struct expression *entry, **list;
unsigned int elem, sorted, i;
- elem = 0;
- FOR_EACH_PTR(expr->expr_list, entry) {
- elem++;
- } END_FOR_EACH_PTR(entry);
-
+ elem = expression_list_size(expr->expr_list);
if (!elem)
return;
@@ -1048,6 +1045,7 @@ static void sort_array(struct expression *expr)
*THIS_ADDRESS(entry) = list[i++];
} END_FOR_EACH_PTR(entry);
+ free(list);
}
static void emit_array(struct symbol *sym)
@@ -2238,7 +2236,7 @@ static struct storage *x86_symbol_expr(struct symbol *sym)
return new;
}
if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
- printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, sym->value);
+ printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new->pseudo, 0LL);
return new;
}
printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new->pseudo, show_ident(sym->ident), sym);
diff --git a/evaluate.c b/evaluate.c
index 649e132b..4bca1354 100644
--- a/evaluate.c
+++ b/evaluate.c
@@ -70,9 +70,11 @@ static struct symbol *evaluate_symbol_expression(struct expression *expr)
addr->symbol = sym;
addr->symbol_name = expr->symbol_name;
addr->ctype = &lazy_ptr_ctype; /* Lazy evaluation: we need to do a proper job if somebody does &sym */
+ addr->flags = expr->flags;
expr->type = EXPR_PREOP;
expr->op = '*';
expr->unop = addr;
+ expr->flags = CEF_NONE;
/* The type of a symbol is the symbol itself! */
expr->ctype = sym;
@@ -106,6 +108,7 @@ static struct symbol *evaluate_string(struct expression *expr)
addr->symbol = sym;
addr->ctype = &lazy_ptr_ctype;
+ addr->flags = CEF_ADDR;
expr->type = EXPR_PREOP;
expr->op = '*';
@@ -271,6 +274,7 @@ warn_for_different_enum_types (struct position pos,
}
}
+static int cast_flags(struct expression *expr, struct expression *target);
static struct symbol *cast_to_bool(struct expression *expr);
/*
@@ -323,10 +327,10 @@ static struct expression * cast_to(struct expression *old, struct symbol *type)
}
expr = alloc_expression(old->pos, EXPR_IMPLIED_CAST);
- expr->flags = old->flags;
expr->ctype = type;
expr->cast_type = type;
expr->cast_expression = old;
+ expr->flags = cast_flags(expr, old);
if (is_bool_type(type))
cast_to_bool(expr);
@@ -404,7 +408,7 @@ static struct symbol *bad_expr_type(struct expression *expr)
break;
}
- expr->flags = 0;
+ expr->flags = CEF_NONE;
return expr->ctype = &bad_ctype;
}
@@ -568,6 +572,13 @@ static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *i
classify_type(degenerate(expr->left), &ctype);
base = examine_pointer_target(ctype);
+ /*
+ * An address constant +/- an integer constant expression
+ * yields an address constant again [6.6(7)].
+ */
+ if ((expr->left->flags & CEF_ADDR) && (expr->right->flags & CEF_ICE))
+ expr->flags = CEF_ADDR;
+
if (!base) {
expression_error(expr, "missing type information");
return NULL;
@@ -627,7 +638,7 @@ static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *i
static void examine_fn_arguments(struct symbol *fn);
-#define MOD_IGN (MOD_VOLATILE | MOD_CONST | MOD_PURE)
+#define MOD_IGN (MOD_QUALIFIER | MOD_PURE)
const char *type_difference(struct ctype *c1, struct ctype *c2,
unsigned long mod1, unsigned long mod2)
@@ -895,10 +906,8 @@ static struct symbol *evaluate_logical(struct expression *expr)
/* the result is int [6.5.13(3), 6.5.14(3)] */
expr->ctype = &int_ctype;
- if (expr->flags) {
- if (!(expr->left->flags & expr->right->flags & Int_const_expr))
- expr->flags = 0;
- }
+ expr->flags = expr->left->flags & expr->right->flags;
+ expr->flags &= ~(CEF_CONST_MASK | CEF_ADDR);
return &int_ctype;
}
@@ -909,13 +918,11 @@ static struct symbol *evaluate_binop(struct expression *expr)
int rclass = classify_type(expr->right->ctype, &rtype);
int op = expr->op;
- if (expr->flags) {
- if (!(expr->left->flags & expr->right->flags & Int_const_expr))
- expr->flags = 0;
- }
-
/* number op number */
if (lclass & rclass & TYPE_NUM) {
+ expr->flags = expr->left->flags & expr->right->flags;
+ expr->flags &= ~CEF_CONST_MASK;
+
if ((lclass | rclass) & TYPE_FLOAT) {
switch (op) {
case '+': case '-': case '*': case '/':
@@ -1002,7 +1009,7 @@ static inline int is_null_pointer_constant(struct expression *e)
{
if (e->ctype == &null_ctype)
return 1;
- if (!(e->flags & Int_const_expr))
+ if (!(e->flags & CEF_ICE))
return 0;
return is_zero_constant(e) ? 2 : 0;
}
@@ -1016,18 +1023,21 @@ static struct symbol *evaluate_compare(struct expression *expr)
struct symbol *ctype;
const char *typediff;
- if (expr->flags) {
- if (!(expr->left->flags & expr->right->flags & Int_const_expr))
- expr->flags = 0;
- }
-
/* Type types? */
- if (is_type_type(ltype) && is_type_type(rtype))
+ if (is_type_type(ltype) && is_type_type(rtype)) {
+ /*
+ * __builtin_types_compatible_p() yields an integer
+ * constant expression
+ */
+ expr->flags = CEF_SET_ICE;
goto OK;
+ }
if (is_safe_type(left->ctype) || is_safe_type(right->ctype))
warning(expr->pos, "testing a 'safe expression'");
+ expr->flags = left->flags & right->flags & ~CEF_CONST_MASK & ~CEF_ADDR;
+
/* number on number */
if (lclass & rclass & TYPE_NUM) {
ctype = usual_conversions(expr->op, expr->left, expr->right,
@@ -1135,12 +1145,23 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr)
true = &expr->cond_true;
}
- if (expr->flags) {
- int flags = expr->conditional->flags & Int_const_expr;
- flags &= (*true)->flags & expr->cond_false->flags;
- if (!flags)
- expr->flags = 0;
- }
+ expr->flags = (expr->conditional->flags & (*true)->flags &
+ expr->cond_false->flags & ~CEF_CONST_MASK);
+ /*
+ * A conditional operator yields a particular constant
+ * expression type only if all of its three subexpressions are
+ * of that type [6.6(6), 6.6(8)].
+ * As an extension, relax this restriction by allowing any
+ * constant expression type for the condition expression.
+ *
+ * A conditional operator never yields an address constant
+ * [6.6(9)].
+ * However, as an extension, if the condition is any constant
+ * expression, and the true and false expressions are both
+ * address constants, mark the result as an address constant.
+ */
+ if (expr->conditional->flags & (CEF_ACE | CEF_ADDR))
+ expr->flags = (*true)->flags & expr->cond_false->flags & ~CEF_CONST_MASK;
lclass = classify_type(ltype, &ltype);
rclass = classify_type(rtype, &rtype);
@@ -1718,7 +1739,6 @@ static struct symbol *evaluate_addressof(struct expression *expr)
}
ctype = op->ctype;
*expr = *op->unop;
- expr->flags = 0;
if (expr->type == EXPR_SYMBOL) {
struct symbol *sym = expr->symbol;
@@ -1746,7 +1766,7 @@ static struct symbol *evaluate_dereference(struct expression *expr)
/* Simplify: *&(expr) => (expr) */
if (op->type == EXPR_PREOP && op->op == '&') {
*expr = *op->unop;
- expr->flags = 0;
+ expr->flags = CEF_NONE;
return expr->ctype;
}
@@ -1838,8 +1858,8 @@ static struct symbol *evaluate_sign(struct expression *expr)
{
struct symbol *ctype = expr->unop->ctype;
int class = classify_type(ctype, &ctype);
- if (expr->flags && !(expr->unop->flags & Int_const_expr))
- expr->flags = 0;
+ unsigned char flags = expr->unop->flags & ~CEF_CONST_MASK;
+
/* should be an arithmetic type */
if (!(class & TYPE_NUM))
return bad_expr_type(expr);
@@ -1856,6 +1876,7 @@ Normal:
}
if (expr->op == '+')
*expr = *expr->unop;
+ expr->flags = flags;
expr->ctype = ctype;
return ctype;
Restr:
@@ -1893,8 +1914,13 @@ static struct symbol *evaluate_preop(struct expression *expr)
return evaluate_postop(expr);
case '!':
- if (expr->flags && !(expr->unop->flags & Int_const_expr))
- expr->flags = 0;
+ expr->flags = expr->unop->flags & ~CEF_CONST_MASK;
+ /*
+ * A logical negation never yields an address constant
+ * [6.6(9)].
+ */
+ expr->flags &= ~CEF_ADDR;
+
if (is_safe_type(ctype))
warning(expr->pos, "testing a 'safe expression'");
if (is_float_type(ctype)) {
@@ -1979,6 +2005,12 @@ static struct expression *evaluate_offset(struct expression *expr, unsigned long
* we ever take the address of this member dereference..
*/
add->ctype = &lazy_ptr_ctype;
+ /*
+ * The resulting address of a member access through an address
+ * constant is an address constant again [6.6(9)].
+ */
+ add->flags = expr->flags;
+
return add;
}
@@ -2475,14 +2507,14 @@ static struct expression *next_designators(struct expression *old,
return new;
}
-static int handle_simple_initializer(struct expression **ep, int nested,
- int class, struct symbol *ctype);
+static int handle_initializer(struct expression **ep, int nested,
+ int class, struct symbol *ctype, unsigned long mods);
/*
* deal with traversing subobjects [6.7.8(17,18,20)]
*/
static void handle_list_initializer(struct expression *expr,
- int class, struct symbol *ctype)
+ int class, struct symbol *ctype, unsigned long mods)
{
struct expression *e, *last = NULL, *top = NULL, *next;
int jumped = 0;
@@ -2540,7 +2572,8 @@ found:
else
v = &top->ident_expression;
- if (handle_simple_initializer(v, 1, lclass, top->ctype))
+ mods |= ctype->ctype.modifiers & MOD_STORAGE;
+ if (handle_initializer(v, 1, lclass, top->ctype, mods))
continue;
if (!(lclass & TYPE_COMPOUND)) {
@@ -2632,8 +2665,8 @@ static struct expression *handle_scalar(struct expression *e, int nested)
* { "string", ...} - we need to preserve that string literal recognizable
* until we dig into the inner struct.
*/
-static int handle_simple_initializer(struct expression **ep, int nested,
- int class, struct symbol *ctype)
+static int handle_initializer(struct expression **ep, int nested,
+ int class, struct symbol *ctype, unsigned long mods)
{
int is_string = is_string_type(ctype);
struct expression *e = *ep, *p;
@@ -2651,6 +2684,16 @@ static int handle_simple_initializer(struct expression **ep, int nested,
if (!evaluate_expression(e))
return 1;
compatible_assignment_types(e, ctype, ep, "initializer");
+ /*
+ * Initializers for static storage duration objects
+ * shall be constant expressions or a string literal [6.7.8(4)].
+ */
+ mods |= ctype->ctype.modifiers;
+ mods &= (MOD_TOPLEVEL | MOD_STATIC);
+ if (mods && !(e->flags & (CEF_ACE | CEF_ADDR)))
+ if (Wconstexpr_not_const)
+ warning(e->pos, "non-constant initializer for static object");
+
return 1;
}
@@ -2673,7 +2716,7 @@ static int handle_simple_initializer(struct expression **ep, int nested,
goto String;
}
}
- handle_list_initializer(e, class, ctype);
+ handle_list_initializer(e, class, ctype, mods);
return 1;
}
@@ -2721,7 +2764,7 @@ static void evaluate_initializer(struct symbol *ctype, struct expression **ep)
{
struct symbol *type;
int class = classify_type(ctype, &type);
- if (!handle_simple_initializer(ep, 0, class, ctype))
+ if (!handle_initializer(ep, 0, class, ctype, 0))
expression_error(*ep, "invalid initializer");
}
@@ -2747,6 +2790,59 @@ static struct symbol *cast_to_bool(struct expression *expr)
return expr->ctype;
}
+static int cast_flags(struct expression *expr, struct expression *old)
+{
+ struct symbol *t;
+ int class;
+ int flags = CEF_NONE;
+
+ class = classify_type(expr->ctype, &t);
+ if (class & TYPE_NUM) {
+ flags = old->flags & ~CEF_CONST_MASK;
+ /*
+ * Casts to numeric types never result in address
+ * constants [6.6(9)].
+ */
+ flags &= ~CEF_ADDR;
+
+ /*
+ * As an extension, treat address constants cast to
+ * integer type as an arithmetic constant.
+ */
+ if (old->flags & CEF_ADDR)
+ flags = CEF_ACE;
+
+ /*
+ * Cast to float type -> not an integer constant
+ * expression [6.6(6)].
+ */
+ if (class & TYPE_FLOAT)
+ flags &= ~CEF_CLR_ICE;
+ /*
+ * Casts of float literals to integer type results in
+ * a constant integer expression [6.6(6)].
+ */
+ else if (old->flags & CEF_FLOAT)
+ flags = CEF_SET_ICE;
+ } else if (class & TYPE_PTR) {
+ /*
+ * Casts of integer literals to pointer type yield
+ * address constants [6.6(9)].
+ *
+ * As an extension, treat address constants cast to a
+ * different pointer type as address constants again.
+ *
+ * As another extension, treat integer constant
+ * expressions (in contrast to literals) cast to
+ * pointer type as address constants.
+ */
+ if (old->flags & (CEF_ICE | CEF_ADDR))
+ flags = CEF_ADDR;
+ }
+
+ return flags;
+}
+
static struct symbol *evaluate_cast(struct expression *expr)
{
struct expression *target = expr->cast_expression;
@@ -2777,6 +2873,8 @@ static struct symbol *evaluate_cast(struct expression *expr)
addr->ctype = &lazy_ptr_ctype; /* Lazy eval */
addr->symbol = sym;
+ if (sym->ctype.modifiers & MOD_TOPLEVEL)
+ addr->flags |= CEF_ADDR;
expr->type = EXPR_PREOP;
expr->op = '*';
@@ -2795,14 +2893,8 @@ static struct symbol *evaluate_cast(struct expression *expr)
class1 = classify_type(ctype, &t1);
- /* cast to non-integer type -> not an integer constant expression */
- if (!is_int(class1))
- expr->flags = 0;
- /* if argument turns out to be not an integer constant expression *and*
- it was not a floating literal to start with -> too bad */
- else if (expr->flags == Int_const_expr &&
- !(target->flags & Int_const_expr))
- expr->flags = 0;
+ expr->flags = cast_flags(expr, target);
+
/*
* You can always throw a value away by casting to
* "void" - that's an implicit "force". Note that
@@ -2871,7 +2963,7 @@ static struct symbol *evaluate_cast(struct expression *expr)
"cast adds address space to expression (<asn:%d>)", as1);
if (!(t1->ctype.modifiers & MOD_PTRINHERIT) && class1 == TYPE_PTR &&
- !as1 && (target->flags & Int_const_expr)) {
+ !as1 && (target->flags & CEF_ICE)) {
if (t1->ctype.base_type == &void_ctype) {
if (is_zero_constant(target)) {
/* NULL */
@@ -2961,20 +3053,22 @@ static struct symbol *evaluate_call(struct expression *expr)
return NULL;
args = expression_list_size(expr->args);
fnargs = symbol_list_size(ctype->arguments);
- if (args < fnargs)
+ if (args < fnargs) {
expression_error(expr,
"not enough arguments for function %s",
show_ident(sym->ident));
+ return NULL;
+ }
if (args > fnargs && !ctype->variadic)
expression_error(expr,
"too many arguments for function %s",
show_ident(sym->ident));
}
+ expr->ctype = ctype->ctype.base_type;
if (sym->type == SYM_NODE) {
if (evaluate_symbol_call(expr))
return expr->ctype;
}
- expr->ctype = ctype->ctype.base_type;
return expr->ctype;
}
@@ -3005,7 +3099,7 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
}
ctype = field;
expr->type = EXPR_VALUE;
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_ICE;
expr->value = offset;
expr->taint = 0;
expr->ctype = size_t_ctype;
@@ -3023,30 +3117,34 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
ctype = ctype->ctype.base_type;
if (!expr->index) {
expr->type = EXPR_VALUE;
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_ICE;
expr->value = 0;
expr->taint = 0;
expr->ctype = size_t_ctype;
} else {
struct expression *idx = expr->index, *m;
struct symbol *i_type = evaluate_expression(idx);
+ unsigned old_idx_flags;
int i_class = classify_type(i_type, &i_type);
+
if (!is_int(i_class)) {
expression_error(expr, "non-integer index");
return NULL;
}
unrestrict(idx, i_class, &i_type);
+ old_idx_flags = idx->flags;
idx = cast_to(idx, size_t_ctype);
+ idx->flags = old_idx_flags;
m = alloc_const_expression(expr->pos,
bits_to_bytes(ctype->bit_size));
m->ctype = size_t_ctype;
- m->flags = Int_const_expr;
+ m->flags = CEF_SET_INT;
expr->type = EXPR_BINOP;
expr->left = idx;
expr->right = m;
expr->op = '*';
expr->ctype = size_t_ctype;
- expr->flags = m->flags & idx->flags & Int_const_expr;
+ expr->flags = m->flags & idx->flags & ~CEF_CONST_MASK;
}
}
if (e) {
@@ -3057,7 +3155,7 @@ static struct symbol *evaluate_offsetof(struct expression *expr)
if (!evaluate_expression(e))
return NULL;
expr->type = EXPR_BINOP;
- expr->flags = e->flags & copy->flags & Int_const_expr;
+ expr->flags = e->flags & copy->flags & ~CEF_CONST_MASK;
expr->op = '+';
expr->ctype = size_t_ctype;
expr->left = copy;
@@ -3160,6 +3258,9 @@ struct symbol *evaluate_expression(struct expression *expr)
case EXPR_SLICE:
expression_error(expr, "internal front-end error: SLICE re-evaluated");
return NULL;
+ case EXPR_ASM_OPERAND:
+ expression_error(expr, "internal front-end error: ASM_OPERAND evaluated");
+ return NULL;
}
return NULL;
}
@@ -3322,8 +3423,8 @@ static void verify_input_constraint(struct expression *expr, const char *constra
static void evaluate_asm_statement(struct statement *stmt)
{
struct expression *expr;
+ struct expression *op;
struct symbol *sym;
- int state;
expr = stmt->asm_string;
if (!expr || expr->type != EXPR_STRING) {
@@ -3331,58 +3432,41 @@ static void evaluate_asm_statement(struct statement *stmt)
return;
}
- state = 0;
- FOR_EACH_PTR(stmt->asm_outputs, expr) {
- switch (state) {
- case 0: /* Identifier */
- state = 1;
- continue;
+ FOR_EACH_PTR(stmt->asm_outputs, op) {
+ /* Identifier */
- case 1: /* Constraint */
- state = 2;
- if (!expr || expr->type != EXPR_STRING) {
- sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string");
- *THIS_ADDRESS(expr) = NULL;
- continue;
- }
+ /* Constraint */
+ expr = op->constraint;
+ if (!expr || expr->type != EXPR_STRING) {
+ sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string");
+ op->constraint = NULL;
+ } else
verify_output_constraint(expr, expr->string->data);
- continue;
-
- case 2: /* Expression */
- state = 0;
- if (!evaluate_expression(expr))
- return;
- if (!lvalue_expression(expr))
- warning(expr->pos, "asm output is not an lvalue");
- evaluate_assign_to(expr, expr->ctype);
- continue;
- }
- } END_FOR_EACH_PTR(expr);
-
- state = 0;
- FOR_EACH_PTR(stmt->asm_inputs, expr) {
- switch (state) {
- case 0: /* Identifier */
- state = 1;
- continue;
- case 1: /* Constraint */
- state = 2;
- if (!expr || expr->type != EXPR_STRING) {
- sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string");
- *THIS_ADDRESS(expr) = NULL;
- continue;
- }
+ /* Expression */
+ expr = op->expr;
+ if (!evaluate_expression(expr))
+ return;
+ if (!lvalue_expression(expr))
+ warning(expr->pos, "asm output is not an lvalue");
+ evaluate_assign_to(expr, expr->ctype);
+ } END_FOR_EACH_PTR(op);
+
+ FOR_EACH_PTR(stmt->asm_inputs, op) {
+ /* Identifier */
+
+ /* Constraint */
+ expr = op->constraint;
+ if (!expr || expr->type != EXPR_STRING) {
+ sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string");
+ op->constraint = NULL;
+ } else
verify_input_constraint(expr, expr->string->data);
- continue;
- case 2: /* Expression */
- state = 0;
- if (!evaluate_expression(expr))
- return;
- continue;
- }
- } END_FOR_EACH_PTR(expr);
+ /* Expression */
+ if (!evaluate_expression(op->expr))
+ return;
+ } END_FOR_EACH_PTR(op);
FOR_EACH_PTR(stmt->asm_clobbers, expr) {
if (!expr) {
diff --git a/expand.c b/expand.c
index f436b5b5..f1aa838d 100644
--- a/expand.c
+++ b/expand.c
@@ -478,7 +478,7 @@ static int expand_comma(struct expression *expr)
return cost;
}
-#define MOD_IGN (MOD_VOLATILE | MOD_CONST)
+#define MOD_IGN (MOD_QUALIFIER)
static int compare_types(int op, struct symbol *left, struct symbol *right)
{
@@ -582,7 +582,7 @@ static struct expression *constant_symbol_value(struct symbol *sym, int offset)
{
struct expression *value;
- if (sym->ctype.modifiers & (MOD_ASSIGNED | MOD_ADDRESSABLE))
+ if (sym->ctype.modifiers & MOD_ACCESS)
return NULL;
value = sym->initializer;
if (!value)
@@ -1048,6 +1048,9 @@ static int expand_expression(struct expression *expr)
case EXPR_OFFSETOF:
expression_error(expr, "internal front-end error: sizeof in expansion?");
return UNSAFE;
+ case EXPR_ASM_OPERAND:
+ expression_error(expr, "internal front-end error: ASM_OPERAND in expansion?");
+ return UNSAFE;
}
return SIDE_EFFECTS;
}
@@ -1223,7 +1226,7 @@ static int expand_statement(struct statement *stmt)
static inline int bad_integer_constant_expression(struct expression *expr)
{
- if (!(expr->flags & Int_const_expr))
+ if (!(expr->flags & CEF_ICE))
return 1;
if (expr->taint & Taint_comma)
return 1;
diff --git a/expression.c b/expression.c
index 638639df..e5ebad65 100644
--- a/expression.c
+++ b/expression.c
@@ -131,7 +131,6 @@ static struct token *parse_type(struct token *token, struct expression **tree)
{
struct symbol *sym;
*tree = alloc_expression(token->pos, EXPR_TYPE);
- (*tree)->flags = Int_const_expr; /* sic */
token = typename(token, &sym, NULL);
if (sym->ident)
sparse_error(token->pos,
@@ -146,7 +145,6 @@ static struct token *builtin_types_compatible_p_expr(struct token *token,
{
struct expression *expr = alloc_expression(
token->pos, EXPR_COMPARE);
- expr->flags = Int_const_expr;
expr->op = SPECIAL_EQUAL;
token = token->next;
if (!match_op(token, '('))
@@ -200,7 +198,6 @@ static struct token *builtin_offsetof_expr(struct token *token,
return expect(token, ')', "at end of __builtin_offset");
case SPECIAL_DEREFERENCE:
e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->flags = Int_const_expr;
e->op = '[';
*p = e;
p = &e->down;
@@ -208,7 +205,6 @@ static struct token *builtin_offsetof_expr(struct token *token,
case '.':
token = token->next;
e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->flags = Int_const_expr;
e->op = '.';
if (token_type(token) != TOKEN_IDENT) {
sparse_error(token->pos, "Expected member name");
@@ -220,7 +216,6 @@ static struct token *builtin_offsetof_expr(struct token *token,
case '[':
token = token->next;
e = alloc_expression(token->pos, EXPR_OFFSETOF);
- e->flags = Int_const_expr;
e->op = '[';
token = parse_expression(token, &e->index);
token = expect(token, ']',
@@ -336,7 +331,7 @@ got_it:
"likely to produce unsigned long (and a warning) here",
show_token(token));
expr->type = EXPR_VALUE;
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_INT;
expr->ctype = ctype_integer(size, want_unsigned);
expr->value = value;
return;
@@ -361,7 +356,7 @@ Float:
else
goto Enoint;
- expr->flags = Float_literal;
+ expr->flags = CEF_SET_FLOAT;
expr->type = EXPR_FVALUE;
return;
@@ -375,8 +370,8 @@ struct token *primary_expression(struct token *token, struct expression **tree)
switch (token_type(token)) {
case TOKEN_CHAR ... TOKEN_WIDE_CHAR_EMBEDDED_3:
- expr = alloc_expression(token->pos, EXPR_VALUE);
- expr->flags = Int_const_expr;
+ expr = alloc_expression(token->pos, EXPR_VALUE);
+ expr->flags = CEF_SET_CHAR;
expr->ctype = token_type(token) < TOKEN_WIDE_CHAR ? &int_ctype : &long_ctype;
get_char_constant(token, &expr->value);
token = token->next;
@@ -390,7 +385,7 @@ struct token *primary_expression(struct token *token, struct expression **tree)
case TOKEN_ZERO_IDENT: {
expr = alloc_expression(token->pos, EXPR_SYMBOL);
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_INT;
expr->ctype = &int_ctype;
expr->symbol = &zero_int;
expr->symbol_name = token->ident;
@@ -417,7 +412,7 @@ struct token *primary_expression(struct token *token, struct expression **tree)
*expr = *sym->initializer;
/* we want the right position reported, thus the copy */
expr->pos = token->pos;
- expr->flags = Int_const_expr;
+ expr->flags = CEF_SET_ENUM;
token = next;
break;
}
@@ -436,6 +431,14 @@ struct token *primary_expression(struct token *token, struct expression **tree)
}
expr->symbol_name = token->ident;
expr->symbol = sym;
+
+ /*
+ * A pointer to an lvalue designating a static storage
+ * duration object is an address constant [6.6(9)].
+ */
+ if (sym && (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_STATIC)))
+ expr->flags = CEF_ADDR;
+
token = next;
break;
}
@@ -451,13 +454,10 @@ struct token *primary_expression(struct token *token, struct expression **tree)
expr = alloc_expression(token->pos, EXPR_PREOP);
expr->op = '(';
token = parens_expression(token, &expr->unop, "in expression");
- if (expr->unop)
- expr->flags = expr->unop->flags;
break;
}
if (token->special == '[' && lookup_type(token->next)) {
expr = alloc_expression(token->pos, EXPR_TYPE);
- expr->flags = Int_const_expr; /* sic */
token = typename(token->next, &expr->symbol, NULL);
token = expect(token, ']', "in type expression");
break;
@@ -573,7 +573,7 @@ static struct token *type_info_expression(struct token *token,
struct token *p;
*tree = expr;
- expr->flags = Int_const_expr; /* XXX: VLA support will need that changed */
+ expr->flags = CEF_SET_ICE; /* XXX: VLA support will need that changed */
token = token->next;
if (!match_op(token, '(') || !lookup_type(token->next))
return unary_expression(token, &expr->cast_expression);
@@ -663,7 +663,6 @@ static struct token *unary_expression(struct token *token, struct expression **t
unary = alloc_expression(token->pos, EXPR_PREOP);
unary->op = token->special;
unary->unop = unop;
- unary->flags = unop->flags & Int_const_expr;
*tree = unary;
return next;
}
@@ -676,6 +675,7 @@ static struct token *unary_expression(struct token *token, struct expression **t
sym->ctype.modifiers |= MOD_ADDRESSABLE;
add_symbol(&function_computed_target_list, sym);
}
+ label->flags = CEF_ADDR;
label->label_symbol = sym;
*tree = label;
return token->next->next;
@@ -708,6 +708,8 @@ static struct token *cast_expression(struct token *token, struct expression **tr
cast->cast_type = sym;
token = expect(token, ')', "at end of cast operator");
if (match_op(token, '{')) {
+ if (toplevel(block_scope))
+ sym->ctype.modifiers |= MOD_TOPLEVEL;
if (is_force)
warning(sym->pos,
"[force] in compound literal");
@@ -721,10 +723,6 @@ static struct token *cast_expression(struct token *token, struct expression **tr
if (!v)
return token;
cast->cast_expression = v;
- if (v->flags & Int_const_expr)
- cast->flags = Int_const_expr;
- else if (v->flags & Float_literal) /* and _not_ int */
- cast->flags = Int_const_expr | Float_literal;
return token;
}
}
@@ -761,8 +759,6 @@ static struct token *cast_expression(struct token *token, struct expression **tr
sparse_error(next->pos, "No right hand side of '%s'-expression", show_special(op)); \
break; \
} \
- top->flags = left->flags & right->flags \
- & Int_const_expr; \
top->op = op; \
top->left = left; \
top->right = right; \
@@ -865,14 +861,6 @@ struct token *conditional_expression(struct token *token, struct expression **tr
token = parse_expression(token->next, &expr->cond_true);
token = expect(token, ':', "in conditional expression");
token = conditional_expression(token, &expr->cond_false);
- if (expr->left && expr->cond_false) {
- int is_const = expr->left->flags &
- expr->cond_false->flags &
- Int_const_expr;
- if (expr->cond_true)
- is_const &= expr->cond_true->flags;
- expr->flags = is_const;
- }
}
return token;
}
diff --git a/expression.h b/expression.h
index d0f3ac92..d12b9197 100644
--- a/expression.h
+++ b/expression.h
@@ -64,12 +64,73 @@ enum expression_type {
EXPR_FVALUE,
EXPR_SLICE,
EXPR_OFFSETOF,
+ EXPR_ASM_OPERAND,
};
-enum {
- Int_const_expr = 1,
- Float_literal = 2,
-}; /* for expr->flags */
+
+/*
+ * Flags for tracking the promotion of constness related attributes
+ * from subexpressions to their parents.
+ *
+ * The flags are not independent as one might imply another.
+ * The implications are as follows:
+ * - CEF_INT, CEF_ENUM and
+ * CEF_CHAR imply CEF_ICE.
+ *
+ * Use the CEF_*_SET_MASK and CEF_*_CLEAR_MASK
+ * helper macros defined below to set or clear one of these flags.
+ */
+enum constexpr_flag {
+ CEF_NONE = 0,
+ /*
+ * A constant in the sense of [6.4.4]:
+ * - Integer constant [6.4.4.1]
+ * - Floating point constant [6.4.4.2]
+ * - Enumeration constant [6.4.4.3]
+ * - Character constant [6.4.4.4]
+ */
+ CEF_INT = (1 << 0),
+ CEF_FLOAT = (1 << 1),
+ CEF_ENUM = (1 << 2),
+ CEF_CHAR = (1 << 3),
+
+ /*
+ * A constant expression in the sense of [6.6]:
+ * - integer constant expression [6.6(6)]
+ * - arithmetic constant expression [6.6(8)]
+ * - address constant [6.6(9)]
+ */
+ CEF_ICE = (1 << 4),
+ CEF_ACE = (1 << 5),
+ CEF_ADDR = (1 << 6),
+
+ /* integer constant expression => arithmetic constant expression */
+ CEF_SET_ICE = (CEF_ICE | CEF_ACE),
+
+ /* integer constant => integer constant expression */
+ CEF_SET_INT = (CEF_INT | CEF_SET_ICE),
+
+ /* floating point constant => arithmetic constant expression */
+ CEF_SET_FLOAT = (CEF_FLOAT | CEF_ACE),
+
+ /* enumeration constant => integer constant expression */
+ CEF_SET_ENUM = (CEF_ENUM | CEF_SET_ICE),
+
+ /* character constant => integer constant expression */
+ CEF_SET_CHAR = (CEF_CHAR | CEF_SET_ICE),
+
+ /*
+ * Remove any "Constant" [6.4.4] flag, but retain the "constant
+ * expression" [6.6] flags.
+ */
+ CEF_CONST_MASK = (CEF_INT | CEF_FLOAT | CEF_CHAR),
+
+ /*
+ * not an integer constant expression => neither of integer,
+ * enumeration and character constant
+ */
+ CEF_CLR_ICE = (CEF_ICE | CEF_INT | CEF_ENUM | CEF_CHAR),
+};
enum {
Taint_comma = 1,
@@ -173,6 +234,12 @@ struct expression {
struct expression *index;
};
};
+ // EXPR_ASM_OPERAND
+ struct {
+ struct ident *name;
+ struct expression *constraint;
+ struct expression *expr;
+ };
};
};
@@ -201,6 +268,7 @@ static inline struct expression *alloc_expression(struct position pos, int type)
struct expression *expr = __alloc_expression(0);
expr->type = type;
expr->pos = pos;
+ expr->flags = CEF_NONE;
return expr;
}
@@ -211,6 +279,7 @@ static inline struct expression *alloc_const_expression(struct position pos, int
expr->pos = pos;
expr->value = value;
expr->ctype = &int_ctype;
+ expr->flags = CEF_SET_INT;
return expr;
}
diff --git a/flow.c b/flow.c
index 6b2c879a..1144bff4 100644
--- a/flow.c
+++ b/flow.c
@@ -169,6 +169,13 @@ static int bb_has_side_effects(struct basic_block *bb)
/* FIXME! This should take "const" etc into account */
return 1;
+ case OP_LOAD:
+ if (!insn->type)
+ return 1;
+ if (insn->type->ctype.modifiers & MOD_VOLATILE)
+ return 1;
+ continue;
+
case OP_STORE:
case OP_CONTEXT:
return 1;
diff --git a/gcc-attr-list.h b/gcc-attr-list.h
index 9aa29800..702b05fa 100644
--- a/gcc-attr-list.h
+++ b/gcc-attr-list.h
@@ -125,6 +125,7 @@ GCC_ATTR(noipa)
GCC_ATTR(nomicromips)
GCC_ATTR(nomips16)
GCC_ATTR(nonnull)
+GCC_ATTR(nonstring)
GCC_ATTR(noplt)
GCC_ATTR(noreturn)
GCC_ATTR(nosave_low_regs)
@@ -199,6 +200,7 @@ GCC_ATTR(vliw)
GCC_ATTR(volatile)
GCC_ATTR(wakeup)
GCC_ATTR(warm)
+GCC_ATTR(warn_if_not_aligned)
GCC_ATTR(warn_unused)
GCC_ATTR(warn_unused_result)
GCC_ATTR(warning)
diff --git a/gdbhelpers b/gdbhelpers
index 86347863..2fe9336d 100644
--- a/gdbhelpers
+++ b/gdbhelpers
@@ -107,6 +107,12 @@ define gdb_show_ctype
if ($arg0->modifiers & MOD_VOLATILE)
printf "MOD_VOLATILE "
end
+ if ($arg0->modifiers & MOD_RESTRICT)
+ printf "MOD_RESTRICT "
+ end
+ if ($arg0->modifiers & MOD_ATOMIC)
+ printf "MOD_ATOMIC "
+ end
if ($arg0->modifiers & MOD_SIGNED)
printf "MOD_SIGNED "
end
@@ -128,9 +134,6 @@ define gdb_show_ctype
if ($arg0->modifiers & MOD_LONGLONGLONG)
printf "MOD_LONGLONGLONG "
end
- if ($arg0->modifiers & MOD_TYPEDEF)
- printf "MOD_TYPEDEF "
- end
if ($arg0->modifiers & MOD_INLINE)
printf "MOD_INLINE "
end
@@ -143,9 +146,6 @@ define gdb_show_ctype
if ($arg0->modifiers & MOD_NODEREF)
printf "MOD_NODEREF "
end
- if ($arg0->modifiers & MOD_ACCESSED)
- printf "MOD_ACCESSED "
- end
if ($arg0->modifiers & MOD_TOPLEVEL)
printf "MOD_TOPLEVEL "
end
diff --git a/graph.c b/graph.c
index 8cbc2202..c9af9a58 100644
--- a/graph.c
+++ b/graph.c
@@ -130,6 +130,8 @@ static void graph_calls(struct entrypoint *ep, int internal)
continue;
FOR_EACH_PTR(bb->insns, insn) {
+ if (!insn->bb)
+ continue;
if (insn->opcode == OP_CALL &&
internal == !(insn->func->sym->ctype.modifiers & MOD_EXTERN)) {
diff --git a/ident-list.h b/ident-list.h
index 13087574..2f1fecb4 100644
--- a/ident-list.h
+++ b/ident-list.h
@@ -37,7 +37,7 @@ IDENT_RESERVED(_Imaginary);
/* C11 keywords */
IDENT(_Alignas);
IDENT_RESERVED(_Alignof);
-IDENT_RESERVED(_Atomic);
+IDENT(_Atomic);
IDENT_RESERVED(_Generic);
IDENT(_Noreturn);
IDENT_RESERVED(_Static_assert);
diff --git a/inline.c b/inline.c
index a3002c6b..012fb379 100644
--- a/inline.c
+++ b/inline.c
@@ -271,6 +271,12 @@ static struct expression * copy_expression(struct expression *expr)
}
break;
}
+ case EXPR_ASM_OPERAND: {
+ expr = dup_expression(expr);
+ expr->constraint = copy_expression(expr->constraint);
+ expr->expr = copy_expression(expr->expr);
+ break;
+ }
default:
warning(expr->pos, "trying to copy expression type %d", expr->type);
}
@@ -281,20 +287,9 @@ static struct expression_list *copy_asm_constraints(struct expression_list *in)
{
struct expression_list *out = NULL;
struct expression *expr;
- int state = 0;
FOR_EACH_PTR(in, expr) {
- switch (state) {
- case 0: /* identifier */
- case 1: /* constraint */
- state++;
- add_expression(&out, expr);
- continue;
- case 2: /* expression */
- state = 0;
- add_expression(&out, copy_expression(expr));
- continue;
- }
+ add_expression(&out, copy_expression(expr));
} END_FOR_EACH_PTR(expr);
return out;
}
diff --git a/lib.c b/lib.c
index 369b21df..037206f7 100644
--- a/lib.c
+++ b/lib.c
@@ -110,6 +110,7 @@ static void do_warn(const char *type, struct position pos, const char * fmt, va_
vsprintf(buffer, fmt, args);
name = stream_name(pos.stream);
+ fflush(stdout);
fprintf(stderr, "%s:%d:%d: %s%s\n",
name, pos.line, pos.pos, type, buffer);
}
@@ -223,6 +224,7 @@ int Waddress_space = 1;
int Wbitwise = 1;
int Wcast_to_as = 0;
int Wcast_truncate = 1;
+int Wconstexpr_not_const = 0;
int Wcontext = 1;
int Wdecl = 1;
int Wdeclarationafterstatement = -1;
@@ -624,6 +626,7 @@ static const struct flag warnings[] = {
{ "bitwise", &Wbitwise },
{ "cast-to-as", &Wcast_to_as },
{ "cast-truncate", &Wcast_truncate },
+ { "constexpr-not-const", &Wconstexpr_not_const},
{ "context", &Wcontext },
{ "decl", &Wdecl },
{ "declaration-after-statement", &Wdeclarationafterstatement },
@@ -1473,6 +1476,20 @@ struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list
*/
protect_token_alloc();
}
+ /*
+ * Evaluate the complete symbol list
+ * Note: This is not needed for normal cases.
+ * These symbols should only be predefined defines and
+ * declaratons which will be evaluated later, when needed.
+ * This is also the case when a file is directly included via
+ * '-include <file>' on the command line *AND* the file only
+ * contains defines, declarations and inline definitions.
+ * However, in the rare cases where the given file should
+ * contain some definitions, these will never be evaluated
+ * and thus won't be able to be linearized correctly.
+ * Hence the evaluate_symbol_list() here under.
+ */
+ evaluate_symbol_list(list);
return list;
}
diff --git a/lib.h b/lib.h
index 8d3c67a0..b0f34265 100644
--- a/lib.h
+++ b/lib.h
@@ -132,6 +132,7 @@ extern int Waddress_space;
extern int Wbitwise;
extern int Wcast_to_as;
extern int Wcast_truncate;
+extern int Wconstexpr_not_const;
extern int Wcontext;
extern int Wdecl;
extern int Wdeclarationafterstatement;
diff --git a/linearize.c b/linearize.c
index 9a92291f..9040d5d9 100644
--- a/linearize.c
+++ b/linearize.c
@@ -1805,12 +1805,10 @@ static void add_asm_output(struct entrypoint *ep, struct instruction *insn, stru
static pseudo_t linearize_asm_statement(struct entrypoint *ep, struct statement *stmt)
{
- int state;
struct expression *expr;
struct instruction *insn;
struct asm_rules *rules;
const char *constraint;
- struct ident *ident;
insn = alloc_instruction(OP_ASM, 0);
expr = stmt->asm_string;
@@ -1824,49 +1822,17 @@ static pseudo_t linearize_asm_statement(struct entrypoint *ep, struct statement
insn->asm_rules = rules;
/* Gather the inputs.. */
- state = 0;
- ident = NULL;
- constraint = NULL;
FOR_EACH_PTR(stmt->asm_inputs, expr) {
- switch (state) {
- case 0: /* Identifier */
- state = 1;
- ident = (struct ident *)expr;
- continue;
-
- case 1: /* Constraint */
- state = 2;
- constraint = expr ? expr->string->data : "";
- continue;
-
- case 2: /* Expression */
- state = 0;
- add_asm_input(ep, insn, expr, constraint, ident);
- }
+ constraint = expr->constraint ? expr->constraint->string->data : "";
+ add_asm_input(ep, insn, expr->expr, constraint, expr->name);
} END_FOR_EACH_PTR(expr);
add_one_insn(ep, insn);
/* Assign the outputs */
- state = 0;
- ident = NULL;
- constraint = NULL;
FOR_EACH_PTR(stmt->asm_outputs, expr) {
- switch (state) {
- case 0: /* Identifier */
- state = 1;
- ident = (struct ident *)expr;
- continue;
-
- case 1: /* Constraint */
- state = 2;
- constraint = expr ? expr->string->data : "";
- continue;
-
- case 2:
- state = 0;
- add_asm_output(ep, insn, expr, constraint, ident);
- }
+ constraint = expr->constraint ? expr->constraint->string->data : "";
+ add_asm_output(ep, insn, expr->expr, constraint, expr->name);
} END_FOR_EACH_PTR(expr);
return VOID;
diff --git a/linearize.h b/linearize.h
index bac82d7f..68efd891 100644
--- a/linearize.h
+++ b/linearize.h
@@ -106,7 +106,7 @@ struct instruction {
pseudo_t base;
unsigned from, len;
};
- struct /* setval */ {
+ struct /* setval and symaddr */ {
pseudo_t symbol; /* Subtle: same offset as "src" !! */
struct expression *val;
};
diff --git a/memops.c b/memops.c
index aeacdf56..1c845a5f 100644
--- a/memops.c
+++ b/memops.c
@@ -158,8 +158,12 @@ static void kill_dominated_stores(struct basic_block *bb)
if (insn->opcode == OP_STORE) {
struct instruction *dom;
pseudo_t pseudo = insn->src;
- int local = local_pseudo(pseudo);
+ int local;
+
+ if (insn->type->ctype.modifiers & MOD_VOLATILE)
+ continue;
+ local = local_pseudo(pseudo);
RECURSE_PTR_REVERSE(insn, dom) {
int dominance;
if (!dom->bb)
diff --git a/parse.c b/parse.c
index 02a55a74..e255345f 100644
--- a/parse.c
+++ b/parse.c
@@ -58,6 +58,8 @@ static declarator_t
typedef_specifier, inline_specifier, auto_specifier,
register_specifier, static_specifier, extern_specifier,
thread_specifier, const_qualifier, volatile_qualifier;
+static declarator_t restrict_qualifier;
+static declarator_t atomic_qualifier;
static struct token *parse_if_statement(struct token *token, struct statement *stmt);
static struct token *parse_return_statement(struct token *token, struct statement *stmt);
@@ -174,6 +176,12 @@ static struct symbol_op volatile_op = {
static struct symbol_op restrict_op = {
.type = KW_QUALIFIER,
+ .declarator = restrict_qualifier,
+};
+
+static struct symbol_op atomic_op = {
+ .type = KW_QUALIFIER,
+ .declarator = atomic_qualifier,
};
static struct symbol_op typeof_op = {
@@ -422,6 +430,10 @@ static struct init_keyword {
{ "volatile", NS_TYPEDEF, .op = &volatile_op },
{ "__volatile", NS_TYPEDEF, .op = &volatile_op },
{ "__volatile__", NS_TYPEDEF, .op = &volatile_op },
+ { "restrict", NS_TYPEDEF, .op = &restrict_op},
+ { "__restrict", NS_TYPEDEF, .op = &restrict_op},
+ { "__restrict__", NS_TYPEDEF, .op = &restrict_op},
+ { "_Atomic", NS_TYPEDEF, .op = &atomic_op},
/* Typedef.. */
{ "typedef", NS_TYPEDEF, .op = &typedef_op },
@@ -467,11 +479,6 @@ static struct init_keyword {
{ "_Alignas", NS_TYPEDEF, .op = &alignas_op },
- /* Ignored for now.. */
- { "restrict", NS_TYPEDEF, .op = &restrict_op},
- { "__restrict", NS_TYPEDEF, .op = &restrict_op},
- { "__restrict__", NS_TYPEDEF, .op = &restrict_op},
-
/* Static assertion */
{ "_Static_assert", NS_KEYWORD, .op = &static_assert_op },
@@ -1377,6 +1384,18 @@ static struct token *volatile_qualifier(struct token *next, struct decl_state *c
return next;
}
+static struct token *restrict_qualifier(struct token *next, struct decl_state *ctx)
+{
+ apply_qualifier(&next->pos, &ctx->ctype, MOD_RESTRICT);
+ return next;
+}
+
+static struct token *atomic_qualifier(struct token *next, struct decl_state *ctx)
+{
+ apply_qualifier(&next->pos, &ctx->ctype, MOD_ATOMIC);
+ return next;
+}
+
static void apply_ctype(struct position pos, struct ctype *thistype, struct ctype *ctype)
{
unsigned long mod = thistype->modifiers;
@@ -1929,24 +1948,20 @@ static struct token *expression_statement(struct token *token, struct expression
static struct token *parse_asm_operands(struct token *token, struct statement *stmt,
struct expression_list **inout)
{
- struct expression *expr;
-
/* Allow empty operands */
if (match_op(token->next, ':') || match_op(token->next, ')'))
return token->next;
do {
- struct ident *ident = NULL;
+ struct expression *op = alloc_expression(token->pos, EXPR_ASM_OPERAND);
if (match_op(token->next, '[') &&
token_type(token->next->next) == TOKEN_IDENT &&
match_op(token->next->next->next, ']')) {
- ident = token->next->next->ident;
+ op->name = token->next->next->ident;
token = token->next->next->next;
}
- add_expression(inout, (struct expression *)ident); /* UGGLEE!!! */
- token = primary_expression(token->next, &expr);
- add_expression(inout, expr);
- token = parens_expression(token, &expr, "in asm parameter");
- add_expression(inout, expr);
+ token = primary_expression(token->next, &op->constraint);
+ token = parens_expression(token, &op->expr, "in asm parameter");
+ add_expression(inout, op);
} while (match_op(token, ','));
return token;
}
@@ -2094,7 +2109,7 @@ static struct statement *start_function(struct symbol *sym)
start_function_scope();
ret = alloc_symbol(sym->pos, SYM_NODE);
ret->ctype = sym->ctype.base_type->ctype;
- ret->ctype.modifiers &= ~(MOD_STORAGE | MOD_CONST | MOD_VOLATILE | MOD_TLS | MOD_INLINE | MOD_ADDRESSABLE | MOD_NOCAST | MOD_NODEREF | MOD_ACCESSED | MOD_TOPLEVEL);
+ ret->ctype.modifiers &= ~(MOD_STORAGE | MOD_QUALIFIER | MOD_TLS | MOD_ACCESS | MOD_NOCAST | MOD_NODEREF);
ret->ctype.modifiers |= (MOD_AUTO | MOD_REGISTER);
bind_symbol(ret, &return_ident, NS_ITERATOR);
stmt->ret = ret;
diff --git a/pre-process.c b/pre-process.c
index 74414dfe..8800dce5 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -296,9 +296,11 @@ static int collect_arguments(struct token *start, struct token *arglist, struct
for (count = 0; count < wanted; count++) {
struct argcount *p = &arglist->next->count;
next = collect_arg(start, p->vararg, &what->pos, p->normal);
- arglist = arglist->next->next;
if (eof_token(next))
goto Eclosing;
+ if (p->vararg && wanted == 1 && eof_token(start->next))
+ break;
+ arglist = arglist->next->next;
args[count].arg = start->next;
args[count].n_normal = p->normal;
args[count].n_quoted = p->quoted;
diff --git a/ptrlist.h b/ptrlist.h
index 78625c8d..4451ee33 100644
--- a/ptrlist.h
+++ b/ptrlist.h
@@ -22,7 +22,7 @@
*/
#define MKTYPE(head,expr) ({ (TYPEOF(head))(expr); })
-#define LIST_NODE_NR (29)
+#define LIST_NODE_NR (13)
struct ptr_list {
int nr:8;
diff --git a/scope.h b/scope.h
index 9bbb6757..d9a14aa3 100644
--- a/scope.h
+++ b/scope.h
@@ -28,7 +28,6 @@
struct symbol;
struct scope {
- struct token *token; /* Scope start information */
struct symbol_list *symbols; /* List of symbols in this scope */
struct scope *next;
};
diff --git a/show-parse.c b/show-parse.c
index d365d737..d60a6dec 100644
--- a/show-parse.c
+++ b/show-parse.c
@@ -125,6 +125,8 @@ const char *modifier_string(unsigned long mod)
{MOD_EXTERN, "extern"},
{MOD_CONST, "const"},
{MOD_VOLATILE, "volatile"},
+ {MOD_RESTRICT, "restrict"},
+ {MOD_ATOMIC, "[atomic]"},
{MOD_SIGNED, "[signed]"},
{MOD_UNSIGNED, "[unsigned]"},
{MOD_CHAR, "[char]"},
@@ -132,13 +134,11 @@ const char *modifier_string(unsigned long mod)
{MOD_LONG, "[long]"},
{MOD_LONGLONG, "[long long]"},
{MOD_LONGLONGLONG, "[long long long]"},
- {MOD_TYPEDEF, "[typedef]"},
{MOD_TLS, "[tls]"},
{MOD_INLINE, "inline"},
{MOD_ADDRESSABLE, "[addressable]"},
{MOD_NOCAST, "[nocast]"},
{MOD_NODEREF, "[noderef]"},
- {MOD_ACCESSED, "[accessed]"},
{MOD_TOPLEVEL, "[toplevel]"},
{MOD_ASSIGNED, "[assigned]"},
{MOD_TYPE, "[type]"},
@@ -927,7 +927,7 @@ static int show_symbol_expr(struct symbol *sym)
return new;
}
if (sym->ctype.modifiers & MOD_ADDRESSABLE) {
- printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new, sym->value);
+ printf("\taddi.%d\t\tv%d,vFP,$%lld\n", bits_in_pointer, new, 0LL);
return new;
}
printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", bits_in_pointer, new, show_ident(sym->ident), sym);
@@ -1169,6 +1169,9 @@ int show_expression(struct expression *expr)
case EXPR_TYPE:
warning(expr->pos, "unable to show type expression");
return 0;
+ case EXPR_ASM_OPERAND:
+ warning(expr->pos, "unable to show asm operand expression");
+ return 0;
}
return 0;
}
diff --git a/simplify.c b/simplify.c
index 2bc86f53..6555da5f 100644
--- a/simplify.c
+++ b/simplify.c
@@ -944,6 +944,10 @@ static int simplify_cast(struct instruction *insn)
if (is_ptr_type(orig_type) || is_ptr_type(insn->type))
return 0;
+ /* Keep float-to-int casts */
+ if (is_float_type(orig_type) && !is_float_type(insn->type))
+ return 0;
+
orig_size = orig_type->bit_size;
size = insn->size;
src = insn->src;
diff --git a/sparse.1 b/sparse.1
index 377d1d3c..5b2bcd9c 100644
--- a/sparse.1
+++ b/sparse.1
@@ -67,8 +67,8 @@ kind of like "NULL" for pointers). So "gfp_t" or the "safe endianness"
types would be __bitwise: you can only operate on them by doing
specific operations that know about *that* particular type.
-Generally, you want bitwise if you are looking for type safety. Sparse
-does not issue these warnings by default.
+Sparse issues these warnings by default. To turn them off, use
+\fB\-Wno\-bitwise\fR.
.
.TP
.B \-Wcast\-to\-as
@@ -86,6 +86,15 @@ Sparse issues these warnings by default. To turn them off, use
\fB\-Wno\-cast\-truncate\fR.
.
.TP
+.B \-Wconstexpr-not-const
+Warn if a non-constant expression is encountered when really expecting a
+constant expression instead.
+Currently, this warns when initializing an object of static storage duration
+with an initializer which is not a constant expression.
+
+Sparse does not issue these warnings by default.
+.
+.TP
.B \-Wcontext
Warn about potential errors in synchronization or other delimited contexts.
diff --git a/sparse.pc.in b/sparse.pc.in
deleted file mode 100644
index f1281c97..00000000
--- a/sparse.pc.in
+++ /dev/null
@@ -1,9 +0,0 @@
-prefix=@prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: Sparse
-Description: Semantic parser for C
-Version: @version@
-Libs: -L${libdir} -lsparse
-Cflags: -I${includedir}
diff --git a/symbol.c b/symbol.c
index 26906ec4..2f4afd51 100644
--- a/symbol.c
+++ b/symbol.c
@@ -48,9 +48,9 @@ struct symbol_list *translation_unit_used_list = NULL;
void access_symbol(struct symbol *sym)
{
if (sym->ctype.modifiers & MOD_INLINE) {
- if (!(sym->ctype.modifiers & MOD_ACCESSED)) {
+ if (!sym->accessed) {
add_symbol(&translation_unit_used_list, sym);
- sym->ctype.modifiers |= MOD_ACCESSED;
+ sym->accessed = 1;
}
}
}
diff --git a/symbol.h b/symbol.h
index 32744961..b0a7205a 100644
--- a/symbol.h
+++ b/symbol.h
@@ -164,7 +164,6 @@ struct symbol {
unsigned long offset;
int bit_size;
unsigned int bit_offset:8,
- arg_count:10,
variadic:1,
initialized:1,
examined:1,
@@ -173,6 +172,7 @@ struct symbol {
string:1,
designated_init:1,
forced_arg:1,
+ accessed:1,
transparent_union:1;
struct expression *array_size;
struct ctype ctype;
@@ -183,7 +183,6 @@ struct symbol {
struct symbol_list *inline_symbol_list;
struct expression *initializer;
struct entrypoint *ep;
- long long value; /* Initial value */
struct symbol *definition;
};
};
@@ -199,55 +198,54 @@ struct symbol {
};
/* Modifiers */
-#define MOD_AUTO 0x0001
-#define MOD_REGISTER 0x0002
-#define MOD_STATIC 0x0004
-#define MOD_EXTERN 0x0008
-
-#define MOD_CONST 0x0010
-#define MOD_VOLATILE 0x0020
-#define MOD_SIGNED 0x0040
-#define MOD_UNSIGNED 0x0080
-
-#define MOD_CHAR 0x0100
-#define MOD_SHORT 0x0200
-#define MOD_LONG 0x0400
-#define MOD_LONGLONG 0x0800
-#define MOD_LONGLONGLONG 0x1000
-#define MOD_PURE 0x2000
-
-#define MOD_TYPEDEF 0x10000
-
-#define MOD_TLS 0x20000
-#define MOD_INLINE 0x40000
-#define MOD_ADDRESSABLE 0x80000
-
-#define MOD_NOCAST 0x100000
-#define MOD_NODEREF 0x200000
-#define MOD_ACCESSED 0x400000
-#define MOD_TOPLEVEL 0x800000 // scoping..
-
-#define MOD_ASSIGNED 0x2000000
-#define MOD_TYPE 0x4000000
-#define MOD_SAFE 0x8000000 // non-null/non-trapping pointer
-
-#define MOD_USERTYPE 0x10000000
-#define MOD_NORETURN 0x20000000
-#define MOD_EXPLICITLY_SIGNED 0x40000000
-#define MOD_BITWISE 0x80000000
-
-
+#define MOD_AUTO 0x00000001
+#define MOD_REGISTER 0x00000002
+#define MOD_STATIC 0x00000004
+#define MOD_EXTERN 0x00000008
+#define MOD_TOPLEVEL 0x00000010 // scoping..
+#define MOD_TLS 0x00000020
+#define MOD_INLINE 0x00000040
+
+#define MOD_ASSIGNED 0x00000080
+#define MOD_ADDRESSABLE 0x00000100
+
+#define MOD_CONST 0x00000200
+#define MOD_VOLATILE 0x00000400
+#define MOD_RESTRICT 0x00000800
+#define MOD_ATOMIC 0x00001000
+
+#define MOD_SIGNED 0x00002000
+#define MOD_UNSIGNED 0x00004000
+#define MOD_EXPLICITLY_SIGNED 0x00008000
+
+#define MOD_TYPE 0x00010000
+#define MOD_USERTYPE 0x00020000
+#define MOD_CHAR 0x00040000
+#define MOD_SHORT 0x00080000
+#define MOD_LONG 0x00100000
+#define MOD_LONGLONG 0x00200000
+#define MOD_LONGLONGLONG 0x00400000
+
+#define MOD_SAFE 0x00800000 // non-null/non-trapping pointer
+#define MOD_PURE 0x01000000
+#define MOD_BITWISE 0x02000000
+#define MOD_NOCAST 0x04000000
+#define MOD_NODEREF 0x08000000
+#define MOD_NORETURN 0x10000000
+
+
+#define MOD_ACCESS (MOD_ASSIGNED | MOD_ADDRESSABLE)
#define MOD_NONLOCAL (MOD_EXTERN | MOD_TOPLEVEL)
#define MOD_STORAGE (MOD_AUTO | MOD_REGISTER | MOD_STATIC | MOD_EXTERN | MOD_INLINE | MOD_TOPLEVEL)
#define MOD_SIGNEDNESS (MOD_SIGNED | MOD_UNSIGNED | MOD_EXPLICITLY_SIGNED)
#define MOD_LONG_ALL (MOD_LONG | MOD_LONGLONG | MOD_LONGLONGLONG)
#define MOD_SPECIFIER (MOD_CHAR | MOD_SHORT | MOD_LONG_ALL | MOD_SIGNEDNESS)
#define MOD_SIZE (MOD_CHAR | MOD_SHORT | MOD_LONG_ALL)
-#define MOD_IGNORE (MOD_TOPLEVEL | MOD_STORAGE | MOD_ADDRESSABLE | \
- MOD_ASSIGNED | MOD_USERTYPE | MOD_ACCESSED | MOD_EXPLICITLY_SIGNED)
-#define MOD_PTRINHERIT (MOD_VOLATILE | MOD_CONST | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST)
+#define MOD_IGNORE (MOD_STORAGE | MOD_ACCESS | MOD_USERTYPE | MOD_EXPLICITLY_SIGNED)
+#define MOD_QUALIFIER (MOD_CONST | MOD_VOLATILE | MOD_RESTRICT | MOD_ATOMIC)
+#define MOD_PTRINHERIT (MOD_QUALIFIER | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST)
/* modifiers preserved by typeof() operator */
-#define MOD_TYPEOF (MOD_VOLATILE | MOD_CONST | MOD_NOCAST | MOD_SPECIFIER)
+#define MOD_TYPEOF (MOD_QUALIFIER | MOD_NOCAST | MOD_SPECIFIER)
/* Current parsing/evaluation function */
@@ -303,7 +301,6 @@ extern void bind_symbol(struct symbol *, struct ident *, enum namespace);
extern struct symbol *examine_symbol_type(struct symbol *);
extern struct symbol *examine_pointer_target(struct symbol *);
-extern void examine_simple_symbol_type(struct symbol *);
extern const char *show_typename(struct symbol *sym);
extern const char *builtin_typename(struct symbol *sym);
extern const char *builtin_ctypename(struct ctype *ctype);
@@ -438,7 +435,6 @@ static inline struct symbol *lookup_keyword(struct ident *ident, enum namespace
#define is_restricted_type(type) (get_sym_type(type) == SYM_RESTRICT)
#define is_fouled_type(type) (get_sym_type(type) == SYM_FOULED)
#define is_bitfield_type(type) (get_sym_type(type) == SYM_BITFIELD)
-extern int is_ptr_type(struct symbol *);
void create_fouled(struct symbol *type);
struct symbol *befoul(struct symbol *type);
diff --git a/tokenize.c b/tokenize.c
index 99b95803..aa4dc184 100644
--- a/tokenize.c
+++ b/tokenize.c
@@ -483,32 +483,20 @@ enum {
Quote = 64,
};
-static const long cclass[257] = {
- ['0' + 1 ... '7' + 1] = Digit | Hex, /* \<octal> */
- ['8' + 1 ... '9' + 1] = Digit | Hex,
+static const char cclass[257] = {
+ ['0' + 1 ... '9' + 1] = Digit | Hex,
['A' + 1 ... 'D' + 1] = Letter | Hex,
['E' + 1] = Letter | Hex | Exp, /* E<exp> */
['F' + 1] = Letter | Hex,
['G' + 1 ... 'O' + 1] = Letter,
['P' + 1] = Letter | Exp, /* P<exp> */
['Q' + 1 ... 'Z' + 1] = Letter,
- ['a' + 1 ... 'b' + 1] = Letter | Hex, /* \a, \b */
- ['c' + 1 ... 'd' + 1] = Letter | Hex,
- ['e' + 1] = Letter | Hex | Exp,/* \e, e<exp> */
- ['f' + 1] = Letter | Hex, /* \f */
- ['g' + 1 ... 'm' + 1] = Letter,
- ['n' + 1] = Letter, /* \n */
- ['o' + 1] = Letter,
+ ['a' + 1 ... 'd' + 1] = Letter | Hex,
+ ['e' + 1] = Letter | Hex | Exp, /* e<exp> */
+ ['f' + 1] = Letter | Hex,
+ ['g' + 1 ... 'o' + 1] = Letter,
['p' + 1] = Letter | Exp, /* p<exp> */
- ['q' + 1] = Letter,
- ['r' + 1] = Letter, /* \r */
- ['s' + 1] = Letter,
- ['t' + 1] = Letter, /* \t */
- ['u' + 1] = Letter,
- ['v' + 1] = Letter, /* \v */
- ['w' + 1] = Letter,
- ['x' + 1] = Letter, /* \x<hex> */
- ['y' + 1 ... 'z' + 1] = Letter,
+ ['q' + 1 ... 'z' + 1] = Letter,
['_' + 1] = Letter,
['.' + 1] = Dot | ValidSecond,
['=' + 1] = ValidSecond,
diff --git a/validation/bad-return-type.c b/validation/bad-return-type.c
new file mode 100644
index 00000000..0f3b3f51
--- /dev/null
+++ b/validation/bad-return-type.c
@@ -0,0 +1,19 @@
+void foo(int a)
+{
+ return a;
+}
+
+int bar(void)
+{
+ return;
+}
+
+/*
+ * check-name: bad return type
+ * check-command: sparse -Wno-decl $file
+ *
+ * check-error-start
+bad-return-type.c:3:16: error: return expression in void function
+bad-return-type.c:8:9: error: return with no return value
+ * check-error-end
+ */
diff --git a/validation/bitfield-size.c b/validation/bitfield-size.c
index ce78ecf2..b027cbd5 100644
--- a/validation/bitfield-size.c
+++ b/validation/bitfield-size.c
@@ -35,7 +35,7 @@ unsigned int get_pbfi_b(struct bfi *bf) { return bf->b; }
* check-command: test-linearize -Wno-decl $file
* check-output-ignore
*
- * check-output-pattern-24-times: cast\\.
- * check-output-pattern-12-times: cast\\.4
- * check-output-pattern-6-times: lsr\\..*\\$6
+ * check-output-pattern(24): cast\\.
+ * check-output-pattern(12): cast\\.4
+ * check-output-pattern(6): lsr\\..*\\$6
*/
diff --git a/validation/c11-atomic.c b/validation/c11-atomic.c
new file mode 100644
index 00000000..bea3dab8
--- /dev/null
+++ b/validation/c11-atomic.c
@@ -0,0 +1,93 @@
+void f00(int _Atomic dst);
+void f01(int _Atomic *dst);
+void f02(int _Atomic *dst);
+void f03(int _Atomic *dst);
+
+int _Atomic qo;
+int uo;
+
+void f00(int dst) { } /* check-should-pass */
+void f01(typeof(&qo) dst) { } /* check-should-pass */
+void f02(int *dst) { } /* check-should-fail */
+void f03(typeof(&uo) dst) { } /* check-should-fail */
+
+void foo(void)
+{
+ qo = uo; /* check-should-pass */
+ uo = qo; /* check-should-pass */
+}
+
+void ref(void)
+{
+ const int qo;
+ int uo;
+ extern const int *pqo;
+ extern int *puo;
+
+ pqo = &qo; /* check-should-pass */
+ pqo = &uo; /* check-should-pass */
+ pqo = puo;
+
+ puo = &uo; /* check-should-pass */
+
+ puo = &qo; /* check-should-fail */
+ puo = pqo; /* check-should-fail */
+}
+
+void bar(void)
+{
+ extern int _Atomic *pqo;
+ extern int *puo;
+
+ pqo = &qo; /* check-should-pass */
+ pqo = &uo; /* check-should-pass */
+ pqo = puo;
+
+ puo = &uo; /* check-should-pass */
+
+ puo = &qo; /* check-should-fail */
+ puo = pqo; /* check-should-fail */
+}
+
+void baz(void)
+{
+ extern typeof(&qo) pqo;
+ extern typeof(&uo) puo;
+
+ pqo = &qo; /* check-should-pass */
+ pqo = &uo; /* check-should-pass */
+ pqo = puo;
+
+ puo = &uo; /* check-should-pass */
+
+ puo = &qo; /* check-should-fail */
+ puo = pqo; /* check-should-fail */
+}
+
+/*
+ * check-name: C11 _Atomic type qualifier
+ * check-command: sparse -Wno-decl $file;
+ *
+ * check-error-start
+c11-atomic.c:11:6: error: symbol 'f02' redeclared with different type (originally declared at c11-atomic.c:3) - incompatible argument 1 (different modifiers)
+c11-atomic.c:12:6: error: symbol 'f03' redeclared with different type (originally declared at c11-atomic.c:4) - incompatible argument 1 (different modifiers)
+c11-atomic.c:33:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:33:13: expected int *extern [assigned] puo
+c11-atomic.c:33:13: got int const *<noident>
+c11-atomic.c:34:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:34:13: expected int *extern [assigned] puo
+c11-atomic.c:34:13: got int const *extern [assigned] pqo
+c11-atomic.c:48:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:48:13: expected int *extern [assigned] puo
+c11-atomic.c:48:13: got int [atomic] *<noident>
+c11-atomic.c:49:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:49:13: expected int *extern [assigned] puo
+c11-atomic.c:49:13: got int [atomic] *extern [assigned] pqo
+c11-atomic.c:63:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:63:13: expected int *extern [assigned] puo
+c11-atomic.c:63:13: got int [atomic] *<noident>
+c11-atomic.c:64:13: warning: incorrect type in assignment (different modifiers)
+c11-atomic.c:64:13: expected int *extern [assigned] puo
+c11-atomic.c:64:13: got int [atomic] *extern [assigned] pqo
+ * check-error-end
+ */
diff --git a/validation/cast-kinds.c b/validation/cast-kinds.c
index 697f9735..e686c01e 100644
--- a/validation/cast-kinds.c
+++ b/validation/cast-kinds.c
@@ -92,7 +92,8 @@ iptr_2_int:
float_2_int:
.L10:
<entry-point>
- ret.32 %arg1
+ cast.32 %r17 <- (32) %arg1
+ ret.32 %r17
double_2_int:
@@ -139,7 +140,8 @@ iptr_2_uint:
float_2_uint:
.L24:
<entry-point>
- ret.32 %arg1
+ cast.32 %r38 <- (32) %arg1
+ ret.32 %r38
double_2_uint:
@@ -193,7 +195,8 @@ float_2_long:
double_2_long:
.L40:
<entry-point>
- ret.64 %arg1
+ cast.64 %r62 <- (64) %arg1
+ ret.64 %r62
int_2_ulong:
@@ -240,7 +243,8 @@ float_2_ulong:
double_2_ulong:
.L54:
<entry-point>
- ret.64 %arg1
+ cast.64 %r83 <- (64) %arg1
+ ret.64 %r83
int_2_vptr:
diff --git a/validation/constexpr-addr-of-static-member.c b/validation/constexpr-addr-of-static-member.c
new file mode 100644
index 00000000..c2a74ac7
--- /dev/null
+++ b/validation/constexpr-addr-of-static-member.c
@@ -0,0 +1,26 @@
+struct A {
+ int a;
+ int b[2];
+};
+
+struct B {
+ int c;
+ struct A d;
+};
+
+static struct B a= {1, {1, {1, 1}}};
+
+static int *b = &a.d.a; // OK
+static int *c = &(&a.d)->a; // OK
+static int *d = a.d.b; // OK
+static int *e = (&a.d)->b; // OK
+static int *f = &a.d.b[1]; // OK
+static int *g = &(&a.d)->b[1]; // OK
+
+/*
+ * check-name: constexpr static object's member address
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+ * check-error-end
+ */
diff --git a/validation/constexpr-addr-of-static.c b/validation/constexpr-addr-of-static.c
new file mode 100644
index 00000000..1af9438c
--- /dev/null
+++ b/validation/constexpr-addr-of-static.c
@@ -0,0 +1,36 @@
+static int a = 1;
+static int b[2] = {1, 1};
+static void c(void) {}
+
+static int *d = &a; // OK
+static int *e = d; // KO
+static int *f = b; // OK
+
+static void (*g)(void) = c; // OK
+static void (*h)(void) = &c; // OK
+
+static int *i = &*&a; // OK
+static int *j = &*b; // OK
+static int *k = &*d; // KO
+
+
+static void l(void) {
+ int a = 1;
+ static int *b = &a; // KO
+}
+
+static void m(void) {
+ static int a = 1;
+ static int *b = &a; // OK
+}
+
+/*
+ * check-name: constexpr static object address
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+constexpr-addr-of-static.c:6:17: warning: non-constant initializer for static object
+constexpr-addr-of-static.c:14:19: warning: non-constant initializer for static object
+constexpr-addr-of-static.c:19:26: warning: non-constant initializer for static object
+ * check-error-end
+ */
diff --git a/validation/constexpr-binop.c b/validation/constexpr-binop.c
new file mode 100644
index 00000000..01261de9
--- /dev/null
+++ b/validation/constexpr-binop.c
@@ -0,0 +1,33 @@
+static int a[] = {
+ [0 + 0] = 0, // OK
+ [0 + 0.] = 0, // KO
+ [(void*)0 + 0] = 0, // KO
+ [0 + __builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [0 + __builtin_choose_expr(0, 0., 0)] = 0, // OK
+ [0 + __builtin_choose_expr(0, 0, 0.)] = 0, // KO
+ [0 < 0] = 0, // OK
+ [0 < 0.] = 0, // KO
+ [0 < __builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [0 < __builtin_choose_expr(0, 0., 0)] = 0, // OK
+ [0 < __builtin_choose_expr(0, 0, 0.)] = 0, // KO
+ [0 && 0] = 0, // OK
+ [0 && 0.] = 0, // KO
+ [0 && __builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [0 && __builtin_choose_expr(0, 0., 0)] = 0, // OK
+ [0 && __builtin_choose_expr(0, 0, 0.)] = 0, // KO
+ [0 + __builtin_types_compatible_p(int, float)] = 0, // OK
+};
+
+/*
+ * check-name: constexprness in binops and alike
+ *
+ * check-error-start
+constexpr-binop.c:3:12: error: bad constant expression
+constexpr-binop.c:4:19: error: bad integer constant expression
+constexpr-binop.c:7:12: error: bad constant expression
+constexpr-binop.c:9:12: error: bad integer constant expression
+constexpr-binop.c:12:12: error: bad integer constant expression
+constexpr-binop.c:14:12: error: bad integer constant expression
+constexpr-binop.c:17:12: error: bad integer constant expression
+ * check-error-end
+ */
diff --git a/validation/constexpr-cast.c b/validation/constexpr-cast.c
new file mode 100644
index 00000000..993c4667
--- /dev/null
+++ b/validation/constexpr-cast.c
@@ -0,0 +1,25 @@
+static int a[] = {
+ [(int)0] = 0, // OK
+ [(int)(int)0] = 0, // OK
+ [(int)0.] = 0, // OK
+ [(int)(int)0.] = 0, // OK
+ [(int)__builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [(int)__builtin_choose_expr(0, 0, 0.)] = 0, // OK
+
+ [(int)(float)0] = 0, // KO
+ [(int)(float)0.] = 0, // KO
+
+ [(int)(void*)0] = 0, // KO
+ [(int)(void*)0.] = 0, // KO
+
+};
+/*
+ * check-name: constexprness in casts
+ *
+ * check-error-start
+constexpr-cast.c:9:11: error: bad integer constant expression
+constexpr-cast.c:10:11: error: bad integer constant expression
+constexpr-cast.c:12:11: error: bad integer constant expression
+constexpr-cast.c:13:11: error: bad integer constant expression
+ * check-error-end
+ */
diff --git a/validation/constexpr-compound-literal.c b/validation/constexpr-compound-literal.c
new file mode 100644
index 00000000..e1378739
--- /dev/null
+++ b/validation/constexpr-compound-literal.c
@@ -0,0 +1,19 @@
+static int *a = &(int){ 1 }; // OK
+static int *b = &(int){ *a }; // KO
+
+static void foo(void)
+{
+ int *b = &(int){ 1 }; // OK
+ int *c = &(int){ *a }; // OK
+ static int *d = &(int){ 1 }; // KO
+}
+
+/*
+ * check-name: constexpr compound literal address
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+constexpr-compound-literal.c:2:25: warning: non-constant initializer for static object
+constexpr-compound-literal.c:8:27: warning: non-constant initializer for static object
+ * check-error-end
+ */
diff --git a/validation/constexpr-conditional.c b/validation/constexpr-conditional.c
new file mode 100644
index 00000000..0f2409bf
--- /dev/null
+++ b/validation/constexpr-conditional.c
@@ -0,0 +1,34 @@
+static int a[] = {
+ [0 ? : 0] = 0, // OK
+ [1 ? : 0] = 0, // OK
+ [0 ? 0 : 0] = 0, // OK
+ [1 ? 0 : 0] = 0, // OK
+ [0 ? 0 : __builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [1 ? __builtin_choose_expr(0, 0, 0) : 0] = 0, // OK
+ [0 ? __builtin_choose_expr(0, 0, 0) : 0] = 0, // OK
+ [1 ? 1 : __builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [__builtin_choose_expr(0, 0, 0) ? : 0] = 0, // OK
+ [__builtin_choose_expr(0, 0, 1) ? : 0] = 0, // OK
+ [0. ? : 0] = 0, // KO
+ [0 ? 0. : 0] = 0, // KO
+ [1 ? : 0.] = 0, // KO
+ [__builtin_choose_expr(0, 0., 0) ? : 0] = 0, // OK
+ [__builtin_choose_expr(0, 0, 0.) ? : 0] = 0, // KO
+ [0 ? __builtin_choose_expr(0, 0., 0) : 0] = 0, // OK
+ [0 ? __builtin_choose_expr(0, 0, 0.) : 0] = 0, // KO
+ [1 ? 0 : __builtin_choose_expr(0, 0., 0)] = 0, // OK
+ [1 ? 0 : __builtin_choose_expr(0, 0, 0.)] = 0, // KO
+};
+
+/*
+ * check-name: constexprness in conditionals
+ *
+ * check-error-start
+constexpr-conditional.c:12:13: error: bad constant expression
+constexpr-conditional.c:13:19: error: bad constant expression
+constexpr-conditional.c:14:12: error: bad constant expression
+constexpr-conditional.c:16:42: error: bad constant expression
+constexpr-conditional.c:18:48: error: bad constant expression
+constexpr-conditional.c:20:14: error: bad constant expression
+ * check-error-end
+ */
diff --git a/validation/constexpr-init.c b/validation/constexpr-init.c
new file mode 100644
index 00000000..c182fe79
--- /dev/null
+++ b/validation/constexpr-init.c
@@ -0,0 +1,60 @@
+static int a = 1; // OK
+static int b[2] = {1, 1}; // OK
+static void c(void) {}
+
+struct A {
+ int a;
+ int b[2];
+};
+
+struct B {
+ int c;
+ struct A d;
+};
+
+static struct B d= {1, {1, {1, 1}}}; // OK
+static struct B e= {a, {1, {1, 1}}}; // KO
+static struct B f= {1, {a, {1, 1}}}; // KO
+static struct B g= {1, {1, {a, 1}}}; // KO
+static struct B h= {1, {1, {1, a}}}; // KO
+static struct B i= {.c = 1, .d = {.a = 1, .b = {1, 1}}}; // OK
+static struct B j= {.c = a, .d = {.a = 1, .b = {1, 1}}}; // KO
+static struct B k= {.c = 1, .d = {.a = a, .b = {1, 1}}}; // KO
+static struct B l= {.c = 1, .d = {.a = 1, .b = {a, 1}}}; // KO
+static struct B m= {.c = 1, .d = {.a = 1, .b = {1, a}}}; // KO
+
+static int n[] = {a, 1}; // KO
+static int o[] = {1, a}; // KO
+static int p[] = {[0] = a, [1] = 1}; // KO
+static int q[] = {[0] = 1, [1] = a}; // KO
+
+static void r(void) {
+ int a = 0;
+ int b = a; // OK
+}
+
+static void s(void) {
+ int a = 1;
+ static int b = a; // KO
+}
+
+/*
+ * check-name: constexprness static storage object initializer
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+constexpr-init.c:16:21: warning: non-constant initializer for static object
+constexpr-init.c:17:25: warning: non-constant initializer for static object
+constexpr-init.c:18:29: warning: non-constant initializer for static object
+constexpr-init.c:19:32: warning: non-constant initializer for static object
+constexpr-init.c:21:26: warning: non-constant initializer for static object
+constexpr-init.c:22:40: warning: non-constant initializer for static object
+constexpr-init.c:23:49: warning: non-constant initializer for static object
+constexpr-init.c:24:52: warning: non-constant initializer for static object
+constexpr-init.c:26:19: warning: non-constant initializer for static object
+constexpr-init.c:27:22: warning: non-constant initializer for static object
+constexpr-init.c:28:25: warning: non-constant initializer for static object
+constexpr-init.c:29:34: warning: non-constant initializer for static object
+constexpr-init.c:38:24: warning: non-constant initializer for static object
+ * check-error-end
+ */
diff --git a/validation/constexpr-labelref.c b/validation/constexpr-labelref.c
new file mode 100644
index 00000000..93dc5ccc
--- /dev/null
+++ b/validation/constexpr-labelref.c
@@ -0,0 +1,14 @@
+static void a(void)
+{
+label1:
+ ;
+ static void *b = &&label1;
+}
+
+/*
+ * check-name: constexprness label reference
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+ * check-error-end
+ */
diff --git a/validation/constexpr-offsetof.c b/validation/constexpr-offsetof.c
new file mode 100644
index 00000000..f55cb563
--- /dev/null
+++ b/validation/constexpr-offsetof.c
@@ -0,0 +1,21 @@
+struct A {
+ int a[1];
+ int b;
+};
+
+extern int c;
+
+static int o[] = {
+ [__builtin_offsetof(struct A, b)] = 0, // OK
+ [__builtin_offsetof(struct A, a[0])] = 0, // OK
+ [__builtin_offsetof(struct A, a[0*0])] = 0, // OK
+ [__builtin_offsetof(struct A, a[c])] = 0 // KO
+};
+
+/*
+ * check-name: constexprness __builtin_offsetof()
+ *
+ * check-error-start
+constexpr-offsetof.c:12:39: error: bad constant expression
+ * check-error-end
+ */
diff --git a/validation/constexpr-pointer-arith.c b/validation/constexpr-pointer-arith.c
new file mode 100644
index 00000000..f27d117a
--- /dev/null
+++ b/validation/constexpr-pointer-arith.c
@@ -0,0 +1,28 @@
+static int a = 1;
+static int b[2] = {1, 1};
+
+static int *c = &b[1]; // OK
+static int *d = (int*)0 + 1; // OK
+static int *e = &b[1] + 1; // OK
+static int *f = b + 1; // OK
+static int *g = d + 1; // KO
+static int *h = &a + 1; // OK
+static int *i = &b[1] + 1; // OK
+static int *j = b + 1; // OK
+static int *k = d + 1; // KO
+static int *l = &*&b[1]; // OK
+static int *m = &*(&a + 1); // OK
+static int *n = &*(&b[1] + 1); // OK
+static int *o = &*(b + 1); // OK
+static int *p = &*(d + 1); // KO
+
+/*
+ * check-name: consrexprness pointer arithmetic
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+constexpr-pointer-arith.c:8:19: warning: non-constant initializer for static object
+constexpr-pointer-arith.c:12:19: warning: non-constant initializer for static object
+constexpr-pointer-arith.c:17:22: warning: non-constant initializer for static object
+ * check-error-end
+ */
diff --git a/validation/constexpr-pointer-cast.c b/validation/constexpr-pointer-cast.c
new file mode 100644
index 00000000..bdf668c1
--- /dev/null
+++ b/validation/constexpr-pointer-cast.c
@@ -0,0 +1,13 @@
+static int *a = (int*)0; // OK
+static int b = 0;
+static int *c = (int*)b; // KO
+
+
+/*
+ * check-name: constexprness integer literal cast to pointer type
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+constexpr-pointer-cast.c:3:18: warning: non-constant initializer for static object
+ * check-error-end
+ */
diff --git a/validation/constexpr-preop.c b/validation/constexpr-preop.c
new file mode 100644
index 00000000..4b54defd
--- /dev/null
+++ b/validation/constexpr-preop.c
@@ -0,0 +1,29 @@
+static int a[] = {
+ [+0] = 0, // OK
+ [+__builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [+0.] = 0, // KO
+ [+__builtin_choose_expr(0, 0, 0.)] = 0, // KO
+ [-0] = 0, // OK
+ [-__builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [-0.] = 0, // KO
+ [-__builtin_choose_expr(0, 0, 0.)] = 0, // KO
+ [~0] = 0, // OK
+ [~__builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [!0] = 0, // OK
+ [!__builtin_choose_expr(0, 0, 0)] = 0, // OK
+ [!0.] = 0, // KO
+ [!__builtin_choose_expr(0, 0, 0.)] = 0, // KO
+};
+
+/*
+ * check-name: constexprness in preops
+ *
+ * check-error-start
+constexpr-preop.c:4:5: error: bad constant expression
+constexpr-preop.c:5:33: error: bad constant expression
+constexpr-preop.c:8:4: error: bad constant expression
+constexpr-preop.c:9:4: error: bad constant expression
+constexpr-preop.c:14:4: error: bad integer constant expression
+constexpr-preop.c:15:4: error: bad integer constant expression
+ * check-error-end
+ */
diff --git a/validation/constexpr-pure-builtin.c b/validation/constexpr-pure-builtin.c
new file mode 100644
index 00000000..f4cd67ed
--- /dev/null
+++ b/validation/constexpr-pure-builtin.c
@@ -0,0 +1,23 @@
+// requires constant integer expressions
+static int bar[] = {
+ [__builtin_bswap16(0x1234)] = 0, // OK
+ [__builtin_bswap32(0x1234)] = 0, // OK
+ [__builtin_bswap64(0x1234)] = 0, // OK
+};
+
+// requires constant integers
+static int foo(unsigned long long a)
+{
+ switch (a) {
+ case __builtin_bswap16(1 << 8):
+ case __builtin_bswap32(2L << 24):
+ case __builtin_bswap64(3LL << 56):
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+/*
+ * check-name: constness of pure/const builtins
+ */
diff --git a/validation/constexpr-string.c b/validation/constexpr-string.c
new file mode 100644
index 00000000..1db101ee
--- /dev/null
+++ b/validation/constexpr-string.c
@@ -0,0 +1,9 @@
+static char *a = "foobar"; // OK
+
+/*
+ * check-name: constness of string literal
+ * check-command: sparse -Wconstexpr-not-const $file
+ *
+ * check-error-start
+ * check-error-end
+ */
diff --git a/validation/constexpr-types-compatible-p.c b/validation/constexpr-types-compatible-p.c
new file mode 100644
index 00000000..1179e9d6
--- /dev/null
+++ b/validation/constexpr-types-compatible-p.c
@@ -0,0 +1,8 @@
+static int a[] = {[__builtin_types_compatible_p(int, int)] = 0};
+
+/*
+ * check-name: constness of __builtin_types_compatible_p()
+ *
+ * check-error-start
+ * check-error-end
+ */
diff --git a/validation/fp2i-cast.c b/validation/fp2i-cast.c
new file mode 100644
index 00000000..08f8c925
--- /dev/null
+++ b/validation/fp2i-cast.c
@@ -0,0 +1,30 @@
+#if __SIZEOF_INT__ == __SIZEOF_FLOAT__
+typedef signed int si;
+typedef unsigned int ui;
+#else
+#error "no float-sized integer type"
+#endif
+
+#if __SIZEOF_LONG_LONG__ == __SIZEOF_DOUBLE__
+typedef signed long long sl;
+typedef unsigned long long ul;
+#else
+#error "no double-sized integer type"
+#endif
+
+si f2si(float a) { return a; }
+ui f2ui(float a) { return a; }
+sl f2sl(float a) { return a; }
+ul f2ul(float a) { return a; }
+si d2si(double a) { return a; }
+ui d2ui(double a) { return a; }
+sl d2sl(double a) { return a; }
+ul d2ul(double a) { return a; }
+
+/*
+ * check-name: fp2i cast
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-pattern-8-times: cast\\.
+ */
diff --git a/validation/include-eval.c b/validation/include-eval.c
new file mode 100644
index 00000000..1a91dab8
--- /dev/null
+++ b/validation/include-eval.c
@@ -0,0 +1,6 @@
+/* nothing */
+
+/*
+ * check-name: include-eval.c
+ * check-command: sparse -include ./include-eval.inc $file
+ */
diff --git a/validation/include-eval.inc b/validation/include-eval.inc
new file mode 100644
index 00000000..e2561ca4
--- /dev/null
+++ b/validation/include-eval.inc
@@ -0,0 +1,12 @@
+typedef unsigned long long_t;
+
+inline
+static unsigned int ok(void)
+{
+ return sizeof(long_t);
+}
+
+static unsigned int ko(void)
+{
+ return sizeof(long_t);
+}
diff --git a/validation/incomplete-struct.c b/validation/incomplete-struct.c
new file mode 100644
index 00000000..f9429f33
--- /dev/null
+++ b/validation/incomplete-struct.c
@@ -0,0 +1,23 @@
+struct s;
+
+void foo(struct s s)
+{
+}
+
+struct s bar(void)
+{
+ struct s s;
+ return s;
+}
+
+/*
+ * check-name: incomplete struct
+ * check-command: sparse -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-error-start
+incomplete-struct.c:3:19: error: parameter 's' has incomplete type
+incomplete-struct.c:7:10: error: return type is incomplete
+incomplete-struct.c:9:11: error: 's' has incompelete type
+ * check-error-end
+ */
diff --git a/validation/kill-load.c b/validation/kill-load.c
index 45fb83e4..563e724c 100644
--- a/validation/kill-load.c
+++ b/validation/kill-load.c
@@ -13,5 +13,5 @@ void ind(volatile int *p,int i) { int v = i++; if (i && 0) p[v]; }
* - bb unreachable.
*
* check-output-ignore
- * check-output-pattern-1-times: load\\.
+ * check-output-pattern(1): load\\.
*/
diff --git a/validation/kill-phi-ttsbb.c b/validation/kill-phi-ttsbb.c
index 178a65d1..7fea30bf 100644
--- a/validation/kill-phi-ttsbb.c
+++ b/validation/kill-phi-ttsbb.c
@@ -1,7 +1,7 @@
int def(void);
void use(int);
-static int foo(int a, int b)
+static void foo(int a, int b)
{
int c;
diff --git a/validation/kill-store.c b/validation/kill-store.c
index 8f725322..204b0367 100644
--- a/validation/kill-store.c
+++ b/validation/kill-store.c
@@ -12,5 +12,5 @@ void dead(int *p, int i) { int v = i++; if (i && 0) p[v] = 0; }
* - bb unreachable.
*
* check-output-ignore
- * check-output-pattern-1-times: store\\.
+ * check-output-pattern(1): store\\.
*/
diff --git a/validation/memops-volatile.c b/validation/memops-volatile.c
index 0f3e12ad..15314e1c 100644
--- a/validation/memops-volatile.c
+++ b/validation/memops-volatile.c
@@ -1,6 +1,7 @@
static int foo(volatile int *a, int v)
{
*a = v;
+ *a = 0;
return *a;
}
@@ -8,14 +9,8 @@ static int foo(volatile int *a, int v)
* check-name: memops-volatile
* check-command: test-linearize $file
*
- * check-output-start
-foo:
-.L0:
- <entry-point>
- store.32 %arg2 -> 0[%arg1]
- load.32 %r5 <- 0[%arg1]
- ret.32 %r5
-
-
- * check-output-end
+ * check-output-ignore
+ * check-output-contains: store\\..*%arg2 -> 0\\[%arg1]
+ * check-output-contains: store\\..*\\$0 -> 0\\[%arg1]
+ * check-output-contains: load\\..*%r.* <- 0\\[%arg1]
*/
diff --git a/validation/optim/bool-context.c b/validation/optim/bool-context.c
index 11326d39..505fa5ce 100644
--- a/validation/optim/bool-context.c
+++ b/validation/optim/bool-context.c
@@ -8,5 +8,5 @@ bool bool_and(int a, int b) { return a && b; }
* check-command: test-linearize -Wno-decl $file
* check-output-ignore
*
- * check-output-pattern-4-times: setne\\..* %arg[12]
+ * check-output-pattern(4): setne\\..* %arg[12]
*/
diff --git a/validation/optim/muldiv-minus-one.c b/validation/optim/muldiv-minus-one.c
index 42b086af..7e2d7bb7 100644
--- a/validation/optim/muldiv-minus-one.c
+++ b/validation/optim/muldiv-minus-one.c
@@ -14,5 +14,5 @@ u32 udivm1(u32 a) { return a / (u32) -1; }
* check-output-excludes: divs\\.
* check-output-contains: neg\\.
* check-output-contains: divu\\.
- * check-output-pattern-3-times: neg\\.
+ * check-output-pattern(3): neg\\.
*/
diff --git a/validation/optim/restrict.c b/validation/optim/restrict.c
new file mode 100644
index 00000000..de6289e2
--- /dev/null
+++ b/validation/optim/restrict.c
@@ -0,0 +1,73 @@
+extern int g, h;
+
+void f00u(int *s)
+{
+ g = *s;
+ h = *s;
+}
+
+void f00r(int *restrict s)
+{
+ g = *s;
+ h = *s;
+}
+
+
+void f01u(int *a, int *b, int *s)
+{
+ *a = *s;
+ *b = *s;
+}
+
+void f01r(int *restrict a, int *restrict b, int *restrict s)
+{
+ *a = *s;
+ *b = *s;
+}
+
+/*
+ * check-name: optim/restrict
+ * check-command: test-linearize -Wno-decl $file
+ * check-known-to-fail
+ *
+ * check-output-start
+f00u:
+.L0:
+ <entry-point>
+ load.32 %r2 <- 0[%arg1]
+ store.32 %r2 -> 0[g]
+ load.32 %r4 <- 0[%arg1]
+ store.32 %r4 -> 0[h]
+ ret
+
+
+f00r:
+.L2:
+ <entry-point>
+ load.32 %r6 <- 0[%arg1]
+ store.32 %r6 -> 0[g]
+ store.32 %r6 -> 0[h]
+ ret
+
+
+f01u:
+.L4:
+ <entry-point>
+ load.32 %r10 <- 0[%arg3]
+ store.32 %r10 -> 0[%arg1]
+ load.32 %r13 <- 0[%arg3]
+ store.32 %r13 -> 0[%arg2]
+ ret
+
+
+f01r:
+.L6:
+ <entry-point>
+ load.32 %r16 <- 0[%arg3]
+ store.32 %r16 -> 0[%arg1]
+ store.32 %r16 -> 0[%arg2]
+ ret
+
+
+ * check-output-end
+ */
diff --git a/validation/optim/volatile-side-effect.c b/validation/optim/volatile-side-effect.c
new file mode 100644
index 00000000..842b7228
--- /dev/null
+++ b/validation/optim/volatile-side-effect.c
@@ -0,0 +1,13 @@
+void foo(int p, volatile int *ptr)
+{
+ p ? : *ptr;
+ p ? : *ptr;
+}
+
+/*
+ * check-name: volatile-side-effect
+ * check-command: test-linearize -Wno-decl $file
+ * check-output-ignore
+ *
+ * check-output-pattern(2): load
+ */
diff --git a/validation/preprocessor/dump-macros-empty.c b/validation/preprocessor/dump-macros-empty.c
index 672c66c7..c9cfe010 100644
--- a/validation/preprocessor/dump-macros-empty.c
+++ b/validation/preprocessor/dump-macros-empty.c
@@ -3,5 +3,5 @@
* check-command: sparse -E -dD empty-file
*
* check-output-ignore
-check-output-pattern-1-times: #define __CHECKER__ 1
+check-output-pattern(1): #define __CHECKER__ 1
*/
diff --git a/validation/preprocessor/dump-macros-multi.c b/validation/preprocessor/dump-macros-multi.c
index 2f6e8d04..c6c334cf 100644
--- a/validation/preprocessor/dump-macros-multi.c
+++ b/validation/preprocessor/dump-macros-multi.c
@@ -3,5 +3,5 @@
* check-command: sparse -E -dD empty-file $file
*
* check-output-ignore
-check-output-pattern-2-times: #define __CHECKER__ 1
+check-output-pattern(2): #define __CHECKER__ 1
*/
diff --git a/validation/preprocessor/dump-macros.c b/validation/preprocessor/dump-macros.c
index 79f3de6a..4dbb9620 100644
--- a/validation/preprocessor/dump-macros.c
+++ b/validation/preprocessor/dump-macros.c
@@ -11,7 +11,7 @@
* check-command: sparse -E -dD -DIJK=ijk -UNDEF -UNYDEF $file
*
* check-output-ignore
-check-output-pattern-1-times: #define __CHECKER__ 1
+check-output-pattern(1): #define __CHECKER__ 1
check-output-contains: #define IJK ijk
check-output-contains: #define DEF xyz
check-output-contains: #define NYDEF ydef
diff --git a/validation/preprocessor/preprocessor23.c b/validation/preprocessor/preprocessor23.c
index 25be5085..a7784838 100644
--- a/validation/preprocessor/preprocessor23.c
+++ b/validation/preprocessor/preprocessor23.c
@@ -12,6 +12,9 @@ I(,)
I(x,)
I(,x)
I(x,x)
+#define J(...) ,##__VA_ARGS__
+J()
+J(x)
/*
* check-name: Preprocessor #23
* check-command: sparse -E $file
@@ -29,6 +32,7 @@ I(x,x)
,x
,x
,xx
+,x
* check-output-end
*
* check-error-start
diff --git a/validation/reload-aliasing.c b/validation/reload-aliasing.c
new file mode 100644
index 00000000..3aad317b
--- /dev/null
+++ b/validation/reload-aliasing.c
@@ -0,0 +1,41 @@
+extern int g, h;
+
+void f00(int *s)
+{
+ g = *s;
+ h = *s;
+}
+
+void f01(int *a, int *b, int *s)
+{
+ *a = *s;
+ *b = *s;
+}
+
+/*
+ * check-name: reload-aliasing.c
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-start
+f00:
+.L0:
+ <entry-point>
+ load.32 %r2 <- 0[%arg1]
+ store.32 %r2 -> 0[g]
+ load.32 %r4 <- 0[%arg1]
+ store.32 %r4 -> 0[h]
+ ret
+
+
+f01:
+.L2:
+ <entry-point>
+ load.32 %r6 <- 0[%arg3]
+ store.32 %r6 -> 0[%arg1]
+ load.32 %r9 <- 0[%arg3]
+ store.32 %r9 -> 0[%arg2]
+ ret
+
+
+ * check-output-end
+ */
diff --git a/validation/restrict.c b/validation/restrict.c
new file mode 100644
index 00000000..f431f6d0
--- /dev/null
+++ b/validation/restrict.c
@@ -0,0 +1,93 @@
+void f00(void *restrict dst);
+void f01(void *restrict *dst);
+void f02(void *restrict *dst);
+void f03(void *restrict *dst);
+
+void *restrict rp;
+void * up;
+
+void f00(void *dst) { } /* check-should-pass */
+void f01(typeof(&rp) dst) { } /* check-should-pass */
+void f02(void **dst) { } /* check-should-fail */
+void f03(typeof(&up) dst) { } /* check-should-fail */
+
+void foo(void)
+{
+ rp = up; /* check-should-pass */
+ up = rp; /* check-should-pass */
+}
+
+void ref(void)
+{
+ void *const qp;
+ void * up;
+ extern void *const *pqp;
+ extern void **pup;
+
+ pqp = &qp; /* check-should-pass */
+ pqp = &up; /* check-should-pass */
+ pqp = pup;
+
+ pup = &up; /* check-should-pass */
+
+ pup = &qp; /* check-should-fail */
+ pup = pqp; /* check-should-fail */
+}
+
+void bar(void)
+{
+ extern void *restrict *prp;
+ extern void **pup;
+
+ prp = &rp; /* check-should-pass */
+ prp = &up; /* check-should-pass */
+ prp = pup;
+
+ pup = &up; /* check-should-pass */
+
+ pup = &rp; /* check-should-fail */
+ pup = prp; /* check-should-fail */
+}
+
+void baz(void)
+{
+ extern typeof(&rp) prp;
+ extern typeof(&up) pup;
+
+ prp = &rp; /* check-should-pass */
+ prp = &up; /* check-should-pass */
+ prp = pup;
+
+ pup = &up; /* check-should-pass */
+
+ pup = &rp; /* check-should-fail */
+ pup = prp; /* check-should-fail */
+}
+
+/*
+ * check-name: restrict qualifier
+ * check-command: sparse -Wno-decl $file;
+ *
+ * check-error-start
+restrict.c:11:6: error: symbol 'f02' redeclared with different type (originally declared at restrict.c:3) - incompatible argument 1 (different modifiers)
+restrict.c:12:6: error: symbol 'f03' redeclared with different type (originally declared at restrict.c:4) - incompatible argument 1 (different modifiers)
+restrict.c:33:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:33:13: expected void **extern [assigned] pup
+restrict.c:33:13: got void *const *<noident>
+restrict.c:34:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:34:13: expected void **extern [assigned] pup
+restrict.c:34:13: got void *const *extern [assigned] pqp
+restrict.c:48:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:48:13: expected void **extern [assigned] pup
+restrict.c:48:13: got void *restrict *<noident>
+restrict.c:49:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:49:13: expected void **extern [assigned] pup
+restrict.c:49:13: got void *restrict *extern [assigned] prp
+restrict.c:63:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:63:13: expected void **extern [assigned] pup
+restrict.c:63:13: got void *restrict *<noident>
+restrict.c:64:13: warning: incorrect type in assignment (different modifiers)
+restrict.c:64:13: expected void **extern [assigned] pup
+restrict.c:64:13: got void *restrict *extern [assigned] prp
+ * check-error-end
+ */
diff --git a/validation/test-be.c b/validation/test-be.c
deleted file mode 100644
index deda3cc1..00000000
--- a/validation/test-be.c
+++ /dev/null
@@ -1,46 +0,0 @@
-int printf(char *c, ...);
-void exit(int c);
-
-#undef PRINT_OUTPUTS
-
-static void test_func_args(int x, int y)
-{
- if (x == y)
- exit(1);
-}
-
-static int binop_s32(int x, int y)
-{
- int a;
-
- a = a + x;
- a = a / y;
- a = a * x;
- a = a - y;
-
- return a;
-}
-
-static void test_binops(void)
-{
- int tmp_s32 = binop_s32(987123, 234);
-
-#ifdef PRINT_OUTPUTS
- printf("binop_s32(987123, 234) == %d\n", tmp_s32);
-#else
- if (tmp_s32 != -1470599007)
- exit(2);
-#endif
-}
-
-int main (int argc, char *argv[])
-{
- test_func_args(1, 2);
- test_binops();
-
- return 0;
-}
-
-/*
- * check-name: binary operations
- */
diff --git a/validation/test-suite b/validation/test-suite
index cf151a36..77536685 100755
--- a/validation/test-suite
+++ b/validation/test-suite
@@ -2,11 +2,18 @@
#set -x
+## allow flags from environment
+flags="$SPARSE_TEST_FLAGS"
+if [ ! -z "$flags" ]; then
+ unset SPARSE_TEST_FLAGS
+ exec "$0" $flags "$@"
+fi
+
cd $(dirname "$0")
default_path=".."
default_cmd="sparse \$file"
-tests_list=`find . -name '*.c' | sed -e 's#^\./\(.*\)#\1#' | sort`
+tests_list=""
prog_name=`basename $0`
if [ ! -x "$default_path/sparse-llvm" ]; then
@@ -31,6 +38,9 @@ known_ko_tests=0
# defaults to not verbose
[ -z "$V" ] && V=0
+vquiet=""
+quiet=0
+abort=0
##
# get_tag_value(file) - get the 'check-<...>' tags & values
@@ -45,7 +55,10 @@ get_tag_value()
check_output_ignore=0
check_output_contains=0
check_output_excludes=0
+ check_output_pattern_obsolete=0
check_output_pattern=0
+ check_arch_ignore=""
+ check_arch_only=""
lines=$(grep 'check-[a-z-]*' $1 | \
sed -e 's/^.*\(check-[a-z-]*:*\) *\(.*\)$/\1 \2/')
@@ -64,7 +77,12 @@ get_tag_value()
check-output-ignore) check_output_ignore=1 ;;
check-output-contains:) check_output_contains=1 ;;
check-output-excludes:) check_output_excludes=1 ;;
- check-output-pattern-) check_output_pattern=1 ;;
+ check-output-pattern-) check_output_pattern_obsolete=1 ;;
+ check-output-pattern) check_output_pattern=1 ;;
+ check-arch-ignore:) arch=$(uname -m)
+ check_arch_ignore="$val" ;;
+ check-arch-only:) arch=$(uname -m)
+ check_arch_only="$val" ;;
esac
done << EOT
$lines
@@ -72,6 +90,23 @@ EOT
}
##
+# verbose(string) - prints string if we are in verbose mode
+verbose()
+{
+ [ "$V" -eq "1" ] && echo " $1"
+ return 0
+}
+
+##
+# error(string[, die]) - prints an error and exits with value die if given
+error()
+{
+ [ "$quiet" -ne 1 ] && echo "error: $1"
+ [ -n "$2" ] && exit $2
+ return 0
+}
+
+##
# helper for has_(each|none)_patterns()
has_patterns()
{
@@ -79,11 +114,14 @@ has_patterns()
patt="$2"
ofile="$3"
cmp="$4"
+ msg="$5"
grep "$patt:" "$ifile" | \
sed -e "s/^.*$patt: *\(.*\)$/\1/" | \
while read val; do
grep -s -q "$val" "$ofile"
if [ "$?" $cmp 0 ]; then
+ error "test '$ifile' failed"
+ error " Pattern '$val' unexpectedly $msg"
return 1
fi
done
@@ -98,7 +136,7 @@ has_patterns()
# returns 0 if all present, 1 otherwise
has_each_patterns()
{
- has_patterns "$1" "$2" "$3" -ne
+ has_patterns "$1" "$2" "$4" -ne "$3"
}
##
@@ -108,7 +146,7 @@ has_each_patterns()
# returns 1 if any present, 0 otherwise
has_none_patterns()
{
- has_patterns "$1" "$2" "$3" -eq
+ has_patterns "$1" "$2" "$4" -eq "$3"
}
##
@@ -125,6 +163,8 @@ nbr_patterns()
while read nbr pat; do
n=$(grep -s "$pat" "$ofile" | wc -l)
if [ "$n" -ne "$nbr" ]; then
+ error "test '$ifile' failed"
+ error " Pattern '$pat' expected $nbr times but got $n times"
return 1
fi
done
@@ -133,33 +173,87 @@ nbr_patterns()
}
##
-# verbose(string) - prints string if we are in verbose mode
-verbose()
+# minmax_patterns(ifile tag ofile) - does ofile contains the
+# the patterns given by ifile's tags
+# the right number of time?
+minmax_patterns()
{
- [ "$V" -eq "1" ] && echo " $1"
- return 0
+ ifile="$1"
+ patt="$2"
+ ofile="$3"
+ grep "$patt([0-9-]*\(, *\)*[0-9-]*):" "$ifile" | \
+ sed -e "s/^.*$patt(\([0-9]*\)): *\(.*\)/\1 eq \2/" \
+ -e "s/^.*$patt(\([0-9-]*\), *\([0-9-]*\)): *\(.*\)/\1 \2 \3/" | \
+ while read min max pat; do
+ n=$(grep -s "$pat" "$ofile" | wc -l)
+ if [ "$max" = "eq" ]; then
+ if [ "$n" -ne "$min" ]; then
+ error "test '$ifile' failed"
+ error " Pattern '$pat' expected $min times but got $n times"
+ return 1
+ fi
+ continue
+ fi
+ if [ "$min" != '-' ]; then
+ if [ "$n" -lt "$min" ]; then
+ error "test '$ifile' failed"
+ error " Pattern '$pat' expected min $min times but got $n times"
+ return 1
+ fi
+ fi
+ if [ "$max" != '-' ]; then
+ if [ "$n" -gt "$max" ]; then
+ error "test '$ifile' failed"
+ error " Pattern '$pat' expected max $max times but got $n times"
+ return 1
+ fi
+ fi
+ done
+
+ return $?
}
##
-# error(string[, die]) - prints an error and exits with value die if given
-error()
+# arg_file(filename) - checks if filename exists
+arg_file()
{
- [ "$quiet" -ne 1 ] && echo "error: $1"
- [ -n "$2" ] && exit $2
+ [ -z "$1" ] && {
+ do_usage
+ exit 1
+ }
+ [ -e "$1" ] || {
+ error "Can't open file $1"
+ exit 1
+ }
return 0
}
+
+##
do_usage()
{
echo "$prog_name - a tiny automatic testing script"
-echo "Usage: $prog_name [command] [command arguments]"
+echo "Usage: $prog_name [option(s)] [command] [arguments]"
+echo
+echo "options:"
+echo " -a|--abort abort the tests as soon as one fails"
+echo " -q|--quiet be extra quiet while running the tests"
echo
echo "commands:"
echo " none runs the whole test suite"
+echo " file ... runs the test suite on the given file(s)"
echo " single file runs the test in 'file'"
echo " format file [name [cmd]] helps writing a new test case using cmd"
echo
-echo " help prints usage"
+echo " [command] help prints usage"
+}
+
+disable()
+{
+ disabled_tests=$(($disabled_tests + 1))
+ if [ -z "$vquiet" ]; then
+ echo " SKIP $1 ($2)"
+ fi
}
##
@@ -198,15 +292,28 @@ do_test()
base_cmd=$1
for i in $disabled_cmds; do
if [ "$i" = "$base_cmd" ] ; then
- disabled_tests=$(($disabled_tests + 1))
- echo " DISABLE $test_name ($file)"
+ disable "$test_name" "$file"
return 3
fi
done
+ if [ "$check_arch_ignore" != "" ]; then
+ if echo $arch | egrep -q -w "$check_arch_ignore"; then
+ disable "$test_name" "$file"
+ return 3
+ fi
+ fi
+ if [ "$check_arch_only" != "" ]; then
+ if ! (echo $arch | egrep -q -w "$check_arch_only"); then
+ disable "$test_name" "$file"
+ return 3
+ fi
+ fi
cmd=`eval echo $default_path/$check_command`
- echo " TEST $test_name ($file)"
+ if [ -z "$vquiet" ]; then
+ echo " TEST $test_name ($file)"
+ fi
verbose "Using command : $cmd"
@@ -228,7 +335,7 @@ do_test()
[ $must_fail -eq 1 ] && [ $V -eq 0 ] && quiet=1
known_ko_tests=$(($known_ko_tests + $must_fail))
- for stream in output error; do
+ for stream in error output; do
eval ignore=\$check_${stream}_ignore
[ $ignore -eq 1 ] && continue
@@ -253,39 +360,47 @@ do_test()
# verify the 'check-output-contains/excludes' tags
if [ $check_output_contains -eq 1 ]; then
- has_each_patterns "$file" 'check-output-contains' $file.output.got
+ has_each_patterns "$file" 'check-output-contains' absent $file.output.got
if [ "$?" -ne "0" ]; then
- error "Actual output doesn't contain some of the expected patterns."
test_failed=1
fi
fi
if [ $check_output_excludes -eq 1 ]; then
- has_none_patterns "$file" 'check-output-excludes' $file.output.got
+ has_none_patterns "$file" 'check-output-excludes' present $file.output.got
if [ "$?" -ne "0" ]; then
- error "Actual output contains some patterns which are not expected."
test_failed=1
fi
fi
- if [ $check_output_pattern -eq 1 ]; then
+ if [ $check_output_pattern_obsolete -eq 1 ]; then
# verify the 'check-output-pattern-X-times' tags
nbr_patterns "$file" 'check-output-pattern' $file.output.got
if [ "$?" -ne "0" ]; then
- error "Actual output doesn't contain the pattern the expected number."
test_failed=1
fi
fi
-
- [ "$test_failed" -eq "$must_fail" ] || failed=1
+ if [ $check_output_pattern -eq 1 ]; then
+ # verify the 'check-output-pattern(...)' tags
+ minmax_patterns "$file" 'check-output-pattern' $file.output.got
+ if [ "$?" -ne "0" ]; then
+ test_failed=1
+ fi
+ fi
if [ "$must_fail" -eq "1" ]; then
if [ "$test_failed" -eq "1" ]; then
+ [ -z "$vquiet" ] && \
echo "info: test '$file' is known to fail"
else
echo "error: test '$file' is known to fail but succeed!"
- test_failed=1
fi
fi
+ if [ "$test_failed" -ne "$must_fail" ]; then
+ [ $abort -eq 1 ] && exit 1
+ test_failed=1
+ failed=1
+ fi
+
if [ "$test_failed" -eq "1" ]; then
ko_tests=$(($ko_tests + 1))
else
@@ -301,37 +416,75 @@ do_test_suite()
do_test "$i"
done
+ OK=OK
+ [ $failed -eq 0 ] || OK=KO
+
# prints some numbers
tests_nr=$(($ok_tests + $ko_tests))
- echo -n "Out of $tests_nr tests, $ok_tests passed, $ko_tests failed"
- echo " ($known_ko_tests of them are known to fail)"
+ echo "$OK: out of $tests_nr tests, $ok_tests passed, $ko_tests failed"
+ if [ "$known_ko_tests" -ne 0 ]; then
+ echo " $known_ko_tests of them are known to fail"
+ fi
if [ "$unhandled_tests" -ne "0" ]; then
- echo "$unhandled_tests tests could not be handled by $prog_name"
+ echo " $unhandled_tests tests could not be handled by $prog_name"
fi
if [ "$disabled_tests" -ne "0" ]; then
- echo "$disabled_tests tests were disabled"
+ echo " $disabled_tests tests were disabled"
fi
}
##
-# do_format(file[, name[, cmd]]) - helps a test writer to format test-suite tags
+do_format_help() {
+echo "Usage: $prog_name [option(s)] [--]format file [name [cmd]]"
+echo
+echo "options:"
+echo " -f write a test known to fail"
+echo " -l write a test for linearized code"
+echo
+echo "argument(s):"
+echo " file file containing the test case(s)"
+echo " name name for the test case (defaults to file)"
+echo " cmd command to be used (defaults to 'sparse \$file')"
+}
+
+##
+# do_format([options,] file[, name[, cmd]]) - helps a test writer to format test-suite tags
do_format()
{
- if [ -z "$2" ]; then
- fname="$1"
- fcmd=$default_cmd
- elif [ -z "$3" ]; then
- fname="$2"
- fcmd=$default_cmd
- else
- fname="$2"
- fcmd="$3"
- fi
+ def_cmd="$default_cmd"
+ linear=0
+ fail=0
+
+ while [ $# -gt 1 ] ; do
+ case "$1" in
+ -f)
+ fail=1 ;;
+ -l)
+ def_cmd='test-linearize -Wno-decl $file'
+ linear=1 ;;
+ help|-*)
+ do_format_help
+ return 0
+ ;;
+ *) break ;;
+ esac
+ shift
+ continue
+ done
+
+ arg_file "$1" || return 1
+
file="$1"
+ fname="$2"
+ [ -z "$fname" ] && fname="$(basename "$1" .c)"
+ fcmd="$3"
+ [ -z "$fcmd" ] && fcmd="$def_cmd"
+
cmd=`eval echo $default_path/$fcmd`
$cmd 1> $file.output.got 2> $file.error.got
fexit_value=$?
cat <<_EOF
+
/*
* check-name: $fname
_EOF
@@ -341,6 +494,15 @@ _EOF
if [ "$fexit_value" -ne "0" ]; then
echo " * check-exit-value: $fexit_value"
fi
+ if [ $fail != 0 ]; then
+ echo " * check-known-to-fail"
+ fi
+ if [ $linear != 0 ]; then
+ echo " *"
+ echo " * check-output-ignore"
+ echo " * check-output-contains: xyz\\\\."
+ echo " * check-output-excludes: \\\\."
+ fi
for stream in output error; do
if [ -s "$file.$stream.got" ]; then
echo " *"
@@ -353,26 +515,29 @@ _EOF
return 0
}
-##
-# arg_file(filename) - checks if filename exists
-arg_file()
-{
- [ -z "$1" ] && {
- do_usage
- exit 1
- }
- [ -e "$1" ] || {
- error "Can't open file $1"
- exit 1
- }
- return 0
-}
+while true; do
+ case "$1" in
+ -a|--abort)
+ abort=1
+ shift
+ continue
+ ;;
+ -q|--quiet)
+ vquiet=1
+ shift
+ continue
+ ;;
-case "$1" in
'')
+ tests_list=`find . -name '*.c' | sed -e 's#^\./\(.*\)#\1#' | sort`
do_test_suite
;;
- single)
+ *.c)
+ tests_list="$@"
+ do_test_suite
+ ;;
+
+ single|--single)
arg_file "$2"
do_test "$2"
case "$?" in
@@ -381,15 +546,17 @@ case "$1" in
2) echo "$2 can't be handled by $prog_name";;
esac
;;
- format)
- arg_file "$2"
- do_format "$2" "$3" "$4"
+ format|--format)
+ shift
+ do_format "$@"
;;
help | *)
do_usage
exit 1
;;
-esac
+ esac
+ break
+done
exit $failed
diff --git a/validation/testsuite-selfcheck1.c b/validation/testsuite-selfcheck1.c
deleted file mode 100644
index d927f996..00000000
--- a/validation/testsuite-selfcheck1.c
+++ /dev/null
@@ -1,10 +0,0 @@
-good
-
-/*
- * check-name: selfcheck1
- * check-command: sparse -E $file
- * check-output-ignore
- *
- * check-output-contains: good
- * check-output-excludes: evil
- */
diff --git a/validation/testsuite-selfcheck2.c b/validation/testsuite-selfcheck2.c
deleted file mode 100644
index 5309e32f..00000000
--- a/validation/testsuite-selfcheck2.c
+++ /dev/null
@@ -1,10 +0,0 @@
-evil
-
-/*
- * check-name: selfcheck2
- * check-command: sparse -E $file
- * check-output-ignore
- * check-known-to-fail
- *
- * check-output-contains: good
- */
diff --git a/validation/testsuite-selfcheck3.c b/validation/testsuite-selfcheck3.c
deleted file mode 100644
index 6d834e68..00000000
--- a/validation/testsuite-selfcheck3.c
+++ /dev/null
@@ -1,10 +0,0 @@
-evil
-
-/*
- * check-name: selfcheck3
- * check-command: sparse -E $file
- * check-output-ignore
- * check-known-to-fail
- *
- * check-output-excludes: evil
- */
diff --git a/validation/typeof-mods.c b/validation/typeof-mods.c
index 9822e96f..aa880f37 100644
--- a/validation/typeof-mods.c
+++ b/validation/typeof-mods.c
@@ -43,6 +43,34 @@ static void test_volatile(void)
obj = *ptr;
}
+static void test_restrict(void)
+{
+ int *restrict obj, *restrict *ptr;
+ typeof(obj) var = obj;
+ typeof(ptr) ptr2 = ptr;
+ typeof(*ptr) var2 = obj;
+ typeof(*ptr) *ptr3 = ptr;
+ typeof(obj) *ptr4 = ptr;
+ obj = obj;
+ ptr = ptr;
+ ptr = &obj;
+ obj = *ptr;
+}
+
+static void test_atomic(void)
+{
+ int _Atomic obj, *ptr;
+ typeof(obj) var = obj;
+ typeof(ptr) ptr2 = ptr;
+ typeof(*ptr) var2 = obj;
+ typeof(*ptr) *ptr3 = ptr;
+ typeof(obj) *ptr4 = ptr;
+ obj = obj;
+ ptr = ptr;
+ ptr = &obj;
+ obj = *ptr;
+}
+
static void test_bitwise(void)
{
typedef int __bitwise type_t;