blob: 2446d523c50b8ec014afbf99d978b9710f622fe1 [file] [log] [blame]
//
// Copyright 2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "PreprocessorTest.h"
#include "compiler/preprocessor/Token.h"
namespace angle
{
class IfTest : public SimplePreprocessorTest
{};
TEST_F(IfTest, If_0)
{
const char *str =
"pass_1\n"
"#if 0\n"
"fail\n"
"#endif\n"
"pass_2\n";
const char *expected =
"pass_1\n"
"\n"
"\n"
"\n"
"pass_2\n";
preprocess(str, expected);
}
TEST_F(IfTest, If_1)
{
const char *str =
"pass_1\n"
"#if 1\n"
"pass_2\n"
"#endif\n"
"pass_3\n";
const char *expected =
"pass_1\n"
"\n"
"pass_2\n"
"\n"
"pass_3\n";
preprocess(str, expected);
}
TEST_F(IfTest, If_0_Else)
{
const char *str =
"pass_1\n"
"#if 0\n"
"fail\n"
"#else\n"
"pass_2\n"
"#endif\n"
"pass_3\n";
const char *expected =
"pass_1\n"
"\n"
"\n"
"\n"
"pass_2\n"
"\n"
"pass_3\n";
preprocess(str, expected);
}
TEST_F(IfTest, If_1_Else)
{
const char *str =
"pass_1\n"
"#if 1\n"
"pass_2\n"
"#else\n"
"fail\n"
"#endif\n"
"pass_3\n";
const char *expected =
"pass_1\n"
"\n"
"pass_2\n"
"\n"
"\n"
"\n"
"pass_3\n";
preprocess(str, expected);
}
TEST_F(IfTest, If_0_Elif)
{
const char *str =
"pass_1\n"
"#if 0\n"
"fail_1\n"
"#elif 0\n"
"fail_2\n"
"#elif 1\n"
"pass_2\n"
"#elif 1\n"
"fail_3\n"
"#else\n"
"fail_4\n"
"#endif\n"
"pass_3\n";
const char *expected =
"pass_1\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"pass_2\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"pass_3\n";
preprocess(str, expected);
}
TEST_F(IfTest, If_1_Elif)
{
const char *str =
"pass_1\n"
"#if 1\n"
"pass_2\n"
"#elif 0\n"
"fail_1\n"
"#elif 1\n"
"fail_2\n"
"#else\n"
"fail_4\n"
"#endif\n"
"pass_3\n";
const char *expected =
"pass_1\n"
"\n"
"pass_2\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"pass_3\n";
preprocess(str, expected);
}
TEST_F(IfTest, If_Elif_Else)
{
const char *str =
"pass_1\n"
"#if 0\n"
"fail_1\n"
"#elif 0\n"
"fail_2\n"
"#elif 0\n"
"fail_3\n"
"#else\n"
"pass_2\n"
"#endif\n"
"pass_3\n";
const char *expected =
"pass_1\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"pass_2\n"
"\n"
"pass_3\n";
preprocess(str, expected);
}
TEST_F(IfTest, If_0_Nested)
{
const char *str =
"pass_1\n"
"#if 0\n"
"fail_1\n"
"#if 1\n"
"fail_2\n"
"#else\n"
"fail_3\n"
"#endif\n"
"#else\n"
"pass_2\n"
"#endif\n"
"pass_3\n";
const char *expected =
"pass_1\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"pass_2\n"
"\n"
"pass_3\n";
preprocess(str, expected);
}
TEST_F(IfTest, If_1_Nested)
{
const char *str =
"pass_1\n"
"#if 1\n"
"pass_2\n"
"#if 1\n"
"pass_3\n"
"#else\n"
"fail_1\n"
"#endif\n"
"#else\n"
"fail_2\n"
"#endif\n"
"pass_4\n";
const char *expected =
"pass_1\n"
"\n"
"pass_2\n"
"\n"
"pass_3\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"pass_4\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorPrecedence)
{
const char *str =
"#if 1 + 2 * 3 + - (26 % 17 - + 4 / 2)\n"
"fail_1\n"
"#else\n"
"pass_1\n"
"#endif\n";
const char *expected =
"\n"
"\n"
"\n"
"pass_1\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorDefined)
{
const char *str =
"#if defined foo\n"
"fail_1\n"
"#else\n"
"pass_1\n"
"#endif\n"
"#define foo\n"
"#if defined(foo)\n"
"pass_2\n"
"#else\n"
"fail_2\n"
"#endif\n"
"#undef foo\n"
"#if defined ( foo ) \n"
"fail_3\n"
"#else\n"
"pass_3\n"
"#endif\n";
const char *expected =
"\n"
"\n"
"\n"
"pass_1\n"
"\n"
"\n"
"\n"
"pass_2\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"pass_3\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorEQ)
{
const char *str =
"#if 4 - 1 == 2 + 1\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorNE)
{
const char *str =
"#if 1 != 2\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorLess)
{
const char *str =
"#if 1 < 2\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorGreater)
{
const char *str =
"#if 2 > 1\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorLE)
{
const char *str =
"#if 1 <= 2\n"
"pass_1\n"
"#else\n"
"fail_1\n"
"#endif\n"
"#if 2 <= 2\n"
"pass_2\n"
"#else\n"
"fail_2\n"
"#endif\n";
const char *expected =
"\n"
"pass_1\n"
"\n"
"\n"
"\n"
"\n"
"pass_2\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorGE)
{
const char *str =
"#if 2 >= 1\n"
"pass_1\n"
"#else\n"
"fail_1\n"
"#endif\n"
"#if 2 >= 2\n"
"pass_2\n"
"#else\n"
"fail_2\n"
"#endif\n";
const char *expected =
"\n"
"pass_1\n"
"\n"
"\n"
"\n"
"\n"
"pass_2\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorBitwiseOR)
{
const char *str =
"#if (0xaaaaaaaa | 0x55555555) == 0xffffffff\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorBitwiseAND)
{
const char *str =
"#if (0xaaaaaaa & 0x5555555) == 0\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorBitwiseXOR)
{
const char *str =
"#if (0xaaaaaaa ^ 0x5555555) == 0xfffffff\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorBitwiseComplement)
{
const char *str =
"#if (~ 0xdeadbeef) == -3735928560\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorLeft)
{
const char *str =
"#if (1 << 12) == 4096\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, OperatorRight)
{
const char *str =
"#if (31762 >> 8) == 124\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, ExpressionWithMacros)
{
const char *str =
"#define one 1\n"
"#define two 2\n"
"#define three 3\n"
"#if one + two == three\n"
"pass\n"
"#else\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"\n"
"\n"
"\n"
"pass\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, JunkInsideExcludedBlockIgnored)
{
const char *str =
"#if 0\n"
"foo !@#$%^&* .1bar\n"
"#foo\n"
"#if bar\n"
"fail\n"
"#endif\n"
"#else\n"
"pass\n"
"#endif\n";
const char *expected =
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"pass\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, Ifdef)
{
const char *str =
"#define foo\n"
"#ifdef foo\n"
"pass_1\n"
"#else\n"
"fail_1\n"
"#endif\n"
"#undef foo\n"
"#ifdef foo\n"
"fail_2\n"
"#else\n"
"pass_2\n"
"#endif\n";
const char *expected =
"\n"
"\n"
"pass_1\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"\n"
"pass_2\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, Ifndef)
{
const char *str =
"#define foo\n"
"#ifndef foo\n"
"fail_1\n"
"#else\n"
"pass_1\n"
"#endif\n"
"#undef foo\n"
"#ifndef foo\n"
"pass_2\n"
"#else\n"
"fail_2\n"
"#endif\n";
const char *expected =
"\n"
"\n"
"\n"
"\n"
"pass_1\n"
"\n"
"\n"
"\n"
"pass_2\n"
"\n"
"\n"
"\n";
preprocess(str, expected);
}
TEST_F(IfTest, MissingExpression)
{
const char *str =
"#if\n"
"#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INVALID_EXPRESSION,
pp::SourceLocation(0, 1), "syntax error"));
preprocess(str);
}
TEST_F(IfTest, DivisionByZero)
{
const char *str =
"#if 1 / (3 - (1 + 2))\n"
"#endif\n";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_DIVISION_BY_ZERO, pp::SourceLocation(0, 1), "1 / 0"));
preprocess(str);
}
TEST_F(IfTest, ModuloByZero)
{
const char *str =
"#if 1 % (3 - (1 + 2))\n"
"#endif\n";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_DIVISION_BY_ZERO, pp::SourceLocation(0, 1), "1 % 0"));
preprocess(str);
}
TEST_F(IfTest, DecIntegerOverflow)
{
const char *str =
"#if 4294967296\n"
"#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INTEGER_OVERFLOW, pp::SourceLocation(0, 1),
"4294967296"));
preprocess(str);
}
TEST_F(IfTest, OctIntegerOverflow)
{
const char *str =
"#if 077777777777\n"
"#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INTEGER_OVERFLOW, pp::SourceLocation(0, 1),
"077777777777"));
preprocess(str);
}
TEST_F(IfTest, HexIntegerOverflow)
{
const char *str =
"#if 0xfffffffff\n"
"#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INTEGER_OVERFLOW, pp::SourceLocation(0, 1),
"0xfffffffff"));
preprocess(str);
}
TEST_F(IfTest, UndefinedMacro)
{
const char *str =
"#if UNDEFINED\n"
"#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
pp::SourceLocation(0, 1), "UNDEFINED"));
preprocess(str);
}
TEST_F(IfTest, InvalidExpressionIgnoredForExcludedElif)
{
const char *str =
"#if 1\n"
"pass\n"
"#elif UNDEFINED\n"
"fail\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n"
"\n"
"\n";
// No error or warning.
using testing::_;
EXPECT_CALL(mDiagnostics, print(_, _, _)).Times(0);
preprocess(str, expected);
}
TEST_F(IfTest, ElseWithoutIf)
{
const char *str = "#else\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
pp::SourceLocation(0, 1), "else"));
preprocess(str);
}
TEST_F(IfTest, ElifWithoutIf)
{
const char *str = "#elif 1\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
pp::SourceLocation(0, 1), "elif"));
preprocess(str);
}
TEST_F(IfTest, EndifWithoutIf)
{
const char *str = "#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
pp::SourceLocation(0, 1), "endif"));
preprocess(str);
}
TEST_F(IfTest, ElseAfterElse)
{
const char *str =
"#if 1\n"
"#else\n"
"#else\n"
"#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
pp::SourceLocation(0, 3), "else"));
preprocess(str);
}
TEST_F(IfTest, ElifAfterElse)
{
const char *str =
"#if 1\n"
"#else\n"
"#elif 0\n"
"#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
pp::SourceLocation(0, 3), "elif"));
preprocess(str);
}
TEST_F(IfTest, UnterminatedIf)
{
const char *str = "#if 1\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNTERMINATED,
pp::SourceLocation(0, 1), "if"));
preprocess(str);
}
TEST_F(IfTest, UnterminatedIfdef)
{
const char *str = "#ifdef foo\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNTERMINATED,
pp::SourceLocation(0, 1), "ifdef"));
preprocess(str);
}
// The preprocessor only allows one expression to follow an #if directive.
// Supplying two integer expressions should be an error.
TEST_F(IfTest, ExtraIntExpression)
{
const char *str =
"#if 1 1\n"
"#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
pp::SourceLocation(0, 1), "1"));
preprocess(str);
}
// The preprocessor only allows one expression to follow an #if directive.
// Supplying two expressions where one uses a preprocessor define should be an error.
TEST_F(IfTest, ExtraIdentifierExpression)
{
const char *str =
"#define one 1\n"
"#if 1 one\n"
"#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
pp::SourceLocation(0, 2), "1"));
preprocess(str);
}
// Divide by zero that's not evaluated because of short-circuiting should not cause an error.
TEST_F(IfTest, ShortCircuitedDivideByZero)
{
const char *str =
"#if 1 || (2 / 0)\n"
"pass\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n";
preprocess(str, expected);
}
// Undefined identifier that's not evaluated because of short-circuiting should not cause an error.
TEST_F(IfTest, ShortCircuitedUndefined)
{
const char *str =
"#if 1 || UNDEFINED\n"
"pass\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n";
preprocess(str, expected);
}
// Defined operator produced by macro expansion has undefined behavior according to C++ spec,
// which the GLSL spec references (see C++14 draft spec section 16.1.4), but this behavior is
// needed for passing dEQP tests, which enforce stricter compatibility between implementations.
TEST_F(IfTest, DefinedOperatorValidAfterMacroExpansion)
{
const char *str =
"#define foo defined\n"
"#if !foo bar\n"
"pass\n"
"#endif\n";
preprocess(str, "\n\npass\n\n");
}
// Validate the defined operator is evaluated when the macro is called, not when defined.
TEST_F(IfTest, DefinedOperatorValidWhenUsed)
{
constexpr char str[] = R"(#define BBB 1
#define AAA defined(BBB)
#undef BBB
#if !AAA
pass
#endif
)";
preprocess(str, "\n\n\n\n\npass\n\n");
}
// Validate the defined operator is evaluated when the macro is called, not when defined.
TEST_F(IfTest, DefinedOperatorAfterMacro)
{
constexpr char str[] = R"(#define AAA defined(BBB)
#define BBB 1
#if AAA
pass
#endif
)";
preprocess(str, "\n\n\n\npass\n\n");
}
// Test generating "defined" by concatenation when a macro is called. This is not allowed.
TEST_F(IfTest, DefinedInMacroConcatenationNotAllowed)
{
constexpr char str[] = R"(#define BBB 1
#define AAA(defi, ned) defi ## ned(BBB)
#if !AAA(defi, ned)
pass
#endif
)";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
pp::SourceLocation(0, 4), "defi"));
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
pp::SourceLocation(0, 4), "#"));
preprocess(str);
}
// Test using defined in a macro parameter name. This is not allowed.
TEST_F(IfTest, DefinedAsParameterNameNotAllowed)
{
constexpr char str[] = R"(#define BBB 1
#define AAA(defined) defined(BBB)
#if AAA(defined)
pass
#endif
)";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_UNEXPECTED_TOKEN, pp::SourceLocation(0, 0), ""));
preprocess(str);
}
// This behavour is disabled in WebGL.
TEST_F(IfTest, DefinedOperatorInvalidAfterMacroExpansionInWebGL)
{
const char *str =
"#define foo defined\n"
"#if !foo bar\n"
"pass\n"
"#endif\n";
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
pp::SourceLocation(0, 2), "defined"));
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
pp::SourceLocation(0, 2), "bar"));
preprocess(str, pp::PreprocessorSettings(SH_WEBGL_SPEC));
}
// Defined operator produced by macro expansion has undefined behavior according to C++ spec,
// which the GLSL spec references (see C++14 draft spec section 16.1.4). Some edge case
// behaviours with defined are not portable between implementations and thus are not required
// to pass dEQP Tests.
TEST_F(IfTest, UnterminatedDefinedInMacro)
{
const char *str =
"#define foo defined(\n"
"#if foo\n"
"#endif\n";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_UNEXPECTED_TOKEN, pp::SourceLocation(0, 2), "\n"));
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INVALID_EXPRESSION,
pp::SourceLocation(0, 2), "syntax error"));
preprocess(str);
}
// Defined operator produced by macro expansion has undefined behavior according to C++ spec,
// which the GLSL spec references (see C++14 draft spec section 16.1.4). Some edge case
// behaviours with defined are not portable between implementations and thus are not required
// to pass dEQP Tests.
TEST_F(IfTest, UnterminatedDefinedInMacro2)
{
const char *str =
"#define foo defined(bar\n"
"#if foo\n"
"#endif\n";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_UNEXPECTED_TOKEN, pp::SourceLocation(0, 2), "\n"));
EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_INVALID_EXPRESSION,
pp::SourceLocation(0, 2), "syntax error"));
preprocess(str);
}
// Undefined shift: negative shift offset.
TEST_F(IfTest, BitShiftLeftOperatorNegativeOffset)
{
const char *str =
"#if 2 << -1 == 1\n"
"foo\n"
"#endif\n";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_UNDEFINED_SHIFT, pp::SourceLocation(0, 1), "2 << -1"));
preprocess(str);
}
// Undefined shift: shift offset is out of range.
TEST_F(IfTest, BitShiftLeftOperatorOffset32)
{
const char *str =
"#if 2 << 32 == 1\n"
"foo\n"
"#endif\n";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_UNDEFINED_SHIFT, pp::SourceLocation(0, 1), "2 << 32"));
preprocess(str);
}
// Left hand side of shift is negative.
TEST_F(IfTest, BitShiftLeftOperatorNegativeLHS)
{
const char *str =
"#if (-2) << 1 == -4\n"
"pass\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n";
preprocess(str, expected);
}
// Left shift overflows. Note that the intended result is not explicitly specified, but we assume it
// to do the same operation on the 2's complement bit representation as unsigned shift in C++.
TEST_F(IfTest, BitShiftLeftOverflow)
{
const char *str =
"#if (0x10000 + 0x1) << 28 == 0x10000000\n"
"pass\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n";
preprocess(str, expected);
}
// Left shift of a negative number overflows. Note that the intended result is not explicitly
// specified, but we assume it to do the same operation on the 2's complement bit representation as
// unsigned shift in C++.
TEST_F(IfTest, BitShiftLeftNegativeOverflow)
{
// The bit representation of -5 is 11111111 11111111 11111111 11111011.
// Shifting by 30 leaves: 11000000 00000000 00000000 00000000.
const char *str =
"#if (-5) << 30 == -1073741824\n"
"pass\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n";
preprocess(str, expected);
}
// Undefined shift: shift offset is out of range.
TEST_F(IfTest, BitShiftRightOperatorNegativeOffset)
{
const char *str =
"#if 2 >> -1 == 4\n"
"foo\n"
"#endif\n";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_UNDEFINED_SHIFT, pp::SourceLocation(0, 1), "2 >> -1"));
preprocess(str);
}
// Undefined shift: shift offset is out of range.
TEST_F(IfTest, BitShiftRightOperatorOffset32)
{
const char *str =
"#if 2 >> 32 == 0\n"
"foo\n"
"#endif\n";
EXPECT_CALL(mDiagnostics,
print(pp::Diagnostics::PP_UNDEFINED_SHIFT, pp::SourceLocation(0, 1), "2 >> 32"));
preprocess(str);
}
// Left hand side of shift is negative.
TEST_F(IfTest, BitShiftRightOperatorNegativeLHS)
{
const char *str =
"#if (-2) >> 1 == 0x7fffffff\n"
"pass\n"
"#endif\n";
const char *expected =
"\n"
"pass\n"
"\n";
preprocess(str, expected);
}
} // namespace angle