Module: Rubycc::Front::AST

Defined in:
lib/rubycc/front/ast.rb

Overview

Abstract syntax tree nodes for the C subset. Each node carries a representative token (token) for source-location diagnostics.

Defined Under Namespace

Classes: AlignofType, ArrayDesignator, Assignment, Binary, Block, Break, BuiltinAlloca, BuiltinAtomic, BuiltinBitScan, BuiltinConstantP, BuiltinExpect, BuiltinOffsetof, BuiltinOverflow, BuiltinSync, BuiltinUnreachable, Call, Case, Cast, Comma, CompoundAssignment, CompoundLiteral, Conditional, Continue, Default, DoWhile, EmptyStmt, ExpressionStmt, FloatLit, For, FunctionDecl, FunctionDef, GlobalDecl, Goto, If, IncDec, InitAttributes, InitItem, InitializerList, InlineAsm, IntLit, Label, LogicalAnd, LogicalOr, MemberAccess, MemberDesignator, OffsetofIndex, OffsetofMember, Parameter, Program, Return, SizeofExpr, SizeofType, StatementExpr, StringLit, Subscript, Switch, Unary, VaArg, VaCopy, VaEnd, VaStart, VariableDecl, VariableRef, While

Class Method Summary collapse

Class Method Details

.integer_constant_zero?(node) ⇒ Boolean

Whether node is an integer constant expression (6.6) whose value is 0, via the shared ConstantEvaluator — not just a syntactic IntLit, so a foldable expression (an enum constant, "1 - 1", a cast to another integer type) is recognized too. Not a constant expression at all (a variable, a call, ...) or a division by a folded-zero divisor rescues to false rather than propagating, since this is a yes/no predicate, not a context that should surface either as a diagnostic.

Returns:

  • (Boolean)


218
219
220
221
222
# File 'lib/rubycc/front/ast.rb', line 218

def self.integer_constant_zero?(node)
  ConstantEvaluator.evaluate(node).zero?
rescue ConstantEvaluator::NotConstant, ConstantEvaluator::DivisionByZero
  false
end

.null_pointer_constant?(node) ⇒ Boolean

A null pointer constant (ISO C11 6.3.2.3p3): "An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant." #integer_constant_zero? below recognizes the first alternative on its own — that is exactly ConstantEvaluator's notion of an expression that folds to the integer 0, which already covers a plain integer literal 0, a character constant like '\0' (the lexer lowers it to an IntLit 0), an enumeration constant of value 0 (the parser folds a reference to one into an IntLit 0 on the spot, see #parse_primary_expression), a purely arithmetic fold such as "1 - 1", and — because 6.6p6 allows a cast to an integer type inside an integer constant expression — any of those cast to another integer type, such as "(unsigned long)0" or "(char)0". A cast to a floating type is never allowed in an integer constant expression (6.6p6 restricts a constant-expression cast to converting to an integer type, outside sizeof/alignof/_Alignof), so "(double)0" is correctly excluded here — matching the "invalid operands" gcc gives comparing it against a pointer, rather than the silent accept a floating cast would otherwise get. The second alternative — that whole expression additionally cast to "void *" — is the explicit Cast case below, since ConstantEvaluator itself only folds a cast to an integer destination.

A null pointer constant converts implicitly to any pointer type in an assignment, an initializer, an argument, a return, an "=="/"!=" comparison and the arms of "?:".

Returns:

  • (Boolean)


204
205
206
207
208
209
# File 'lib/rubycc/front/ast.rb', line 204

def self.null_pointer_constant?(node)
  return true if integer_constant_zero?(node)

  node.is_a?(Cast) && node.type.pointer? && node.type.target.void? &&
    integer_constant_zero?(node.operand)
end