diff --git a/dstep/translator/MacroDefinition.d b/dstep/translator/MacroDefinition.d index 1775c982..dabf9659 100644 --- a/dstep/translator/MacroDefinition.d +++ b/dstep/translator/MacroDefinition.d @@ -328,6 +328,14 @@ string translate(Expression expression, ExpressionContext context) }, delegate string(CastExpr castExpr) { + if (!castExpr.type.isExposed && !castExpr.isParamType) + { + return format( + "%s(%s)", + castExpr.type.spelling, + castExpr.subexpr.debraced.translate(context)); + } + return format( "cast(%s) %s", translateType(context, Cursor.init, castExpr.type).makeString(), @@ -343,6 +351,9 @@ string translate(Expression expression, ExpressionContext context) translateBinaryOperator!OrExpr, translateBinaryOperator!LogicalAndExpr, translateBinaryOperator!LogicalOrExpr, + translateBinaryOperator!AndAssignExpr, + translateBinaryOperator!XorAssignExpr, + translateBinaryOperator!OrAssignExpr, delegate string(CondExpr condExpr) { return format( @@ -403,6 +414,9 @@ void guessParamTypes(Expression expression, ref ExprType[string] params, ExprTyp guessBinaryOperator!OrExpr, guessBinaryOperator!LogicalAndExpr, guessBinaryOperator!LogicalOrExpr, + guessBinaryOperator!AndAssignExpr, + guessBinaryOperator!XorAssignExpr, + guessBinaryOperator!OrAssignExpr, delegate void(CondExpr condExpr) { condExpr.expr.guessParamTypes(params, type); @@ -522,6 +536,7 @@ bool translateFunctAlias( { import std.algorithm.comparison : equal; import std.algorithm.iteration : map; + import std.algorithm.searching : startsWith; CallExpr* expr = definition.expr.peek!CallExpr; auto expressionContext = ExpressionContext.make(context); @@ -554,11 +569,17 @@ bool translateFunctAlias( .map!(a => a.translate(expressionContext)))) { version (D1) - enum fmt = "alias %2$s %1$s;"; + string fmt = "alias %2$s %1$s;"; else - enum fmt = "alias %1$s = %2$s;"; + string fmt = "alias %1$s = %2$s;"; - output.singleLine(fmt, definition.spelling, ident.spelling); + // Handle compiler builtins (eg. __builtin_unreachable) + string value = ident.spelling; + if (value.startsWith("__builtin_") || value == "_Alignof") + { + fmt = "// FIXME: " ~ fmt; + } + output.singleLine(fmt, definition.spelling, value); return true; } } @@ -592,6 +613,8 @@ void translateMacroDefinitionAliasOrConst( Context context, TypedMacroDefinition definition) { + import std.algorithm.searching : startsWith, canFind; + auto expressionContext = ExpressionContext.make(context); string formatString; @@ -612,10 +635,19 @@ void translateMacroDefinitionAliasOrConst( formatString = "enum %s = %s;"; } + string value = debraced.translate(expressionContext); + if (["const", "static", "volatile", "_Static_assert"].canFind(value) || + // Handle compiler builtins + value.startsWith("__builtin_") || + value.startsWith("__attribute__")) + { + formatString = "// FIXME: " ~ formatString; + } + output.singleLine( formatString, definition.definition.spelling, - debraced.translate(expressionContext)); + value); expressionContext.elevateImports(); } diff --git a/dstep/translator/MacroParser.d b/dstep/translator/MacroParser.d index 8f3686e5..459feb63 100644 --- a/dstep/translator/MacroParser.d +++ b/dstep/translator/MacroParser.d @@ -414,6 +414,7 @@ class CastExpr { Type type; Expression subexpr; + bool isParamType; override string toString() { @@ -480,6 +481,15 @@ class LogicalAndExpr : BinaryExpr class LogicalOrExpr : BinaryExpr { } +class AndAssignExpr : BinaryExpr +{ } + +class XorAssignExpr : BinaryExpr +{ } + +class OrAssignExpr : BinaryExpr +{ } + class CondExpr { Expression expr; @@ -530,6 +540,9 @@ alias Expression = Algebraic!( OrExpr, LogicalAndExpr, LogicalOrExpr, + AndAssignExpr, + XorAssignExpr, + OrAssignExpr, CondExpr); Expression debraced(Expression expression) @@ -655,17 +668,24 @@ Expression parseTokenConcat(ref Token[] tokens) Expression parsePrimaryExpr(ref Token[] tokens, Cursor[string] table, bool defined) { + auto local = tokens; string spelling; - auto type = parseTypeName(tokens, table); + auto type = parseTypeName(local, table, false); if (type.isValid) + { + tokens = local; return Expression(TypeIdentifier(type)); + } - if (accept(tokens, spelling, TokenKind.identifier)) + local = tokens; + if (accept(local, spelling, TokenKind.identifier) || + accept(local, spelling, TokenKind.keyword)) + { + tokens = local; return Expression(Identifier(spelling)); - - auto local = tokens; + } auto substrings = parseStringConcat(local); @@ -709,9 +729,9 @@ Expression parseArg(ref Token[] tokens, Cursor[string] table, bool defined) return expression; } - auto type = parseTypeName(local, table); + auto type = parseTypeName(local, table, false); - if (type.isValid) + if (type.isValid && type.isExposed) { tokens = local; expression = TypeIdentifier(type); @@ -843,7 +863,7 @@ Expression parseSizeofType(ref Token[] tokens, Cursor[string] table) if (acceptPunctuation!("(")(local)) { - Type type = parseTypeName(local, table); + Type type = parseTypeName(local, table, true); if (type.isValid && acceptPunctuation!(")")(local)) { @@ -964,7 +984,7 @@ Expression parseCastExpr(ref Token[] tokens, Cursor[string] table, bool defined) if (!accept!("(")(local, TokenKind.punctuation)) return parseUnaryExpr(tokens, table, defined); - Type type = parseTypeName(local, table); + Type type = parseTypeName(local, table, true); if (!type.isValid) return parseUnaryExpr(tokens, table, defined); @@ -1032,6 +1052,56 @@ Expression parseCondExpr(ref Token[] tokens, Cursor[string] table, bool defined) return expr; } +Expression parseAssignExpr(ref Token[] tokens, Cursor[string] table, bool defined) +{ + auto local = tokens; + + Expression expr = parseCondExpr(local, table, defined); + + if (!expr.hasValue) + return Expression.init; + + string op; + + if (accept!("&=", "^=", "|=")(local, op, TokenKind.punctuation)) + { + Expression rhs = parseAssignExpr(local, table, defined); + + if (!rhs.hasValue) + return Expression.init; + + tokens = local; + + if (op == "&=") + { + auto result = new AndAssignExpr; + result.left = expr; + result.right = rhs; + result.operator = op; + return Expression(result); + } + else if (op == "^=") + { + auto result = new XorAssignExpr; + result.left = expr; + result.right = rhs; + result.operator = op; + return Expression(result); + } + else + { + auto result = new OrAssignExpr; + result.left = expr; + result.right = rhs; + result.operator = op; + return Expression(result); + } + } + + tokens = local; + return expr; +} + bool parseBasicSpecifier(ref Token[] tokens, ref string spelling, Cursor[string] table) { import std.meta : AliasSeq; @@ -1049,7 +1119,11 @@ bool parseBasicSpecifier(ref Token[] tokens, ref string spelling, Cursor[string] // "__complex__", TBD // "_Complex", TBD "bool", - "_Bool"); + "_Bool", + "__SIZE_TYPE__", + "__WCHAR_TYPE__", + "__WINT_TYPE__", + "__PTRDIFF_TYPE__"); return accept!(specifiers)(tokens, spelling); } @@ -1374,6 +1448,30 @@ bool basicSpecifierListToType(ref Type type, Set!string specifiers) return true; } + if (specifiers.contains("__SIZE_TYPE__")) + { + type = Type(CXTypeKind.unexposed, "size_t"); + return true; + } + + if (specifiers.contains("__WCHAR_TYPE__")) + { + type = Type(CXTypeKind.wChar, "wchar"); + return true; + } + + if (specifiers.contains("__WINT_TYPE__")) + { + type = Type(CXTypeKind.uShort, "ushort"); + return true; + } + + if (specifiers.contains("__PTRDIFF_TYPE__")) + { + type = Type(CXTypeKind.unexposed, "ptrdiff_t"); + return true; + } + return false; } @@ -1402,7 +1500,7 @@ bool parseAbstractDeclarator(ref Token[] tokens, ref Type type, Cursor[string] t return parsePointer(tokens, type); } -Type parseTypeName(ref Token[] tokens, Cursor[string] table) +Type parseTypeName(ref Token[] tokens, Cursor[string] table, bool anyType = false) { auto local = tokens; @@ -1411,6 +1509,9 @@ Type parseTypeName(ref Token[] tokens, Cursor[string] table) if (!parseSpecifierQualifierList(local, type, table)) return type; + if (anyType && acceptIdentifier(local, type.spelling)) + type.kind = CXTypeKind.unexposed; + parseAbstractDeclarator(local, type, table); tokens = local; @@ -1425,10 +1526,10 @@ Expression parseExpr(ref Token[] tokens, Cursor[string] table, bool defined) if (concatExpr.hasValue) return concatExpr; - auto condExpr = parseCondExpr(tokens, table, defined); + auto assignExpr = parseAssignExpr(tokens, table, defined); - if (condExpr.hasValue) - return condExpr; + if (assignExpr.hasValue) + return assignExpr; return Expression.init; } @@ -1437,7 +1538,7 @@ Expression parseExpr(ref Token[] tokens, bool defined) { Cursor[string] table; - return parseCondExpr(tokens, table, defined); + return parseAssignExpr(tokens, table, defined); } Expression parseEnumMember(Token[] tokens, Cursor[string] table) @@ -1588,10 +1689,101 @@ MacroDefinition parsePartialMacroDefinition( else { tokens = local; + fixCasts(result); return result; } } +void fixCasts(MacroDefinition definition) +{ + if (!definition.aliasOrConst) + { + fixCasts(definition.params, definition.expr); + } +} + +void fixCasts(string[] params, ref Expression expr) +{ + import std.algorithm.searching : canFind; + + if (auto castExpr = expr.peek!CastExpr()) + { + if (!castExpr.type.isExposed()) + { + if (auto unaryExpr = castExpr.subexpr.peek!UnaryExpr()) + { + fixCasts(params, unaryExpr.subexpr); + if (unaryExpr.operator == "&") + { + auto newExpr = new AndExpr(); + newExpr.operator = unaryExpr.operator; + newExpr.left = Identifier(castExpr.type.spelling); + newExpr.right = unaryExpr.subexpr; + expr = newExpr; + } else if (["+", "-"].canFind(unaryExpr.operator)) + { + auto newExpr = new AddExpr(); + newExpr.operator = unaryExpr.operator; + newExpr.left = Identifier(castExpr.type.spelling); + newExpr.right = unaryExpr.subexpr; + expr = newExpr; + } else if (unaryExpr.operator == "*") + { + auto newExpr = new MulExpr(); + newExpr.operator = unaryExpr.operator; + newExpr.left = Identifier(castExpr.type.spelling); + newExpr.right = unaryExpr.subexpr; + expr = newExpr; + } + return; + } + else if (!params.canFind(castExpr.type.spelling)) + { + fixCasts(params, castExpr.subexpr); + + if (castExpr.subexpr.convertsTo!BinaryExpr) + { + BinaryExpr binaryExpr = castExpr.subexpr.get!(BinaryExpr); + auto newCallExpr = new CallExpr(); + newCallExpr.expr = Identifier(castExpr.type.spelling); + newCallExpr.args = [binaryExpr.left]; + binaryExpr.left = newCallExpr; + expr = castExpr.subexpr; + } + return; + } + } + castExpr.isParamType = params.canFind(castExpr.type.spelling); + fixCasts(params, castExpr.subexpr); + } else if (auto subExpr = expr.peek!SubExpr()) + { + fixCasts(params, subExpr.subexpr); + } else if (auto unaryExpr = expr.peek!UnaryExpr()) + { + fixCasts(params, unaryExpr.subexpr); + } else if (auto dotExpr = expr.peek!DotExpr()) + { + fixCasts(params, dotExpr.subexpr); + } else if (auto arrowExpr = expr.peek!ArrowExpr()) + { + fixCasts(params, arrowExpr.subexpr); + } else if (auto indexExpr = expr.peek!IndexExpr()) + { + fixCasts(params, indexExpr.subexpr); + fixCasts(params, indexExpr.index); + } else if (auto condExpr = expr.peek!CondExpr()) + { + fixCasts(params, condExpr.expr); + fixCasts(params, condExpr.left); + fixCasts(params, condExpr.right); + } else if (expr.hasValue && expr.convertsTo!(BinaryExpr)) + { + BinaryExpr binaryExpr = expr.get!BinaryExpr; + fixCasts(params, binaryExpr.left); + fixCasts(params, binaryExpr.right); + } +} + MacroDefinition[] parseMacroDefinitions(Range)( Range cursors, Cursor[string] types) diff --git a/dstep/translator/Type.d b/dstep/translator/Type.d index 3bd80b49..e47efea1 100644 --- a/dstep/translator/Type.d +++ b/dstep/translator/Type.d @@ -109,7 +109,7 @@ do default: result = translateType( context, - type.kind, + type, rewriteIdToObjcObject) .makeSourceNode(); } @@ -278,7 +278,7 @@ string translateTypedef(Context context, Type type) if (isDKeyword(type.spelling)) { - return type.spelling != translateType(context, type.canonical.kind) + return type.spelling != translateType(context, type.canonical) ? renameDKeyword(type.spelling) : type.spelling; } @@ -300,7 +300,7 @@ do if (declaration.isValid) return translateType(context, declaration, rewriteIdToObjcObject); else - return translateType(context, type.kind, rewriteIdToObjcObject) + return translateType(context, type, rewriteIdToObjcObject) .makeSourceNode(); } @@ -561,15 +561,15 @@ do return translateType(context, cursor, pointee); } -string translateType (Context context, CXTypeKind kind, bool rewriteIdToObjcObject = true) +string translateType (Context context, Type type, bool rewriteIdToObjcObject = true) { import std.conv; with (CXTypeKind) - switch (kind) + switch (type.kind) { case invalid: return ""; - case unexposed: return ""; + case unexposed: return type.spelling.empty ? "" : type.spelling; case void_: return "void"; case bool_: return "bool"; case charU: return ""; @@ -632,6 +632,6 @@ string translateType (Context context, CXTypeKind kind, bool rewriteIdToObjcObje case elaborated: return ""; - default: assert(0, "Unhandled type kind " ~ to!string(kind)); + default: assert(0, "Unhandled type kind " ~ to!string(type.kind)); } } diff --git a/dstep/translator/TypeInference.d b/dstep/translator/TypeInference.d index 65934f16..56d21791 100644 --- a/dstep/translator/TypeInference.d +++ b/dstep/translator/TypeInference.d @@ -70,6 +70,12 @@ void inferMacroSignature( void pass(T)(T operator) { } + void recurseBinary(T)(T expr) + { + inferMacroSignature(context, currentDefinition, expr.left); + inferMacroSignature(context, currentDefinition, expr.right); + } + bool isParamMeta(TypedMacroDefinition definition, string name) { import std.algorithm; @@ -122,10 +128,58 @@ void inferMacroSignature( if (updated) context.queue.insertBack(*definition); }, + delegate void(CastExpr castExpr) + { + import std.algorithm : countUntil; + + auto type = castExpr.type.isPointer ? castExpr.type.pointee : castExpr.type; + auto index = currentDefinition.params.countUntil(type.spelling); + + if (index != -1 && currentDefinition.signature.params[index].peek!Generic) + { + currentDefinition.signature.params[index] = Meta.init; + } + }, delegate void(SubExpr subExpr) { inferMacroSignature(context, currentDefinition, subExpr.subexpr); }, + delegate void(UnaryExpr unaryExpr) + { + inferMacroSignature(context, currentDefinition, unaryExpr.subexpr); + }, + delegate void(DotExpr dotExpr) + { + inferMacroSignature(context, currentDefinition, dotExpr.subexpr); + }, + delegate void(ArrowExpr arrowExpr) + { + inferMacroSignature(context, currentDefinition, arrowExpr.subexpr); + }, + delegate void(IndexExpr indexExpr) + { + inferMacroSignature(context, currentDefinition, indexExpr.subexpr); + inferMacroSignature(context, currentDefinition, indexExpr.index); + }, + delegate void(CondExpr condExpr) + { + inferMacroSignature(context, currentDefinition, condExpr.expr); + inferMacroSignature(context, currentDefinition, condExpr.left); + inferMacroSignature(context, currentDefinition, condExpr.right); + }, + recurseBinary!MulExpr, + recurseBinary!AddExpr, + recurseBinary!SftExpr, + recurseBinary!RelExpr, + recurseBinary!EqlExpr, + recurseBinary!AndExpr, + recurseBinary!XorExpr, + recurseBinary!OrExpr, + recurseBinary!LogicalAndExpr, + recurseBinary!LogicalOrExpr, + recurseBinary!AndAssignExpr, + recurseBinary!XorAssignExpr, + recurseBinary!OrAssignExpr, pass); } @@ -229,6 +283,9 @@ InferredType inferExpressionType(Expression expression) inferBinaryOperator!OrExpr, inferBinaryOperator!LogicalAndExpr, inferBinaryOperator!LogicalOrExpr, + inferBinaryOperator!AndAssignExpr, + inferBinaryOperator!XorAssignExpr, + inferBinaryOperator!OrAssignExpr, delegate InferredType(CondExpr condExpr) { return commonType( diff --git a/tests/functional/clang-c/Platform.d b/tests/functional/clang-c/Platform.d index 0ac640d8..4e1cc85a 100644 --- a/tests/functional/clang-c/Platform.d +++ b/tests/functional/clang-c/Platform.d @@ -17,3 +17,5 @@ extern (C): /* MSVC DLL import/export. */ +// FIXME: enum CINDEX_DEPRECATED = __attribute__(deprecated); + diff --git a/tests/unit/MacroParsingTests.d b/tests/unit/MacroParsingTests.d index a77a1afc..dbb09d18 100644 --- a/tests/unit/MacroParsingTests.d +++ b/tests/unit/MacroParsingTests.d @@ -142,6 +142,17 @@ unittest localAssert("int long unsigned long", CXTypeKind.uLongLong); } +// Parse compiler types. +unittest +{ + alias localAssert = assertParsedTypeHasKind; + + localAssert("__SIZE_TYPE__", CXTypeKind.unexposed); + localAssert("__WCHAR_TYPE__", CXTypeKind.wChar); + localAssert("__WINT_TYPE__", CXTypeKind.uShort); + localAssert("__PTRDIFF_TYPE__", CXTypeKind.unexposed); +} + // Do not parse invalid types. unittest { diff --git a/tests/unit/MacroTranslTests.d b/tests/unit/MacroTranslTests.d index 6a7cb3c3..befefb81 100644 --- a/tests/unit/MacroTranslTests.d +++ b/tests/unit/MacroTranslTests.d @@ -841,3 +841,167 @@ extern (D) auto fun(T)(auto ref T a) } D"); } + +// Translate compound assignment operators &=, ^=, |=. +unittest +{ + assertTME("#define FOO(a, b) a &= b", "a &= b"); + assertTME("#define FOO(a, b) a ^= b", "a ^= b"); + assertTME("#define FOO(a, b) a |= b", "a |= b"); +} + +// Compound assignment operators are right-associative. +unittest +{ + assertTME("#define FOO(a, b, c) a &= b |= c", "a &= b |= c"); + assertTME("#define FOO(a, b, c) a ^= b &= c", "a ^= b &= c"); + assertTME("#define FOO(a, b, c) a |= b ^= c", "a |= b ^= c"); + assertTME("#define FOO(a, b, c, d) a &= b |= c ^= d", "a &= b |= c ^= d"); +} + +// Compound assignment has lower precedence than conditional ?:. +unittest +{ + assertTME("#define FOO(a, b, c, d) a &= b ? c : d", "a &= b ? c : d"); + assertTME("#define FOO(a, b, c, d) a ^= b ? c : d", "a ^= b ? c : d"); + assertTME("#define FOO(a, b, c, d) a |= b ? c : d", "a |= b ? c : d"); +} + +// Compound assignment mixed with other operators. +unittest +{ + assertTME("#define FOO(a, b, c) a &= b & !c", "a &= b & !c"); + assertTME("#define FOO(a, b, c) a ^= ~b + c", "a ^= ~b + c"); + assertTME("#define FOO(a, b, c, d) d &= a |= b && c", "d &= a |= b && c"); + assertTME("#define FOO(a, b, c, d) d ^= a ? ~c % d : c * ~d ^ -(b ? c & d : d) | c", "d ^= a ? ~c % d : c * ~d ^ -(b ? c & d : d) | c"); +} + +// Comment out compiler builtins and language keywords. +unittest +{ + assertTMD(q"C +#define va_copy __builtin_va_copy +C", q"D +// FIXME: enum va_copy = __builtin_va_copy; +D"); + + assertTMD(q"C +#define fake _builtin_fake +C", q"D +enum fake = _builtin_fake; +D"); + + assertTMD(q"C +#define foo(x) __builtin_foo(x) +C", q"D +// FIXME: alias foo = __builtin_foo; +D"); +} + +// Translate unknown identifier as function call with multiple args. +unittest +{ + assertTMD(q"C +#define FOO(a) (func)((bar)(a), (baz)(a)) +C", q"D +extern (D) auto FOO(T)(auto ref T a) +{ + return func(bar(a), baz(a)); +} +D"); +} + +unittest +{ + assertTMD(q"C +#define NEG(a) (func)(-(a)) +C", q"D +extern (D) auto NEG(T)(auto ref T a) +{ + return func(-a); +} +D"); +} + +// Translate unknown identifier as function call. +unittest +{ + assertTMD(q"C +#define FOO(a, b) (func)((baz)(~a) & (!b) + 3 * sizeof((b))) +C", q"D +extern (D) auto FOO(T0, T1)(auto ref T0 a, auto ref T1 b) +{ + return func(baz(~a) & (!b) + 3 * (b).sizeof); +} +D"); +} + +// Translate macro argument as type cast. +unittest +{ + assertTMD(q"C +#define FIELD_PTR(Record, TYPE, Field) ((TYPE *)&((Record)->Field)) +C", q"D +extern (D) auto FIELD_PTR(TYPE, T0, T2)(auto ref T0 Record, auto ref T2 Field) +{ + return cast(TYPE*) &(Record.Field); +} +D"); + + assertTMD(q"C +#define mycast(x,y) (x)y +C", q"D +extern (D) auto mycast(x, T)(auto ref T y) +{ + return cast(x) y; +} +D"); +} + +// Translate macro argument as type cast in conditional expression. +unittest +{ + assertTMD(q"C +#define VA_ARG(Marker, TYPE) ((sizeof(TYPE) < sizeof(UINTN)) ? (TYPE)(__builtin_va_arg(Marker, UINTN)) : (TYPE)(__builtin_va_arg(Marker, TYPE))) +C", q"D +extern (D) auto VA_ARG(TYPE, T)(auto ref T Marker) +{ + return (TYPE.sizeof < UINTN.sizeof) ? cast(TYPE) __builtin_va_arg(Marker, UINTN) : cast(TYPE) __builtin_va_arg(Marker, TYPE); +} +D"); +} + +// Translate unknown identifier as function call with complex arguments. +unittest +{ + assertTMD(q"C +#define FOO(a) (func)(~(a.d) ? (b[1]) : (((c) + (1)) * ((2) - (c)))) +C", q"D +extern (D) auto FOO(T)(auto ref T a) +{ + return func(~a.d ? (b[1]) : ((c + (1)) * ((2) - c))); +} +D"); +} + +// Translate compiler type macros. +unittest +{ + assertTMD(q"C +#define FOO __SIZE_TYPE__ +C", q"D +alias FOO = size_t; +D"); + + assertTMD(q"C +#define FOO __WCHAR_TYPE__ +C", q"D +alias FOO = wchar; +D"); + + assertTMD(q"C +#define FOO __PTRDIFF_TYPE__ +C", q"D +alias FOO = ptrdiff_t; +D"); +} diff --git a/tests/unit/TypeInferenceTests.d b/tests/unit/TypeInferenceTests.d index b5604773..e0e042dd 100644 --- a/tests/unit/TypeInferenceTests.d +++ b/tests/unit/TypeInferenceTests.d @@ -215,3 +215,269 @@ enum ENUM2 = QUX!int('c', 2); D"); } + +unittest +{ + assertTranslates(q"C +#define XOR(x) x ^ 0xFF +C", q"D +extern (C): + +extern (D) auto XOR(T)(auto ref T x) +{ + return x ^ 0xFF; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define LAND(x, y) x && y +C", q"D +extern (C): + +extern (D) auto LAND(T0, T1)(auto ref T0 x, auto ref T1 y) +{ + return x && y; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define ADD_CAST(x, y, z) ((x) + (z)y) +C", q"D +extern (C): + +extern (D) auto ADD_CAST(z, T0, T1)(auto ref T0 x, auto ref T1 y) +{ + return x + cast(z) y; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define UNARY_CAST(x, z) ~(z)(x) +C", q"D +extern (C): + +extern (D) auto UNARY_CAST(z, T)(auto ref T x) +{ + return ~cast(z) x; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define DOT_CAST(x, z) ((z)x).field +C", q"D +extern (C): + +extern (D) auto DOT_CAST(z, T)(auto ref T x) +{ + return (cast(z) x).field; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define ARROW_CAST(x, z) ((z)x)->field +C", q"D +extern (C): + +extern (D) auto ARROW_CAST(z, T)(auto ref T x) +{ + return (cast(z) x).field; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define INDEX_CAST(arr, TYPE, i) arr[(TYPE)i] +C", q"D +extern (C): + +extern (D) auto INDEX_CAST(TYPE, T0, T2)(auto ref T0 arr, auto ref T2 i) +{ + return arr[cast(TYPE) i]; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define SFT_CAST(TYPE, x) (TYPE)x << 1 +C", q"D +extern (C): + +extern (D) auto SFT_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x << 1; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define REL_CAST(TYPE, x) (TYPE)x < 10 +C", q"D +extern (C): + +extern (D) auto REL_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x < 10; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define EQL_CAST(TYPE, x) (TYPE)x == 0 +C", q"D +extern (C): + +extern (D) auto EQL_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x == 0; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define MUL_CAST(TYPE, x) (TYPE)x * 2 +C", q"D +extern (C): + +extern (D) auto MUL_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x * 2; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define AND_CAST(TYPE, x) (TYPE)x & 0xFF +C", q"D +extern (C): + +extern (D) auto AND_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x & 0xFF; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define XOR_CAST(TYPE, x) (TYPE)x ^ 0xFF +C", q"D +extern (C): + +extern (D) auto XOR_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x ^ 0xFF; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define OR_CAST(TYPE, x) (TYPE)x | 1 +C", q"D +extern (C): + +extern (D) auto OR_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x | 1; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define LAND_CAST(TYPE, x) (TYPE)x && 1 +C", q"D +extern (C): + +extern (D) auto LAND_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x && 1; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define LOR_CAST(TYPE, x) (TYPE)x || 0 +C", q"D +extern (C): + +extern (D) auto LOR_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x || 0; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define AND_ASSIGN_CAST(TYPE, x) (TYPE)x &= 0xFF +C", q"D +extern (C): + +extern (D) auto AND_ASSIGN_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x &= 0xFF; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define XOR_ASSIGN_CAST(TYPE, x) (TYPE)x ^= 0xFF +C", q"D +extern (C): + +extern (D) auto XOR_ASSIGN_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x ^= 0xFF; +} +D"); +} + +unittest +{ + assertTranslates(q"C +#define OR_ASSIGN_CAST(TYPE, x) (TYPE)x |= 1 +C", q"D +extern (C): + +extern (D) auto OR_ASSIGN_CAST(TYPE, T)(auto ref T x) +{ + return cast(TYPE) x |= 1; +} +D"); +}