Check the application of a unary operator to an expression.
(check-unary op arg-expr arg-etype) → etype
We check
The operand of the address operator must be an lvalue [C:6.5.3.2/1].
The text in [C:6.5.3.2/1] talks about lvalues
but singles out postfix
The operand of the indirection operator must be a pointer [C:6.5.3.2/2]. The result has the referenced type, and the expression is an lvalue [C:6.5.3.2/4]. We return an expression type, not a type, so that we can represent the fact that an indirection expression is an lvalue. All the other unary expressions are not lvalues.
For unary plus and minus, the operand must be arithmetic, and the result has the promoted type.
For bitwise negation, the operand must be integer, and the result has the promoted type.
For logical negation,
the operand must be scalar
and the result is
For all operators except
Function:
(defun check-unary (op arg-expr arg-etype) (declare (xargs :guard (and (unopp op) (exprp arg-expr) (expr-typep arg-etype)))) (let ((__function__ 'check-unary)) (declare (ignorable __function__)) (case (unop-kind op) (:address (if (expr-type->lvalue arg-etype) (make-expr-type :type (type-pointer (expr-type->type arg-etype)) :lvalue nil) (reserrf (list :unary-mistype (unop-fix op) (expr-fix arg-expr) :required :lvalue :supplied (expr-type-fix arg-etype))))) (:indir (b* ((arg-type (expr-type->type arg-etype)) (arg-type (apconvert-type arg-type))) (if (type-case arg-type :pointer) (make-expr-type :type (type-pointer->to arg-type) :lvalue t) (reserrf (list :unary-mistype (unop-fix op) (expr-fix arg-expr) :required :pointer :supplied arg-type))))) ((:plus :minus) (b* ((arg-type (expr-type->type arg-etype)) (arg-type (apconvert-type arg-type))) (if (type-arithmeticp arg-type) (make-expr-type :type (promote-type arg-type) :lvalue nil) (reserrf (list :unary-mistype (unop-fix op) (expr-fix arg-expr) :required :arithmetic :supplied (type-fix arg-type)))))) (:bitnot (b* ((arg-type (expr-type->type arg-etype)) (arg-type (apconvert-type arg-type))) (if (type-integerp arg-type) (make-expr-type :type (promote-type arg-type) :lvalue nil) (reserrf (list :unary-mistype (unop-fix op) (expr-fix arg-expr) :required :integer :supplied (type-fix arg-type)))))) (:lognot (b* ((arg-type (expr-type->type arg-etype)) (arg-type (apconvert-type arg-type))) (if (type-scalarp arg-type) (make-expr-type :type (type-sint) :lvalue nil) (reserrf (list :unary-mistype (unop-fix op) (expr-fix arg-expr) :required :scalar :supplied (type-fix arg-type)))))) (t (reserrf (impossible))))))
Theorem:
(defthm expr-type-resultp-of-check-unary (b* ((etype (check-unary op arg-expr arg-etype))) (expr-type-resultp etype)) :rule-classes :rewrite)
Theorem:
(defthm check-unary-of-unop-fix-op (equal (check-unary (unop-fix op) arg-expr arg-etype) (check-unary op arg-expr arg-etype)))
Theorem:
(defthm check-unary-unop-equiv-congruence-on-op (implies (unop-equiv op op-equiv) (equal (check-unary op arg-expr arg-etype) (check-unary op-equiv arg-expr arg-etype))) :rule-classes :congruence)
Theorem:
(defthm check-unary-of-expr-fix-arg-expr (equal (check-unary op (expr-fix arg-expr) arg-etype) (check-unary op arg-expr arg-etype)))
Theorem:
(defthm check-unary-expr-equiv-congruence-on-arg-expr (implies (expr-equiv arg-expr arg-expr-equiv) (equal (check-unary op arg-expr arg-etype) (check-unary op arg-expr-equiv arg-etype))) :rule-classes :congruence)
Theorem:
(defthm check-unary-of-expr-type-fix-arg-etype (equal (check-unary op arg-expr (expr-type-fix arg-etype)) (check-unary op arg-expr arg-etype)))
Theorem:
(defthm check-unary-expr-type-equiv-congruence-on-arg-etype (implies (expr-type-equiv arg-etype arg-etype-equiv) (equal (check-unary op arg-expr arg-etype) (check-unary op arg-expr arg-etype-equiv))) :rule-classes :congruence)