Avoid defining static const members in headers

Defining a static const member in a header breaks ODR, as the object will be
defined in every translation unit that includes the header.

Instead, the members should either be declared `inline` (which is
implicitly the case for `constexpr` members) or initialized in a cpp.
Alternatively, using an anonymous enum allows the definition to remain
inside the header meaning that the compiler can still choose to inline
values.
This commit is contained in:
Nathan Burles 2020-06-12 14:50:24 +01:00
parent 0b35a76e9b
commit a1d2d47da8
16 changed files with 157 additions and 33 deletions

View File

@ -182,6 +182,7 @@
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -201,6 +202,7 @@
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -220,6 +222,7 @@
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -239,6 +242,7 @@
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -259,6 +263,7 @@
</ForcedIncludeFiles>
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -281,6 +286,7 @@
</ForcedIncludeFiles>
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -303,6 +309,7 @@
</ForcedIncludeFiles>
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@ -325,6 +332,7 @@
</ForcedIncludeFiles>
<DisableSpecificWarnings>4251</DisableSpecificWarnings>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>

View File

@ -27,7 +27,13 @@ namespace antlr4 {
/// </summary>
class ANTLR4CPP_PUBLIC IntStream {
public:
static const size_t EOF = static_cast<size_t>(-1); // std::numeric_limits<size_t>::max(); doesn't work in VS 2013
#if __cplusplus >= 201703L
static constexpr size_t EOF = std::numeric_limits<size_t>::max();
#else
enum : size_t {
EOF = static_cast<size_t>(-1), // std::numeric_limits<size_t>::max(); doesn't work in VS 2013
};
#endif
/// The value returned by <seealso cref="#LA LA()"/> when the end of the stream is
/// reached.

View File

@ -18,14 +18,27 @@ namespace antlr4 {
/// of speed.
class ANTLR4CPP_PUBLIC Lexer : public Recognizer, public TokenSource {
public:
static const size_t DEFAULT_MODE = 0;
static const size_t MORE = static_cast<size_t>(-2);
static const size_t SKIP = static_cast<size_t>(-3);
#if __cplusplus >= 201703L
static constexpr size_t DEFAULT_MODE = 0;
static constexpr size_t MORE = std::numeric_limits<size_t>::max() - 1;
static constexpr size_t SKIP = std::numeric_limits<size_t>::max() - 2;
static const size_t DEFAULT_TOKEN_CHANNEL = Token::DEFAULT_CHANNEL;
static const size_t HIDDEN = Token::HIDDEN_CHANNEL;
static const size_t MIN_CHAR_VALUE = 0;
static const size_t MAX_CHAR_VALUE = 0x10FFFF;
static constexpr size_t DEFAULT_TOKEN_CHANNEL = Token::DEFAULT_CHANNEL;
static constexpr size_t HIDDEN = Token::HIDDEN_CHANNEL;
static constexpr size_t MIN_CHAR_VALUE = 0;
static constexpr size_t MAX_CHAR_VALUE = 0x10FFFF;
#else
enum : size_t {
DEFAULT_MODE = 0,
MORE = static_cast<size_t>(-2), // std::numeric_limits<size_t>::max() - 1; doesn't work in VS 2013
SKIP = static_cast<size_t>(-3), // std::numeric_limits<size_t>::max() - 2; doesn't work in VS 2013
DEFAULT_TOKEN_CHANNEL = Token::DEFAULT_CHANNEL,
HIDDEN = Token::HIDDEN_CHANNEL,
MIN_CHAR_VALUE = 0,
MAX_CHAR_VALUE = 0x10FFFF,
};
#endif
CharStream *_input; // Pure reference, usually from statically allocated instance.

View File

@ -11,7 +11,13 @@ namespace antlr4 {
class ANTLR4CPP_PUBLIC Recognizer {
public:
static const size_t EOF = static_cast<size_t>(-1); // std::numeric_limits<size_t>::max(); doesn't work in VS 2013.
#if __cplusplus >= 201703L
static constexpr size_t EOF = std::numeric_limits<size_t>::max();
#else
enum : size_t {
EOF = static_cast<size_t>(-1), // std::numeric_limits<size_t>::max(); doesn't work in VS 2013.
};
#endif
Recognizer();
Recognizer(Recognizer const&) = delete;

View File

@ -14,24 +14,50 @@ namespace antlr4 {
/// we obtained this token.
class ANTLR4CPP_PUBLIC Token {
public:
static const size_t INVALID_TYPE = 0;
#if __cplusplus >= 201703L
static constexpr size_t INVALID_TYPE = 0;
#else
enum : size_t {
INVALID_TYPE = 0,
};
#endif
/// During lookahead operations, this "token" signifies we hit rule end ATN state
/// and did not follow it despite needing to.
static const size_t EPSILON = static_cast<size_t>(-2);
static const size_t MIN_USER_TOKEN_TYPE = 1;
static const size_t EOF = IntStream::EOF;
#if __cplusplus >= 201703L
static constexpr size_t EPSILON = std::numeric_limits<size_t>::max() - 1;
static constexpr size_t MIN_USER_TOKEN_TYPE = 1;
static constexpr size_t EOF = IntStream::EOF;
#else
enum : size_t {
EPSILON = static_cast<size_t>(-2), // std::numeric_limits<size_t>::max() - 1; doesn't work in VS 2013
MIN_USER_TOKEN_TYPE = 1,
EOF = IntStream::EOF,
};
#endif
virtual ~Token();
/// All tokens go to the parser (unless skip() is called in that rule)
/// on a particular "channel". The parser tunes to a particular channel
/// so that whitespace etc... can go to the parser on a "hidden" channel.
static const size_t DEFAULT_CHANNEL = 0;
#if __cplusplus >= 201703L
static constexpr size_t DEFAULT_CHANNEL = 0;
#else
enum : size_t {
DEFAULT_CHANNEL = 0,
};
#endif
/// Anything on different channel than DEFAULT_CHANNEL is not parsed
/// by parser.
static const size_t HIDDEN_CHANNEL = 1;
#if __cplusplus >= 201703L
static constexpr size_t HIDDEN_CHANNEL = 1;
#else
enum : size_t {
HIDDEN_CHANNEL = 1,
};
#endif
/**
* This is the minimum constant value which can be assigned to a
@ -44,7 +70,13 @@ namespace antlr4 {
*
* @see Token#getChannel()
*/
static const size_t MIN_USER_CHANNEL_VALUE = 2;
#if __cplusplus >= 201703L
static constexpr size_t MIN_USER_CHANNEL_VALUE = 2;
#else
enum : size_t {
MIN_USER_CHANNEL_VALUE = 2,
};
#endif
/// Get the text of the token.
virtual std::string getText() const = 0;

View File

@ -86,8 +86,15 @@ namespace antlr4 {
class ANTLR4CPP_PUBLIC TokenStreamRewriter {
public:
static const std::string DEFAULT_PROGRAM_NAME;
static const size_t PROGRAM_INIT_SIZE = 100;
static const size_t MIN_TOKEN_INDEX = 0;
#if __cplusplus >= 201703L
static constexpr size_t PROGRAM_INIT_SIZE = 100;
static constexpr size_t MIN_TOKEN_INDEX = 0;
#else
enum : size_t {
PROGRAM_INIT_SIZE = 100,
MIN_TOKEN_INDEX = 0,
};
#endif
TokenStreamRewriter(TokenStream *tokens);
virtual ~TokenStreamRewriter();

View File

@ -12,7 +12,13 @@ namespace atn {
class ANTLR4CPP_PUBLIC ATN {
public:
static const size_t INVALID_ALT_NUMBER = 0;
#if __cplusplus >= 201703L
static constexpr size_t INVALID_ALT_NUMBER = 0;
#else
enum : size_t {
INVALID_ALT_NUMBER = 0,
};
#endif
/// Used for runtime deserialization of ATNs from strings.
ATN();

View File

@ -11,8 +11,6 @@
using namespace antlr4::atn;
const size_t ATNConfig::SUPPRESS_PRECEDENCE_FILTER = 0x40000000;
ATNConfig::ATNConfig(ATNState *state_, size_t alt_, Ref<PredictionContext> const& context_)
: ATNConfig(state_, alt_, context_, SemanticContext::NONE) {
}

View File

@ -114,7 +114,13 @@ namespace atn {
* {@link #isPrecedenceFilterSuppressed} property as a bit within the
* existing {@link #reachesIntoOuterContext} field.
*/
static const size_t SUPPRESS_PRECEDENCE_FILTER;
#if __cplusplus >= 201703L
static constexpr size_t SUPPRESS_PRECEDENCE_FILTER = 0x40000000;
#else
enum : size_t {
SUPPRESS_PRECEDENCE_FILTER = 0x40000000,
};
#endif
};
} // namespace atn

View File

@ -57,8 +57,6 @@ using namespace antlr4;
using namespace antlr4::atn;
using namespace antlrcpp;
const size_t ATNDeserializer::SERIALIZED_VERSION = 3;
namespace {
uint32_t deserializeInt32(const std::vector<uint16_t>& data, size_t offset) {

View File

@ -13,7 +13,13 @@ namespace atn {
class ANTLR4CPP_PUBLIC ATNDeserializer {
public:
static const size_t SERIALIZED_VERSION;
#if __cplusplus >= 201703L
static constexpr size_t SERIALIZED_VERSION = 3;
#else
enum : size_t {
SERIALIZED_VERSION = 3,
};
#endif
/// This is the current serialized UUID.
// ml: defined as function to avoid the “static initialization order fiasco”.

View File

@ -81,8 +81,15 @@ namespace atn {
ATNState& operator=(ATNState const&) = delete;
static const size_t INITIAL_NUM_TRANSITIONS = 4;
static const size_t INVALID_STATE_NUMBER = static_cast<size_t>(-1); // std::numeric_limits<size_t>::max();
#if __cplusplus >= 201703L
static constexpr size_t INITIAL_NUM_TRANSITIONS = 4;
static constexpr size_t INVALID_STATE_NUMBER = std::numeric_limits<size_t>::max();
#else
enum : size_t {
INITIAL_NUM_TRANSITIONS = 4,
INVALID_STATE_NUMBER = static_cast<size_t>(-1), // std::numeric_limits<size_t>::max(); doesn't work in VS 2013
};
#endif
enum {
ATN_INVALID_TYPE = 0,

View File

@ -17,7 +17,13 @@ namespace atn {
public:
/// Special value added to the lookahead sets to indicate that we hit
/// a predicate during analysis if {@code seeThruPreds==false}.
static const size_t HIT_PRED = Token::INVALID_TYPE;
#if __cplusplus >= 201703L
static constexpr size_t HIT_PRED = Token::INVALID_TYPE;
#else
enum : size_t {
HIT_PRED = Token::INVALID_TYPE,
};
#endif
const atn::ATN &_atn;

View File

@ -38,8 +38,15 @@ namespace atn {
public:
static const size_t MIN_DFA_EDGE = 0;
static const size_t MAX_DFA_EDGE = 127; // forces unicode to stay in ATN
#if __cplusplus >= 201703L
static constexpr size_t MIN_DFA_EDGE = 0;
static constexpr size_t MAX_DFA_EDGE = 127; // forces unicode to stay in ATN
#else
enum : size_t {
MIN_DFA_EDGE = 0,
MAX_DFA_EDGE = 127, // forces unicode to stay in ATN
};
#endif
protected:
/// <summary>

View File

@ -30,10 +30,22 @@ namespace atn {
// ml: originally Integer.MAX_VALUE, which would be -1 for us, but this is already used in places where
// -1 is converted to unsigned, so we use a different value here. Any value does the job provided it doesn't
// conflict with real return states.
static const size_t EMPTY_RETURN_STATE = static_cast<size_t>(-10); // std::numeric_limits<size_t>::max() - 9;
#if __cplusplus >= 201703L
static constexpr size_t EMPTY_RETURN_STATE = std::numeric_limits<size_t>::max() - 9;
#else
enum : size_t {
EMPTY_RETURN_STATE = static_cast<size_t>(-10), // std::numeric_limits<size_t>::max() - 9; doesn't work in VS 2013
};
#endif
private:
static const size_t INITIAL_HASH = 1;
#if __cplusplus >= 201703L
static constexpr size_t INITIAL_HASH = 1;
#else
enum : size_t {
INITIAL_HASH = 1,
};
#endif
public:
static size_t globalNodeCount;

View File

@ -13,7 +13,13 @@ namespace misc {
class ANTLR4CPP_PUBLIC MurmurHash {
private:
static const size_t DEFAULT_SEED = 0;
#if __cplusplus >= 201703L
static constexpr size_t DEFAULT_SEED = 0;
#else
enum : size_t {
DEFAULT_SEED = 0,
};
#endif
/// Initialize the hash using the default seed value.
/// Returns the intermediate hash value.