Index: ELF/LinkerScript.h =================================================================== --- ELF/LinkerScript.h +++ ELF/LinkerScript.h @@ -75,7 +75,6 @@ AssignmentKind, // . = expr or = expr OutputSectionKind, InputSectionKind, - AssertKind, // ASSERT(expr) ByteKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr) }; @@ -177,15 +176,6 @@ std::vector> ThunkSections; }; -// Represents an ASSERT(). -struct AssertCommand : BaseCommand { - AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {} - - static bool classof(const BaseCommand *C) { return C->Kind == AssertKind; } - - Expr Expression; -}; - // Represents BYTE(), SHORT(), LONG(), or QUAD(). struct ByteCommand : BaseCommand { ByteCommand(Expr E, unsigned Size, std::string CommandString) Index: ELF/LinkerScript.cpp =================================================================== --- ELF/LinkerScript.cpp +++ ELF/LinkerScript.cpp @@ -801,12 +801,6 @@ continue; } - // Handle ASSERT(). - if (auto *Cmd = dyn_cast(Base)) { - Cmd->Expression(); - continue; - } - // Handle a single input section description command. // It calculates and assigns the offsets for each section and also // updates the output section size. @@ -1053,12 +1047,6 @@ Cmd->Size = Dot - Cmd->Addr; continue; } - - if (auto *Cmd = dyn_cast(Base)) { - Cmd->Expression(); - continue; - } - assignOffsets(cast(Base)); } Ctx = nullptr; Index: ELF/ScriptParser.cpp =================================================================== --- ELF/ScriptParser.cpp +++ ELF/ScriptParser.cpp @@ -89,10 +89,9 @@ unsigned readPhdrType(); SortSectionPolicy readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); - SymbolAssignment *readProvideOrAssignment(StringRef Tok); + SymbolAssignment *readAssignment(StringRef Tok); void readSort(); - AssertCommand *readAssert(); - Expr readAssertExpr(); + Expr readAssert(); Expr readConstant(); Expr getPageSize(); @@ -228,9 +227,7 @@ if (Tok == ";") continue; - if (Tok == "ASSERT") { - Script->SectionCommands.push_back(readAssert()); - } else if (Tok == "ENTRY") { + if (Tok == "ENTRY") { readEntry(); } else if (Tok == "EXTERN") { readExtern(); @@ -258,7 +255,7 @@ readSections(); } else if (Tok == "VERSION") { readVersion(); - } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) { + } else if (SymbolAssignment *Cmd = readAssignment(Tok)) { Script->SectionCommands.push_back(Cmd); } else { setError("unknown directive: " + Tok); @@ -449,14 +446,10 @@ std::vector V; while (!errorCount() && !consume("}")) { StringRef Tok = next(); - BaseCommand *Cmd = readProvideOrAssignment(Tok); - if (!Cmd) { - if (Tok == "ASSERT") - Cmd = readAssert(); - else - Cmd = readOutputSectionDescription(Tok); - } - V.push_back(Cmd); + if (BaseCommand *Cmd = readAssignment(Tok)) + V.push_back(Cmd); + else + V.push_back(readOutputSectionDescription(Tok)); } if (!atEOF() && consume("INSERT")) { @@ -606,11 +599,7 @@ expect(")"); } -AssertCommand *ScriptParser::readAssert() { - return make(readAssertExpr()); -} - -Expr ScriptParser::readAssertExpr() { +Expr ScriptParser::readAssert() { expect("("); Expr E = readExpr(); expect(","); @@ -711,13 +700,10 @@ StringRef Tok = next(); if (Tok == ";") { // Empty commands are allowed. Do nothing here. - } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) { + } else if (SymbolAssignment *Assign = readAssignment(Tok)) { Cmd->SectionCommands.push_back(Assign); } else if (ByteCommand *Data = readByteCommand(Tok)) { Cmd->SectionCommands.push_back(Data); - } else if (Tok == "ASSERT") { - Cmd->SectionCommands.push_back(readAssert()); - expect(";"); } else if (Tok == "CONSTRUCTORS") { // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors // by name. This is for very old file formats such as ECOFF/XCOFF. @@ -785,7 +771,11 @@ return Cmd; } -SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) { +SymbolAssignment *ScriptParser::readAssignment(StringRef Tok) { + // Assert expression returns Dot, so this is equal to ".=." + if (Tok == "ASSERT") + return make(".", readAssert(), getCurrentLocation()); + size_t OldPos = Pos; SymbolAssignment *Cmd = nullptr; if (peek() == "=" || peek() == "+=") @@ -1055,7 +1045,7 @@ }; } if (Tok == "ASSERT") - return readAssertExpr(); + return readAssert(); if (Tok == "CONSTANT") return readConstant(); if (Tok == "DATA_SEGMENT_ALIGN") { Index: test/ELF/linkerscript/assert.s =================================================================== --- test/ELF/linkerscript/assert.s +++ test/ELF/linkerscript/assert.s @@ -30,10 +30,11 @@ # RUN: ld.lld -shared -o %t6 --script %t6.script %t1.o # RUN: llvm-readobj %t6 > /dev/null +## Unlike the GNU ld, we accept the ASSERT without the semicolon. +## It is consistent with how ASSERT can be written outside of the +## output section declaration. # RUN: echo "SECTIONS { .foo : { ASSERT(1, \"true\") } }" > %t7.script -# RUN: not ld.lld -shared -o %t7 --script %t7.script %t1.o > %t.log 2>&1 -# RUN: FileCheck %s -check-prefix=CHECK-SEMI < %t.log -# CHECK-SEMI: error: {{.*}}.script:1: ; expected, but got } +# RUN: ld.lld -shared -o %t7 --script %t7.script %t1.o .section .foo, "a" .quad 0