feat(parser): evaluate the TEXT and GLOBL flags operand as one expression
Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
4eb9100def
commit
cea5db6964
4 files changed
+239
-16
No files matched your search
+39
-13
@@ -43,6 +43,12 @@ type state struct {
|
||||
file *ast.File
|
||||
errs []error
|
||||
|
||||
// expand records the assembly path (ParseWithOptions with Expand): the
|
||||
// one view of a file that must reject what the toolchain's assembler
|
||||
// rejects. The tooling view (linter, formatter, language server) stays
|
||||
// tolerant and reports through its own diagnostics instead.
|
||||
expand bool
|
||||
|
||||
curText *ast.Text // the TEXT body labels/instructions attach to
|
||||
pending []string // comment lines awaiting a TEXT to become its Doc
|
||||
}
|
||||
@@ -245,13 +251,14 @@ func (p *state) parseText(line []token.Token) {
|
||||
text.Name = sym
|
||||
rest = rest[n:]
|
||||
|
||||
// Consume flags (identifiers, possibly '|' joined) up to the frame '$'.
|
||||
// Consume the flags operand: everything between the symbol and the
|
||||
// frame '$' is one operand, which the toolchain evaluates to a single
|
||||
// integer (identifiers joined by '|', each a known textflag.h name,
|
||||
// literals and constant arithmetic beside them). A single trailing
|
||||
// comma is the separator that stood before the '$'.
|
||||
rest = skipComma(rest)
|
||||
text.Flags, text.FlagVal = p.evalFlags(flagsRun(rest), false)
|
||||
for len(rest) > 0 && rest[0].Kind != token.Dollar {
|
||||
if rest[0].Kind == token.Ident {
|
||||
text.Flags = append(text.Flags, rest[0].Text)
|
||||
}
|
||||
// Commas, '|' and anything else between flags is skipped.
|
||||
rest = rest[1:]
|
||||
}
|
||||
|
||||
@@ -291,6 +298,23 @@ func (p *state) parseText(line []token.Token) {
|
||||
}
|
||||
}
|
||||
|
||||
// The toolchain's own TEXT diagnostics over the evaluated flags
|
||||
// (cmd/asm/internal/asm/asm.go asmText, and the frame check its arm64
|
||||
// backend raises): an ABIInternal symbol must not grow the stack, and
|
||||
// NOFRAME reserves no frame at all, so a declared frame contradicts it.
|
||||
// Both belong to the assembly path; the tooling view reports the frame
|
||||
// case through the linter's own advisory instead.
|
||||
if p.expand {
|
||||
if text.Name.ABI == "ABIInternal" && text.FlagVal&flagNOSPLIT == 0 {
|
||||
p.errorf(line[0].Pos, "TEXT %q: ABIInternal requires NOSPLIT", text.Name.Name)
|
||||
}
|
||||
if text.FlagVal&flagNOFRAME != 0 && text.Frame != nil &&
|
||||
text.Frame.Imm.HasVal && text.Frame.Imm.Val > 0 {
|
||||
p.errorf(text.Frame.Pos, "NOFRAME functions must have a frame size of 0, not %d",
|
||||
text.Frame.Imm.Val)
|
||||
}
|
||||
}
|
||||
|
||||
p.file.Decls = append(p.file.Decls, text)
|
||||
p.curText = text
|
||||
}
|
||||
@@ -309,15 +333,17 @@ func (p *state) parseGlobl(line []token.Token) *ast.Globl {
|
||||
g.Name = sym
|
||||
rest = skipComma(rest[n:])
|
||||
// Flags are identifiers (RODATA, DUPOK) or legacy numeric constants
|
||||
// (2, 8, 9, 10) from runtime/textflag.h.
|
||||
for len(rest) > 0 && rest[0].Kind != token.Dollar {
|
||||
if rest[0].Kind == token.Ident || rest[0].Kind == token.Number {
|
||||
g.Flags = append(g.Flags, rest[0].Text)
|
||||
// (2, 8, 9, 10) from runtime/textflag.h. The toolchain evaluates the
|
||||
// operand as one constant expression, so every name is validated here
|
||||
// and the whole operand folds to g.FlagVal; Flags keeps the atoms as
|
||||
// written, the numeric spellings being data-side combinations the
|
||||
// link layer reads back.
|
||||
g.Flags, g.FlagVal = p.evalFlags(flagsRun(rest), true)
|
||||
for i, t := range rest {
|
||||
if t.Kind == token.Dollar {
|
||||
g.Size = parseOperand(rest[i:], false)
|
||||
break
|
||||
}
|
||||
rest = rest[1:]
|
||||
}
|
||||
if len(rest) > 0 && rest[0].Kind == token.Dollar {
|
||||
g.Size = parseOperand(rest, false)
|
||||
}
|
||||
return g
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user