diff --git a/compiler/src/dmd/expression.d b/compiler/src/dmd/expression.d index 13454f1ba2..f6f59ad7f8 100644 --- a/compiler/src/dmd/expression.d +++ b/compiler/src/dmd/expression.d @@ -535,105 +535,6 @@ extern (C++) abstract class Expression : ASTNode return false; } - extern (D) final bool checkScalar() - { - if (op == EXP.error) - return true; - if (type.toBasetype().ty == Terror) - return true; - if (!type.isScalar()) - { - error(loc, "`%s` is not a scalar, it is a `%s`", toChars(), type.toChars()); - return true; - } - return checkValue(); - } - - extern (D) final bool checkNoBool() - { - if (op == EXP.error) - return true; - if (type.toBasetype().ty == Terror) - return true; - if (type.toBasetype().ty == Tbool) - { - error(loc, "operation not allowed on `bool` `%s`", toChars()); - return true; - } - return false; - } - - extern (D) final bool checkIntegral() - { - if (op == EXP.error) - return true; - if (type.toBasetype().ty == Terror) - return true; - if (!type.isIntegral()) - { - error(loc, "`%s` is not of integral type, it is a `%s`", toChars(), type.toChars()); - return true; - } - return checkValue(); - } - - extern (D) final bool checkArithmetic(EXP op) - { - if (op == EXP.error) - return true; - if (type.toBasetype().ty == Terror) - return true; - if (!type.isIntegral() && !type.isFloating()) - { - // unary aggregate ops error here - const char* msg = type.isAggregate() ? - "operator `%s` is not defined for `%s` of type `%s`" : - "illegal operator `%s` for `%s` of type `%s`"; - error(loc, msg, EXPtoString(op).ptr, toChars(), type.toChars()); - return true; - } - - // FIXME: Existing code relies on adding / subtracting types in typeof() expressions: - // alias I = ulong; alias U = typeof(I + 1u); - // https://github.com/dlang/dmd/issues/20763 - if (op == EXP.add || op == EXP.min) - return false; - - return checkValue(); - } - - /******************************* - * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not. - * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics) - * Returns true if error occurs. - */ - extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null) - { - //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : ""); - if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass()) - return false; - - // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal. - switch (rmwOp) - { - case EXP.plusPlus: - case EXP.prePlusPlus: - rmwOp = EXP.addAssign; - break; - case EXP.minusMinus: - case EXP.preMinusMinus: - rmwOp = EXP.minAssign; - break; - default: - break; - } - - error(loc, "read-modify-write operations are not allowed for `shared` variables"); - errorSupplemental(loc, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead", - EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1"); - return true; - } - /****************************** * Take address of expression. */ @@ -3065,18 +2966,6 @@ extern (C++) abstract class BinExp : Expression return e; } - extern (D) final bool checkIntegralBin() - { - bool r1 = e1.checkIntegral(); - bool r2 = e2.checkIntegral(); - return (r1 || r2); - } - - extern (D) final bool checkArithmeticBin() - { - return e1.checkArithmetic(this.op) || e2.checkArithmetic(this.op); - } - /********************* * Mark the operands as will never be dereferenced, * which is useful info for @safe checks. diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 6f79dd03f2..8089f74631 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -14683,6 +14683,98 @@ MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink return m; } +private bool checkScalar(Expression e) +{ + if (e.op == EXP.error) + return true; + if (e.type.toBasetype().ty == Terror) + return true; + if (!e.type.isScalar()) + { + error(e.loc, "`%s` is not a scalar, it is a `%s`", e.toChars(), e.type.toChars()); + return true; + } + return e.checkValue(); +} + +private bool checkNoBool(Expression e) +{ + if (e.op == EXP.error) + return true; + if (e.type.toBasetype().ty == Terror) + return true; + if (e.type.toBasetype().ty == Tbool) + { + error(e.loc, "operation not allowed on `bool` `%s`", e.toChars()); + return true; + } + return false; +} + +private bool checkIntegral(Expression e) +{ + if (e.op == EXP.error) + return true; + if (e.type.toBasetype().ty == Terror) + return true; + if (!e.type.isIntegral()) + { + error(e.loc, "`%s` is not of integral type, it is a `%s`", e.toChars(), e.type.toChars()); + return true; + } + return e.checkValue(); +} + +private bool checkArithmetic(Expression e, EXP op) +{ + if (op == EXP.error) + return true; + if (e.type.toBasetype().ty == Terror) + return true; + if (!e.type.isIntegral() && !e.type.isFloating()) + { + // unary aggregate ops error here + const char* msg = e.type.isAggregate() ? + "operator `%s` is not defined for `%s` of type `%s`" : + "illegal operator `%s` for `%s` of type `%s`"; + error(e.loc, msg, EXPtoString(op).ptr, e.toChars(), e.type.toChars()); + return true; + } + return e.checkValue(); +} + +/******************************* + * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not. + * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics) + * Returns true if error occurs. + */ +private bool checkReadModifyWrite(Expression e, EXP rmwOp, Expression ex = null) +{ + //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : ""); + if (!e.type || !e.type.isShared() || e.type.isTypeStruct() || e.type.isTypeClass()) + return false; + + // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal. + switch (rmwOp) + { + case EXP.plusPlus: + case EXP.prePlusPlus: + rmwOp = EXP.addAssign; + break; + case EXP.minusMinus: + case EXP.preMinusMinus: + rmwOp = EXP.minAssign; + break; + default: + break; + } + + error(e.loc, "read-modify-write operations are not allowed for `shared` variables"); + errorSupplemental(e.loc, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead", + EXPtoString(rmwOp).ptr, e.toChars(), ex ? ex.toChars() : "1"); + return true; +} + private bool checkSharedAccessBin(BinExp binExp, Scope* sc) { const r1 = binExp.e1.checkSharedAccess(sc); @@ -14690,6 +14782,18 @@ private bool checkSharedAccessBin(BinExp binExp, Scope* sc) return (r1 || r2); } +private bool checkIntegralBin(BinExp e) +{ + bool r1 = e.e1.checkIntegral(); + bool r2 = e.e2.checkIntegral(); + return (r1 || r2); +} + +private bool checkArithmeticBin(BinExp e) +{ + return (e.e1.checkArithmetic(e.op) || e.e2.checkArithmetic(e.op)); +} + /*************************************** * If expression is shared, check that we can access it. * Give error message if not.