|
| 1 | +// Verify that all 12 KEYCONTRACT keywords are lexed correctly. |
| 2 | +// |
| 3 | +// With -fverify-contracts: each name lexes as a keyword token. |
| 4 | +// Without -fverify-contracts: each name lexes as an identifier (no conflict |
| 5 | +// with existing C++ code). |
| 6 | + |
| 7 | +// --- dump-tokens: WITH flag — expect keyword tokens --- |
| 8 | +// RUN: %clang_cc1 -std=c++20 -fverify-contracts -dump-tokens %s 2>&1 \ |
| 9 | +// RUN: | FileCheck %s --check-prefix=KW |
| 10 | + |
| 11 | +// --- dump-tokens: WITHOUT flag — expect identifier tokens --- |
| 12 | +// RUN: %clang_cc1 -std=c++20 -dump-tokens %s 2>&1 \ |
| 13 | +// RUN: | FileCheck %s --check-prefix=ID |
| 14 | + |
| 15 | +// --- __is_identifier: WITH flag (-DWITH_FLAG selects the right assertions) --- |
| 16 | +// RUN: %clang_cc1 -std=c++20 -fverify-contracts -DWITH_FLAG -fsyntax-only %s |
| 17 | + |
| 18 | +// --- __is_identifier: WITHOUT flag --- |
| 19 | +// RUN: %clang_cc1 -std=c++20 -fsyntax-only %s |
| 20 | + |
| 21 | +// ========================================================================== |
| 22 | +// Section 1: FileCheck patterns for dump-tokens runs |
| 23 | +// |
| 24 | +// dump-tokens is lex-only; syntax does not matter. The tokens that satisfy |
| 25 | +// these checks come from the variable declarations in Section 3, which are |
| 26 | +// compiled by every dump-tokens run (neither run defines WITH_FLAG). |
| 27 | +// |
| 28 | +// KW-DAG checks that each name appears as a keyword token. |
| 29 | +// ID-DAG checks that each name appears as an identifier token. |
| 30 | +// ========================================================================== |
| 31 | + |
| 32 | +// KW-DAG: pre 'pre' |
| 33 | +// KW-DAG: post 'post' |
| 34 | +// KW-DAG: invariant 'invariant' |
| 35 | +// KW-DAG: decreases 'decreases' |
| 36 | +// KW-DAG: ghost 'ghost' |
| 37 | +// KW-DAG: spec 'spec' |
| 38 | +// KW-DAG: proof 'proof' |
| 39 | +// KW-DAG: contract_assert 'contract_assert' |
| 40 | +// KW-DAG: forall 'forall' |
| 41 | +// KW-DAG: exists 'exists' |
| 42 | +// KW-DAG: old 'old' |
| 43 | +// KW-DAG: result 'result' |
| 44 | + |
| 45 | +// ID-DAG: identifier 'pre' |
| 46 | +// ID-DAG: identifier 'post' |
| 47 | +// ID-DAG: identifier 'invariant' |
| 48 | +// ID-DAG: identifier 'decreases' |
| 49 | +// ID-DAG: identifier 'ghost' |
| 50 | +// ID-DAG: identifier 'spec' |
| 51 | +// ID-DAG: identifier 'proof' |
| 52 | +// ID-DAG: identifier 'contract_assert' |
| 53 | +// ID-DAG: identifier 'forall' |
| 54 | +// ID-DAG: identifier 'exists' |
| 55 | +// ID-DAG: identifier 'old' |
| 56 | +// ID-DAG: identifier 'result' |
| 57 | + |
| 58 | +// ========================================================================== |
| 59 | +// Section 2: __is_identifier() static assertions |
| 60 | +// |
| 61 | +// __is_identifier(X) is a preprocessor built-in: it expands to 0 or 1 |
| 62 | +// *before* the C++ parser runs, so the parser never sees the keyword token |
| 63 | +// inside the parens. The result is a pure integer literal. |
| 64 | +// |
| 65 | +// WITH_FLAG → -fverify-contracts active → all 12 are keywords → expect 0 |
| 66 | +// !WITH_FLAG → flag absent → all 12 are identifiers → expect 1 |
| 67 | +// ========================================================================== |
| 68 | + |
| 69 | +#ifdef WITH_FLAG |
| 70 | +static_assert(!__is_identifier(pre), "pre must be a keyword with -fverify-contracts"); |
| 71 | +static_assert(!__is_identifier(post), "post must be a keyword with -fverify-contracts"); |
| 72 | +static_assert(!__is_identifier(invariant), "invariant must be a keyword with -fverify-contracts"); |
| 73 | +static_assert(!__is_identifier(decreases), "decreases must be a keyword with -fverify-contracts"); |
| 74 | +static_assert(!__is_identifier(ghost), "ghost must be a keyword with -fverify-contracts"); |
| 75 | +static_assert(!__is_identifier(spec), "spec must be a keyword with -fverify-contracts"); |
| 76 | +static_assert(!__is_identifier(proof), "proof must be a keyword with -fverify-contracts"); |
| 77 | +static_assert(!__is_identifier(contract_assert), "contract_assert must be a keyword with -fverify-contracts"); |
| 78 | +static_assert(!__is_identifier(forall), "forall must be a keyword with -fverify-contracts"); |
| 79 | +static_assert(!__is_identifier(exists), "exists must be a keyword with -fverify-contracts"); |
| 80 | +static_assert(!__is_identifier(old), "old must be a keyword with -fverify-contracts"); |
| 81 | +static_assert(!__is_identifier(result), "result must be a keyword with -fverify-contracts"); |
| 82 | +#else |
| 83 | +// ========================================================================== |
| 84 | +// Section 3: identifier-mode checks + token source for dump-tokens runs |
| 85 | +// |
| 86 | +// This block is compiled by: |
| 87 | +// - the two dump-tokens runs (no WITH_FLAG defined) |
| 88 | +// - the fsyntax-only run WITHOUT -fverify-contracts |
| 89 | +// |
| 90 | +// The variable declarations give dump-tokens the tokens to match against. |
| 91 | +// The static_assert lines verify backward compatibility. |
| 92 | +// ========================================================================== |
| 93 | + |
| 94 | +// Backward compatibility: all names remain valid C++ identifiers. |
| 95 | +static_assert(__is_identifier(pre), "pre must be an identifier without -fverify-contracts"); |
| 96 | +static_assert(__is_identifier(post), "post must be an identifier without -fverify-contracts"); |
| 97 | +static_assert(__is_identifier(invariant), "invariant must be an identifier without -fverify-contracts"); |
| 98 | +static_assert(__is_identifier(decreases), "decreases must be an identifier without -fverify-contracts"); |
| 99 | +static_assert(__is_identifier(ghost), "ghost must be an identifier without -fverify-contracts"); |
| 100 | +static_assert(__is_identifier(spec), "spec must be an identifier without -fverify-contracts"); |
| 101 | +static_assert(__is_identifier(proof), "proof must be an identifier without -fverify-contracts"); |
| 102 | +static_assert(__is_identifier(contract_assert), "contract_assert must be an identifier without -fverify-contracts"); |
| 103 | +static_assert(__is_identifier(forall), "forall must be an identifier without -fverify-contracts"); |
| 104 | +static_assert(__is_identifier(exists), "exists must be an identifier without -fverify-contracts"); |
| 105 | +static_assert(__is_identifier(old), "old must be an identifier without -fverify-contracts"); |
| 106 | +static_assert(__is_identifier(result), "result must be an identifier without -fverify-contracts"); |
| 107 | + |
| 108 | +// Declarations whose names produce the keyword/identifier tokens that the |
| 109 | +// dump-tokens FileCheck patterns match against. With -fverify-contracts each |
| 110 | +// name lexes as its keyword token; without it, as an identifier token. |
| 111 | +// (dump-tokens is lex-only so no parse error occurs in either case.) |
| 112 | +int pre, post, invariant, decreases, ghost, spec, proof; |
| 113 | +int contract_assert, forall, exists, old, result; |
| 114 | +#endif |
0 commit comments