diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a7a5a9cf..e43fa6c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,12 @@ jobs: with: ignore_words_file: spelling.ignore.txt skip: alectryon + clang-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build and test C library with clang (-Wall -Werror) + run: CC=clang CFLAGS="-Wimplicit-fallthrough -Wconditional-uninitialized" make -C C -j$(nproc) check doCheck=1 build: strategy: fail-fast: false diff --git a/C/dag.c b/C/dag.c index d09cd274..f26b647e 100644 --- a/C/dag.c +++ b/C/dag.c @@ -116,6 +116,7 @@ sha256_midstate simplicity_computeWordCMR(const bitstring* value, size_t n) { case 0: i = getBit(value, 0); break; case 1: i = 2 + ((1U * getBit(value, 0) << 1) | getBit(value, 1)); break; case 2: i = 6 + ((1U * getBit(value, 0) << 3) | (1U * getBit(value, 1) << 2) | (1U * getBit(value, 2) << 1) | getBit(value, 3)); break; + default: SIMPLICITY_UNREACHABLE; } memcpy(stack_ptr, &word_cmr[i], sizeof(uint32_t[8])); } else { @@ -174,7 +175,7 @@ void simplicity_computeCommitmentMerkleRoot(dag_node* dag, const uint_fast32_t i case PAIR: memcpy(block + j, dag[dag[i].child[1]].cmr.s, sizeof(uint32_t[8])); j = 0; - /*@fallthrough@*/ + SIMPLICITY_FALLTHROUGH; case DISCONNECT: /* Only the first child is used in the CMR. */ case INJL: case INJR: @@ -182,6 +183,7 @@ void simplicity_computeCommitmentMerkleRoot(dag_node* dag, const uint_fast32_t i case DROP: memcpy(block + j, dag[dag[i].child[0]].cmr.s, sizeof(uint32_t[8])); simplicity_sha256_compression(dag[i].cmr.s, block); + SIMPLICITY_FALLTHROUGH; case IDEN: case UNIT: case WITNESS: @@ -224,13 +226,14 @@ static void computeIdentityHashRoots(sha256_midstate* ihr, const dag_node* dag, case DISCONNECT: memcpy(block + j, ihr[dag[i].child[1]].s, sizeof(uint32_t[8])); j = 0; - /*@fallthrough@*/ + SIMPLICITY_FALLTHROUGH; case INJL: case INJR: case TAKE: case DROP: memcpy(block + j, ihr[dag[i].child[0]].s, sizeof(uint32_t[8])); simplicity_sha256_compression(ihr[i].s, block); + SIMPLICITY_FALLTHROUGH; case IDEN: case UNIT: case HIDDEN: @@ -420,6 +423,7 @@ simplicity_err simplicity_verifyCanonicalOrder(dag_node* dag, const uint_fast32_ continue; } if (bottom == child) bottom++; + SIMPLICITY_FALLTHROUGH; case IDEN: case UNIT: case WITNESS: @@ -444,6 +448,7 @@ simplicity_err simplicity_verifyCanonicalOrder(dag_node* dag, const uint_fast32_ continue; } if (bottom == child) bottom++; + SIMPLICITY_FALLTHROUGH; case INJL: case INJR: case TAKE: diff --git a/C/eval.c b/C/eval.c index 6c9e9dc0..706e09b4 100644 --- a/C/eval.c +++ b/C/eval.c @@ -462,7 +462,7 @@ static simplicity_err runTCO(evalState state, call* stack, const dag_node* dag, skip(state.activeWriteFrame, pad( INJR == dag[pc].tag , type_dag[INJ_B(dag, type_dag, pc)].bitSize , type_dag[INJ_C(dag, type_dag, pc)].bitSize)); - /*@fallthrough@*/ + SIMPLICITY_FALLTHROUGH; case TAKE: simplicity_debug_assert(calling); /* TAIL_CALL(dag[pc].child[0], SAME_TCO); */ @@ -496,7 +496,7 @@ static simplicity_err runTCO(evalState state, call* stack, const dag_node* dag, } else { writeValue(state.activeWriteFrame, &dag[pc].compactValue, dag[pc].targetType, type_dag); } - /*@fallthrough@*/ + SIMPLICITY_FALLTHROUGH; case UNIT: simplicity_debug_assert(calling); if (get_tco_flag(&stack[pc])) { diff --git a/C/simplicity_assert.h b/C/simplicity_assert.h index a321c938..e74b41f7 100644 --- a/C/simplicity_assert.h +++ b/C/simplicity_assert.h @@ -34,4 +34,18 @@ # define SIMPLICITY_UNREACHABLE assert(NULL == "SIMPLICITY_UNCREACHABLE was reached") #endif +/* Defines a FALLTHROUGH macro to annotate intentional switch fallthroughs, silencing -Wimplicit-fallthrough + * warnings on compilers that support the 'fallthrough' attribute. + * No-op on compilers (e.g. MSVC) that don't support it. + */ +#if defined(__has_attribute) +# if __has_attribute(fallthrough) +# define SIMPLICITY_FALLTHROUGH __attribute__((fallthrough)) +# endif +#endif + +#ifndef SIMPLICITY_FALLTHROUGH +# define SIMPLICITY_FALLTHROUGH ((void)0) +#endif + #endif /* SIMPLICITY_SIMPLICITY_ASSERT_H */