diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index f8dd1a39c676..dab538f3a983 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2521,3 +2521,45 @@ whether or not an attribute is supported by the pragma by referring to the The attributes are applied to all matching declarations individually, even when the attribute is semantically incorrect. The attributes that aren't applied to any declaration are not verified semantically. + +Specifying section names for global objects (#pragma clang section) +=================================================================== + +The ``#pragma clang section`` directive provides a means to assign section-names +to global variables, functions and static variables. + +The section names can be specified as: + +.. code-block:: c++ + + #pragma clang section bss="myBSS" data="myData" rodata="myRodata" text="myText" + +The section names can be reverted back to default name by supplying an empty +string to the section kind, for example: + +.. code-block:: c++ + + #pragma clang section bss="" data="" text="" rodata="" + +The ``#pragma clang section`` directive obeys the following rules: + +* The pragma applies to all global variable, statics and function declarations + from the pragma to the end of the translation unit. + +* The pragma clang section is enabled automatically, without need of any flags. + +* This feature is only defined to work sensibly for ELF targets. + +* If section name is specified through _attribute_((section("myname"))), then + the attribute name gains precedence. + +* Global variables that are initialized to zero will be placed in the named + bss section, if one is present. + +* The ``#pragma clang section`` directive does not does try to infer section-kind + from the name. For example, naming a section "``.bss.mySec``" does NOT mean + it will be a bss section name. + +* The decision about which section-kind applies to each global is taken in the back-end. + Once the section-kind is known, appropriate section name, as specified by the user using + ``#pragma clang section`` directive, is applied to that global. diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 9da2cc376d54..bc36fd8c8297 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1683,6 +1683,42 @@ def Section : InheritableAttr { let Documentation = [SectionDocs]; } +def PragmaClangBSSSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PragmaClangDataSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PragmaClangRodataSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[GlobalVar], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + +def PragmaClangTextSection : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"Name">]; + let Subjects = SubjectList<[Function], ErrorDiag, + "ExpectedFunctionMethodOrGlobalVar">; + let Documentation = [Undocumented]; +} + def Sentinel : InheritableAttr { let Spellings = [GCC<"sentinel">]; let Args = [DefaultIntArgument<"Sentinel", 0>, diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index f04ed8ed4ce6..f39ffeae61f4 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -887,9 +887,18 @@ def warn_pragma_expected_rparen : Warning< "missing ')' after '#pragma %0' - ignoring">, InGroup; def warn_pragma_expected_identifier : Warning< "expected identifier in '#pragma %0' - ignored">, InGroup; + +// '#pragma clang section' related errors +def err_pragma_expected_clang_section_name : Error< + "expected one of [bss|data|rodata|text] section kind in '#pragma %0'">; +def err_pragma_clang_section_expected_equal : Error< + "expected '=' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">; +def err_pragma_clang_section_expected_name_or_clear : Error< + "expected section name or '\"\"' following '#pragma clang section %select{invalid|bss|data|rodata|text}0'">; def warn_pragma_expected_section_name : Warning< "expected a string literal for the section name in '#pragma %0' - ignored">, InGroup; + def warn_pragma_expected_section_push_pop_or_name : Warning< "expected push, pop or a string literal for the section name in '#pragma %0' - ignored">, InGroup; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 537796fa6465..f4d5a661bd72 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -166,6 +166,7 @@ class Parser : public CodeCompletionHandler { std::unique_ptr FPContractHandler; std::unique_ptr OpenCLExtensionHandler; std::unique_ptr OpenMPHandler; + std::unique_ptr PCSectionHandler; std::unique_ptr MSCommentHandler; std::unique_ptr MSDetectMismatchHandler; std::unique_ptr MSPointersToMembers; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4c9f18a0724c..741a3a471667 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -336,6 +336,35 @@ public: /// \brief Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; + /// \brief pragma clang section kind + enum PragmaClangSectionKind { + PCSK_Invalid = 0, + PCSK_BSS = 1, + PCSK_Data = 2, + PCSK_Rodata = 3, + PCSK_Text = 4 + }; + + enum PragmaClangSectionAction { + PCSA_Set = 0, + PCSA_Clear = 1 + }; + + struct PragmaClangSection { + std::string SectionName; + bool Valid = false; + SourceLocation PragmaLocation; + + void Act(SourceLocation PragmaLocation, + PragmaClangSectionAction Action, + StringLiteral* Name); + }; + + PragmaClangSection PragmaClangBSSSection; + PragmaClangSection PragmaClangDataSection; + PragmaClangSection PragmaClangRodataSection; + PragmaClangSection PragmaClangTextSection; + enum PragmaMsStackAction { PSK_Reset = 0x0, // #pragma () PSK_Set = 0x1, // #pragma (value) @@ -8117,6 +8146,11 @@ public: POAK_Reset // #pragma options align=reset }; + /// ActOnPragmaClangSection - Called on well formed \#pragma clang section + void ActOnPragmaClangSection(SourceLocation PragmaLoc, + PragmaClangSectionAction Action, + PragmaClangSectionKind SecKind, StringRef SecName); + /// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align. void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index d6abfa15e541..87bfa507a8c0 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -406,6 +406,13 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, if (D.hasAttr()) CGM.AddGlobalAnnotations(&D, var); + if (auto *SA = D.getAttr()) + var->addAttribute("bss-section", SA->getName()); + if (auto *SA = D.getAttr()) + var->addAttribute("data-section", SA->getName()); + if (auto *SA = D.getAttr()) + var->addAttribute("rodata-section", SA->getName()); + if (const SectionAttr *SA = D.getAttr()) var->setSection(SA->getName()); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index dde8f2e36920..77adf7b441a2 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1026,9 +1026,25 @@ void CodeGenModule::setNonAliasAttributes(const Decl *D, llvm::GlobalObject *GO) { SetCommonAttributes(D, GO); - if (D) + if (D) { + if (auto *GV = dyn_cast(GO)) { + if (auto *SA = D->getAttr()) + GV->addAttribute("bss-section", SA->getName()); + if (auto *SA = D->getAttr()) + GV->addAttribute("data-section", SA->getName()); + if (auto *SA = D->getAttr()) + GV->addAttribute("rodata-section", SA->getName()); + } + + if (auto *F = dyn_cast(GO)) { + if (auto *SA = D->getAttr()) + if (!D->getAttr()) + F->addFnAttr("implicit-section-name", SA->getName()); + } + if (const SectionAttr *SA = D->getAttr()) GO->setSection(SA->getName()); + } getTargetCodeGenInfo().setTargetAttributes(D, GO, *this); } @@ -1127,6 +1143,10 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, setLinkageAndVisibilityForGV(F, FD); + if (FD->getAttr()) { + F->addFnAttr("implicit-section-name"); + } + if (const SectionAttr *SA = FD->getAttr()) F->setSection(SA->getName()); @@ -2828,6 +2848,14 @@ static bool isVarDeclStrongDefinition(const ASTContext &Context, if (D->hasAttr()) return true; + // A variable cannot be both common and exist in a section. + // We dont try to determine which is the right section in the front-end. + // If no specialized section name is applicable, it will resort to default. + if (D->hasAttr() || + D->hasAttr() || + D->hasAttr()) + return true; + // Thread local vars aren't considered common linkage. if (D->getTLSKind()) return true; diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 18aebe658073..262743756a6b 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -49,6 +49,15 @@ struct PragmaPackHandler : public PragmaHandler { Token &FirstToken) override; }; +struct PragmaClangSectionHandler : public PragmaHandler { + explicit PragmaClangSectionHandler(Sema &S) + : PragmaHandler("section"), Actions(S) {} + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) override; +private: + Sema &Actions; +}; + struct PragmaMSStructHandler : public PragmaHandler { explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {} void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, @@ -224,6 +233,9 @@ void Parser::initializePragmaHandlers() { FPContractHandler.reset(new PragmaFPContractHandler()); PP.AddPragmaHandler("STDC", FPContractHandler.get()); + PCSectionHandler.reset(new PragmaClangSectionHandler(Actions)); + PP.AddPragmaHandler("clang", PCSectionHandler.get()); + if (getLangOpts().OpenCL) { OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler()); PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get()); @@ -323,6 +335,9 @@ void Parser::resetPragmaHandlers() { MSCommentHandler.reset(); } + PP.RemovePragmaHandler("clang", PCSectionHandler.get()); + PCSectionHandler.reset(); + if (getLangOpts().MicrosoftExt) { PP.RemovePragmaHandler(MSDetectMismatchHandler.get()); MSDetectMismatchHandler.reset(); @@ -1614,6 +1629,51 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true); } +// #pragma clang section bss="abc" data="" rodata="def" text="" +void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, Token &FirstToken) { + + Token Tok; + auto SecKind = Sema::PragmaClangSectionKind::PCSK_Invalid; + + PP.Lex(Tok); // eat 'section' + while (Tok.isNot(tok::eod)) { + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section"; + return; + } + + const IdentifierInfo *SecType = Tok.getIdentifierInfo(); + if (SecType->isStr("bss")) + SecKind = Sema::PragmaClangSectionKind::PCSK_BSS; + else if (SecType->isStr("data")) + SecKind = Sema::PragmaClangSectionKind::PCSK_Data; + else if (SecType->isStr("rodata")) + SecKind = Sema::PragmaClangSectionKind::PCSK_Rodata; + else if (SecType->isStr("text")) + SecKind = Sema::PragmaClangSectionKind::PCSK_Text; + else { + PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section"; + return; + } + + PP.Lex(Tok); // eat ['bss'|'data'|'rodata'|'text'] + if (Tok.isNot(tok::equal)) { + PP.Diag(Tok.getLocation(), diag::err_pragma_clang_section_expected_equal) << SecKind; + return; + } + + std::string SecName; + if (!PP.LexStringLiteral(Tok, SecName, "pragma clang section", false)) + return; + + Actions.ActOnPragmaClangSection(Tok.getLocation(), + (SecName.size()? Sema::PragmaClangSectionAction::PCSA_Set : + Sema::PragmaClangSectionAction::PCSA_Clear), + SecKind, SecName); + } +} + // #pragma 'align' '=' {'native','natural','mac68k','power','reset'} // #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'} static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok, diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 76ca65373dda..8c13ead64457 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -126,6 +126,36 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, PackStack.Act(PragmaLoc, Action, StringRef(), Alignment); } +void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action, + PragmaClangSectionKind SecKind, StringRef SecName) { + PragmaClangSection *CSec; + switch (SecKind) { + case PragmaClangSectionKind::PCSK_BSS: + CSec = &PragmaClangBSSSection; + break; + case PragmaClangSectionKind::PCSK_Data: + CSec = &PragmaClangDataSection; + break; + case PragmaClangSectionKind::PCSK_Rodata: + CSec = &PragmaClangRodataSection; + break; + case PragmaClangSectionKind::PCSK_Text: + CSec = &PragmaClangTextSection; + break; + default: + llvm_unreachable("invalid clang section kind"); + } + + if (Action == PragmaClangSectionAction::PCSA_Clear) { + CSec->Valid = false; + return; + } + + CSec->Valid = true; + CSec->SectionName = SecName; + CSec->PragmaLocation = PragmaLoc; +} + void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, StringRef SlotLabel, Expr *alignment) { Expr *Alignment = static_cast(alignment); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index ef6dfaa2f28c..cba220daf774 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8651,6 +8651,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setInvalidDecl(); } + // Apply an implicit SectionAttr if '#pragma clang section text' is active + if (PragmaClangTextSection.Valid && D.isFunctionDefinition() && + !NewFD->hasAttr()) { + NewFD->addAttr(PragmaClangTextSectionAttr::CreateImplicit(Context, + PragmaClangTextSection.SectionName, + PragmaClangTextSection.PragmaLocation)); + } + // Apply an implicit SectionAttr if #pragma code_seg is active. if (CodeSegStack.CurrentValue && D.isFunctionDefinition() && !NewFD->hasAttr()) { @@ -11175,6 +11183,23 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) { if (!VD) return; + // Apply an implicit SectionAttr if '#pragma clang section bss|data|rodata' is active + if (VD->hasGlobalStorage() && VD->isThisDeclarationADefinition() && + !inTemplateInstantiation() && !VD->hasAttr()) { + if (PragmaClangBSSSection.Valid) + VD->addAttr(PragmaClangBSSSectionAttr::CreateImplicit(Context, + PragmaClangBSSSection.SectionName, + PragmaClangBSSSection.PragmaLocation)); + if (PragmaClangDataSection.Valid) + VD->addAttr(PragmaClangDataSectionAttr::CreateImplicit(Context, + PragmaClangDataSection.SectionName, + PragmaClangDataSection.PragmaLocation)); + if (PragmaClangRodataSection.Valid) + VD->addAttr(PragmaClangRodataSectionAttr::CreateImplicit(Context, + PragmaClangRodataSection.SectionName, + PragmaClangRodataSection.PragmaLocation)); + } + if (auto *DD = dyn_cast(ThisDecl)) { for (auto *BD : DD->bindings()) { FinalizeDeclaration(BD); diff --git a/clang/test/CodeGenCXX/clang-sections-tentative.c b/clang/test/CodeGenCXX/clang-sections-tentative.c new file mode 100644 index 000000000000..e663079b9aa4 --- /dev/null +++ b/clang/test/CodeGenCXX/clang-sections-tentative.c @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -x c -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s + +// Test that section attributes are attached to C tentative definitions as per +// '#pragma clang section' directives. + +#pragma clang section bss = ".bss.1" +int x; // bss.1 + +#pragma clang section bss = "" +int x; // stays in .bss.1 +int y; // not assigned a section attribute +int z; // not assigned a section attribute + +#pragma clang section bss = ".bss.2" +int x; // stays in .bss.1 +int y; // .bss.2 + +// Test the same for `const` declarations. +#pragma clang section rodata = ".rodata.1" +const int cx; // rodata.1 + +#pragma clang section rodata = "" +const int cx; // stays in .rodata.1 +const int cy; // not assigned a section attribute +const int cz; // not assigned a rodata section attribute + +#pragma clang section rodata = ".rodata.2" +const int cx; // stays in .rodata.1 +const int cy; // .rodata.2 + +// CHECK: @x = global i32 0, align 4 #0 +// CHECK: @y = global i32 0, align 4 #1 +// CHECK: @z = common global i32 0, align 4 +// CHECK: @cx = constant i32 0, align 4 #2 +// CHECK: @cy = constant i32 0, align 4 #3 +// CHECK: @cz = constant i32 0, align 4 #1 + +// CHECK: attributes #0 = { "bss-section"=".bss.1" } +// CHECK: attributes #1 = { "bss-section"=".bss.2" } +// CHECK: attributes #2 = { "bss-section"=".bss.2" "rodata-section"=".rodata.1" } +// CHECK: attributes #3 = { "bss-section"=".bss.2" "rodata-section"=".rodata.2" } diff --git a/clang/test/CodeGenCXX/clang-sections.cpp b/clang/test/CodeGenCXX/clang-sections.cpp new file mode 100644 index 000000000000..4fe42eaf7789 --- /dev/null +++ b/clang/test/CodeGenCXX/clang-sections.cpp @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -emit-llvm -triple arm-none-eabi -o - %s | FileCheck %s +// Test that global variables, statics and functions are attached section-attributes +// as per '#pragma clang section' directives. + +extern "C" { +// test with names for each section +#pragma clang section bss="my_bss.1" data="my_data.1" rodata="my_rodata.1" +#pragma clang section text="my_text.1" +int a; // my_bss.1 +int b = 1; // my_data.1 +int c[4]; // my_bss.1 +short d[5] = {0}; // my_bss.1 +short e[6] = {0, 0, 1}; // my_data.1 +extern const int f; +const int f = 2; // my_rodata.1 +int foo(void) { // my_text.1 + return b; +} +static int g[2]; // my_bss.1 +#pragma clang section bss="" +int h; // default - .bss +#pragma clang section data="" bss="my_bss.2" text="my_text.2" +int i = 0; // my_bss.2 +extern const int j; +const int j = 4; // default - .rodata +int k; // my_bss.2 +extern int zoo(int *x, int *y); +int goo(void) { // my_text.2 + static int lstat_h; // my_bss.2 + return zoo(g, &lstat_h); +} +#pragma clang section rodata="my_rodata.2" data="my_data.2" +int l = 5; // my_data.2 +extern const int m; +const int m = 6; // my_rodata.2 +#pragma clang section rodata="" data="" bss="" text="" +int n; // default +int o = 6; // default +extern const int p; +const int p = 7; // default +int hoo(void) { + return b; +} +} +//CHECK: @a = global i32 0, align 4 #0 +//CHECK: @b = global i32 1, align 4 #0 +//CHECK: @c = global [4 x i32] zeroinitializer, align 4 #0 +//CHECK: @d = global [5 x i16] zeroinitializer, align 2 #0 +//CHECK: @e = global [6 x i16] [i16 0, i16 0, i16 1, i16 0, i16 0, i16 0], align 2 #0 +//CHECK: @f = constant i32 2, align 4 #0 + +//CHECK: @h = global i32 0, align 4 #1 +//CHECK: @i = global i32 0, align 4 #2 +//CHECK: @j = constant i32 4, align 4 #2 +//CHECK: @k = global i32 0, align 4 #2 +//CHECK: @_ZZ3gooE7lstat_h = internal global i32 0, align 4 #2 +//CHECK: @_ZL1g = internal global [2 x i32] zeroinitializer, align 4 #0 + +//CHECK: @l = global i32 5, align 4 #3 +//CHECK: @m = constant i32 6, align 4 #3 + +//CHECK: @n = global i32 0, align 4 +//CHECK: @o = global i32 6, align 4 +//CHECK: @p = constant i32 7, align 4 + +//CHECK: define i32 @foo() #4 { +//CHECK: define i32 @goo() #5 { +//CHECK: declare i32 @zoo(i32*, i32*) #6 +//CHECK: define i32 @hoo() #7 { + +//CHECK: attributes #0 = { "bss-section"="my_bss.1" "data-section"="my_data.1" "rodata-section"="my_rodata.1" } +//CHECK: attributes #1 = { "data-section"="my_data.1" "rodata-section"="my_rodata.1" } +//CHECK: attributes #2 = { "bss-section"="my_bss.2" "rodata-section"="my_rodata.1" } +//CHECK: attributes #3 = { "bss-section"="my_bss.2" "data-section"="my_data.2" "rodata-section"="my_rodata.2" } +//CHECK: attributes #4 = { {{.*"implicit-section-name"="my_text.1".*}} } +//CHECK: attributes #5 = { {{.*"implicit-section-name"="my_text.2".*}} } +//CHECK-NOT: attributes #6 = { {{.*"implicit-section-name".*}} } +//CHECK-NOT: attributes #7 = { {{.*"implicit-section-name".*}} } diff --git a/clang/test/Sema/pragma-clang-section.c b/clang/test/Sema/pragma-clang-section.c new file mode 100644 index 000000000000..49463889d37b --- /dev/null +++ b/clang/test/Sema/pragma-clang-section.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple arm-none-eabi +#pragma clang section bss="mybss.1" data="mydata.1" rodata="myrodata.1" text="mytext.1" +#pragma clang section bss="" data="" rodata="" text="" +#pragma clang section + +#pragma clang section dss="mybss.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} +#pragma clang section deta="mydata.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} +#pragma clang section rodeta="rodata.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} +#pragma clang section taxt="text.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} + +#pragma clang section section bss="mybss.2" // expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} + +#pragma clang section bss "mybss.2" // expected-error {{expected '=' following '#pragma clang section bss'}} +#pragma clang section data "mydata.2" // expected-error {{expected '=' following '#pragma clang section data'}} +#pragma clang section rodata "myrodata.2" // expected-error {{expected '=' following '#pragma clang section rodata'}} +#pragma clang section bss="" data="" rodata="" text="" more //expected-error {{expected one of [bss|data|rodata|text] section kind in '#pragma clang section'}} +int a;