From: Warren Hunt Date: Tue, 8 Apr 2014 22:30:47 +0000 (+0000) Subject: [MS-ABI] Add support for #pragma section and related pragmas X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7e2504387c6a54cb58eeb05b4f312585433bfe39;p=clang [MS-ABI] Add support for #pragma section and related pragmas This patch adds support for the msvc pragmas section, bss_seg, code_seg, const_seg and data_seg as well as support for __declspec(allocate()). Additionally it corrects semantics and adds diagnostics for __attribute__((section())) and the interaction between the attribute and the msvc pragmas and declspec. In general conflicts should now be well diganosed within and among these features. In supporting the pragmas new machinery for uniform lexing for msvc pragmas was introduced. The new machinery always lexes the entire pragma and stores it on an annotation token. The parser is responsible for parsing the pragma when the handling the annotation token. There is a known outstanding bug in this implementation in C mode. Because these attributes and pragmas apply _only_ to definitions, we process them at the time we detect a definition. Due to tentative definitions in C, we end up processing the definition late. This means that in C mode, everything that ends up in a BSS section will end up in the _last_ BSS section rather than the one that was live at the time of tentative definition, even if that turns out to be the point of actual definition. This issue is not known to impact anything as of yet because we are not aware of a clear use or use case for #pragma bss_seg but should be fixed at some point. Differential Revision=http://reviews.llvm.org/D3065#inline-16241 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205810 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 12a85174c9..6c08e49dac 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -1075,7 +1075,7 @@ def InitPriority : InheritableAttr { } def Section : InheritableAttr { - let Spellings = [GCC<"section">]; + let Spellings = [GCC<"section">, Declspec<"allocate">]; let Args = [StringArgument<"Name">]; let Subjects = SubjectList<[Function, GlobalVar, ObjCMethod, ObjCProperty], ErrorDiag, @@ -1697,6 +1697,7 @@ def MSInheritance : InheritableAttr { Keyword<"__multiple_inheritance">, Keyword<"__virtual_inheritance">, Keyword<"__unspecified_inheritance">]; + let Documentation = [SectionDocs]; let AdditionalMembers = [{ static bool hasVBPtrOffsetField(Spelling Inheritance) { return Inheritance == Keyword_unspecified_inheritance; diff --git a/include/clang/Basic/AttrDocs.td b/include/clang/Basic/AttrDocs.td index 2f62175849..7e923af812 100644 --- a/include/clang/Basic/AttrDocs.td +++ b/include/clang/Basic/AttrDocs.td @@ -27,6 +27,14 @@ This page lists the attributes currently supported by Clang. }]; } +def SectionDocs : Documentation { + let Category = DocCatVariable; + let Content = [{ +The ``section`` attribute allows you to specify a specific section a +global variable or function should be in after translation. + }]; +} + def TLSModelDocs : Documentation { let Category = DocCatVariable; let Content = [{ diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 40fab75f8a..3efac016ad 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -771,6 +771,15 @@ 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; +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; +def warn_pragma_expected_section_label_or_name : Warning< + "expected a stack label or a string literal for the section name in '#pragma %0' - ignored">, + InGroup; def warn_pragma_expected_integer : Warning< "expected integer between %0 and %1 inclusive in '#pragma %2' - ignored">, InGroup; @@ -793,6 +802,15 @@ def warn_pragma_align_invalid_option : Warning< "invalid alignment option in '#pragma %select{align|options align}0' - ignored">, InGroup; // - #pragma pack +def warn_pragma_unsupported_action : Warning< + "known but unsupported action '%1' for '#pragma %0' - ignored">, + InGroup; +def warn_pragma_invalid_specific_action : Warning< + "unknown action '%1' for '#pragma %0' - ignored">, + InGroup; +def warn_pragma_expected_action_or_r_paren : Warning< + "expected action or ')' in '#pragma %0' - ignored">, + InGroup; def warn_pragma_invalid_action : Warning< "unknown action for '#pragma %0' - ignored">, InGroup; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1dd7f815be..0eefcd70f0 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -521,6 +521,7 @@ def warn_cxx_ms_struct : Warning<"ms_struct may not produce MSVC-compatible layouts for classes " "with base classes or virtual functions">, DefaultError, InGroup; +def err_section_conflict : Error<"%0 causes a section type conflict with %1">; def warn_pragma_unused_undeclared_var : Warning< "undeclared variable %0 used as an argument for '#pragma unused'">, diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 47e23ff049..845a8b096f 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -685,6 +685,11 @@ ANNOTATION(pragma_ms_pointers_to_members) // handles them. ANNOTATION(pragma_ms_vtordisp) +// Annotation for all microsoft #pragmas... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_ms_pragma) + // Annotation for #pragma OPENCL EXTENSION... // The lexer produces these so that they only take effect when the parser // handles them. diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index db527f6e45..2d71a0403d 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -155,6 +155,11 @@ class Parser : public CodeCompletionHandler { std::unique_ptr MSPointersToMembers; std::unique_ptr MSVtorDisp; std::unique_ptr MSInitSeg; + std::unique_ptr MSDataSeg; + std::unique_ptr MSBSSSeg; + std::unique_ptr MSConstSeg; + std::unique_ptr MSCodeSeg; + std::unique_ptr MSSection; std::unique_ptr CommentSemaHandler; @@ -476,6 +481,14 @@ private: void HandlePragmaMSVtorDisp(); + void HandlePragmaMSPragma(); + unsigned HandlePragmaMSSection(llvm::StringRef PragmaName, + SourceLocation PragmaLocation); + unsigned HandlePragmaMSSegment(llvm::StringRef PragmaName, + SourceLocation PragmaLocation); + unsigned HandlePragmaMSInitSeg(llvm::StringRef PragmaName, + SourceLocation PragmaLocation); + /// \brief Handle the annotation token produced for /// #pragma align... void HandlePragmaAlign(); diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ea9344d483..ce83089322 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -274,6 +274,15 @@ public: PVDK_Reset ///< #pragma vtordisp() }; + enum PragmaMsStackAction { + PSK_Reset, // #pragma () + PSK_Set, // #pragma ("name") + PSK_Push, // #pragma (push[, id]) + PSK_Push_Set, // #pragma (push[, id], "name") + PSK_Pop, // #pragma (pop[, id]) + PSK_Pop_Set, // #pragma (pop[, id], "name") + }; + /// \brief Whether to insert vtordisps prior to virtual bases in the Microsoft /// C++ ABI. Possible values are 0, 1, and 2, which mean: /// @@ -289,6 +298,35 @@ public: /// \brief Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; + template + struct PragmaStack { + struct Slot { + llvm::StringRef StackSlotLabel; + ValueType Value; + SourceLocation PragmaLocation; + Slot(llvm::StringRef StackSlotLabel, + ValueType Value, + SourceLocation PragmaLocation) + : StackSlotLabel(StackSlotLabel), Value(Value), + PragmaLocation(PragmaLocation) {} + }; + void Act(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + ValueType Value); + explicit PragmaStack(const ValueType &Value) + : CurrentValue(Value) {} + SmallVector Stack; + ValueType CurrentValue; + SourceLocation CurrentPragmaLocation; + }; + // FIXME: We should serialize / deserialize these if they occur in a PCH (but + // we shouldn't do so if they're in a module). + PragmaStack DataSegStack; + PragmaStack BSSSegStack; + PragmaStack ConstSegStack; + PragmaStack CodeSegStack; + /// VisContext - Manages the stack for \#pragma GCC visibility. void *VisContext; // Really a "PragmaVisStack*" @@ -7031,6 +7069,54 @@ public: void ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind, SourceLocation PragmaLoc, MSVtorDispAttr::Mode Value); + enum PragmaSectionKind { + PSK_DataSeg, + PSK_BSSSeg, + PSK_ConstSeg, + PSK_CodeSeg, + }; + + enum PragmaSectionFlag { + PSF_None = 0, + PSF_Read = 0x1, + PSF_Write = 0x2, + PSF_Execute = 0x4, + PSF_Implicit = 0x8, + PSF_Invalid = 0x80000000, + }; + + struct SectionInfo { + DeclaratorDecl *Decl; + SourceLocation PragmaSectionLocation; + int SectionFlags; + SectionInfo() = default; + SectionInfo(DeclaratorDecl *Decl, + SourceLocation PragmaSectionLocation, + int SectionFlags) + : Decl(Decl), + PragmaSectionLocation(PragmaSectionLocation), + SectionFlags(SectionFlags) {} + }; + + llvm::StringMap SectionInfos; + bool UnifySection(const StringRef &SectionName, + int SectionFlags, + DeclaratorDecl *TheDecl); + bool UnifySection(const StringRef &SectionName, + int SectionFlags, + SourceLocation PragmaSectionLocation); + + /// \brief Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg. + void ActOnPragmaMSSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName, + llvm::StringRef PragmaName); + + /// \brief Called on well formed \#pragma section(). + void ActOnPragmaMSSection(SourceLocation PragmaLocation, + int SectionFlags, StringLiteral *SegmentName); + /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index cef748f2aa..a04b33c627 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -2648,6 +2648,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } + if (Tok.is(tok::annot_pragma_ms_pragma)) { + HandlePragmaMSPragma(); + continue; + } + // If we see a namespace here, a close brace was missing somewhere. if (Tok.is(tok::kw_namespace)) { DiagnoseUnexpectedNamespace(cast(TagDecl)); diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 33c1f0b628..4b687a8b2e 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "RAIIObjectsForParser.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" @@ -124,8 +125,8 @@ struct PragmaMSVtorDisp : public PragmaHandler { Token &FirstToken) override; }; -struct PragmaMSInitSeg : public PragmaHandler { - explicit PragmaMSInitSeg() : PragmaHandler("init_seg") {} +struct PragmaMSPragma : public PragmaHandler { + explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {} void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken) override; }; @@ -181,8 +182,18 @@ void Parser::initializePragmaHandlers() { PP.AddPragmaHandler(MSPointersToMembers.get()); MSVtorDisp.reset(new PragmaMSVtorDisp()); PP.AddPragmaHandler(MSVtorDisp.get()); - MSInitSeg.reset(new PragmaMSInitSeg()); + MSInitSeg.reset(new PragmaMSPragma("init_seg")); PP.AddPragmaHandler(MSInitSeg.get()); + MSDataSeg.reset(new PragmaMSPragma("data_seg")); + PP.AddPragmaHandler(MSDataSeg.get()); + MSBSSSeg.reset(new PragmaMSPragma("bss_seg")); + PP.AddPragmaHandler(MSBSSSeg.get()); + MSConstSeg.reset(new PragmaMSPragma("const_seg")); + PP.AddPragmaHandler(MSConstSeg.get()); + MSCodeSeg.reset(new PragmaMSPragma("code_seg")); + PP.AddPragmaHandler(MSCodeSeg.get()); + MSSection.reset(new PragmaMSPragma("section")); + PP.AddPragmaHandler(MSSection.get()); } } @@ -224,6 +235,16 @@ void Parser::resetPragmaHandlers() { MSVtorDisp.reset(); PP.RemovePragmaHandler(MSInitSeg.get()); MSInitSeg.reset(); + PP.RemovePragmaHandler(MSDataSeg.get()); + MSDataSeg.reset(); + PP.RemovePragmaHandler(MSBSSSeg.get()); + MSBSSSeg.reset(); + PP.RemovePragmaHandler(MSConstSeg.get()); + MSConstSeg.reset(); + PP.RemovePragmaHandler(MSCodeSeg.get()); + MSCodeSeg.reset(); + PP.RemovePragmaHandler(MSSection.get()); + MSSection.reset(); } PP.RemovePragmaHandler("STDC", FPContractHandler.get()); @@ -410,6 +431,145 @@ void Parser::HandlePragmaMSVtorDisp() { Actions.ActOnPragmaMSVtorDisp(Kind, PragmaLoc, Mode); } +void Parser::HandlePragmaMSPragma() { + assert(Tok.is(tok::annot_pragma_ms_pragma)); + // Grab the tokens out of the annotation and enter them into the stream. + auto TheTokens = (std::pair *)Tok.getAnnotationValue(); + PP.EnterTokenStream(TheTokens->first, TheTokens->second, true, true); + SourceLocation PragmaLocation = ConsumeToken(); // The annotation token. + assert(Tok.isAnyIdentifier()); + llvm::StringRef PragmaName = Tok.getIdentifierInfo()->getName(); + PP.Lex(Tok); // pragma kind + // Figure out which #pragma we're dealing with. The switch has no default + // because lex shouldn't emit the annotation token for unrecognized pragmas. + typedef unsigned (Parser::*PragmaHandler)(llvm::StringRef, SourceLocation); + PragmaHandler Handler = llvm::StringSwitch(PragmaName) + .Case("data_seg", &Parser::HandlePragmaMSSegment) + .Case("bss_seg", &Parser::HandlePragmaMSSegment) + .Case("const_seg", &Parser::HandlePragmaMSSegment) + .Case("code_seg", &Parser::HandlePragmaMSSegment) + .Case("section", &Parser::HandlePragmaMSSection) + .Case("init_seg", &Parser::HandlePragmaMSInitSeg); + if (auto DiagID = (this->*Handler)(PragmaName, PragmaLocation)) { + PP.Diag(PragmaLocation, DiagID) << PragmaName; + while (Tok.isNot(tok::eof)) + PP.Lex(Tok); + PP.Lex(Tok); + } +} + +unsigned Parser::HandlePragmaMSSection(llvm::StringRef PragmaName, + SourceLocation PragmaLocation) { + if (Tok.isNot(tok::l_paren)) + return diag::warn_pragma_expected_lparen; + PP.Lex(Tok); // ( + // Parsing code for pragma section + if (Tok.isNot(tok::string_literal)) + return diag::warn_pragma_expected_section_name; + StringLiteral *SegmentName = + cast(ParseStringLiteralExpression().get()); + int SectionFlags = 0; + while (Tok.is(tok::comma)) { + PP.Lex(Tok); // , + if (!Tok.isAnyIdentifier()) + return diag::warn_pragma_expected_action_or_r_paren; + Sema::PragmaSectionFlag Flag = + llvm::StringSwitch( + Tok.getIdentifierInfo()->getName()) + .Case("read", Sema::PSF_Read) + .Case("write", Sema::PSF_Write) + .Case("execute", Sema::PSF_Execute) + .Case("shared", Sema::PSF_Invalid) + .Case("nopage", Sema::PSF_Invalid) + .Case("nocache", Sema::PSF_Invalid) + .Case("discard", Sema::PSF_Invalid) + .Case("remove", Sema::PSF_Invalid) + .Default(Sema::PSF_None); + if (Flag == Sema::PSF_None || Flag == Sema::PSF_Invalid) { + PP.Diag(PragmaLocation, Flag == Sema::PSF_None ? + diag::warn_pragma_invalid_specific_action : + diag::warn_pragma_unsupported_action) + << PragmaName << Tok.getIdentifierInfo()->getName(); + while (Tok.isNot(tok::eof)) + PP.Lex(Tok); + PP.Lex(Tok); + return 0; + } + SectionFlags |= Flag; + PP.Lex(Tok); // Identifier + } + if (Tok.isNot(tok::r_paren)) + return diag::warn_pragma_expected_rparen; + PP.Lex(Tok); // ) + if (Tok.isNot(tok::eof)) + return diag::warn_pragma_extra_tokens_at_eol; + PP.Lex(Tok); // eof + Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName); + return 0; +} + +unsigned Parser::HandlePragmaMSSegment(llvm::StringRef PragmaName, + SourceLocation PragmaLocation) { + if (Tok.isNot(tok::l_paren)) + return diag::warn_pragma_expected_lparen; + PP.Lex(Tok); // ( + Sema::PragmaMsStackAction Action = Sema::PSK_Reset; + llvm::StringRef SlotLabel; + if (Tok.isAnyIdentifier()) { + llvm::StringRef PushPop = Tok.getIdentifierInfo()->getName(); + if (PushPop == "push") + Action = Sema::PSK_Push; + else if (PushPop == "pop") + Action = Sema::PSK_Pop; + else + return diag::warn_pragma_expected_section_push_pop_or_name; + if (Action != Sema::PSK_Reset) { + PP.Lex(Tok); // push | pop + if (Tok.is(tok::comma)) { + PP.Lex(Tok); // , + // If we've got a comma, we either need a label or a string. + if (Tok.isAnyIdentifier()) { + SlotLabel = Tok.getIdentifierInfo()->getName(); + PP.Lex(Tok); // identifier + if (Tok.is(tok::comma)) + PP.Lex(Tok); + else if (Tok.isNot(tok::r_paren)) + return diag::warn_pragma_expected_punc; + } + } else if (Tok.isNot(tok::r_paren)) + return diag::warn_pragma_expected_punc; + } + } + // Grab the string literal for our section name. + StringLiteral *SegmentName = nullptr; + if (Tok.isNot(tok::r_paren)) { + if (Tok.isNot(tok::string_literal)) + return Action != Sema::PSK_Reset ? !SlotLabel.empty() ? + diag::warn_pragma_expected_section_name : + diag::warn_pragma_expected_section_label_or_name : + diag::warn_pragma_expected_section_push_pop_or_name; + SegmentName = cast(ParseStringLiteralExpression().get()); + // Setting section "" has no effect + if (SegmentName->getLength()) + Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); + } + if (Tok.isNot(tok::r_paren)) + return diag::warn_pragma_expected_rparen; + PP.Lex(Tok); // ) + if (Tok.isNot(tok::eof)) + return diag::warn_pragma_extra_tokens_at_eol; + PP.Lex(Tok); // eof + Actions.ActOnPragmaMSSeg(PragmaLocation, Action, SlotLabel, + SegmentName, PragmaName); + return 0; +} + +unsigned Parser::HandlePragmaMSInitSeg(llvm::StringRef PragmaName, + SourceLocation PragmaLocation) { + return PP.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Error, "'#pragma %0' not implemented."); +} + // #pragma GCC visibility comes in two variants: // 'push' '(' [visibility] ')' // 'pop' @@ -1214,12 +1374,31 @@ void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP, PP.EnterToken(AnnotTok); } -void PragmaMSInitSeg::HandlePragma(Preprocessor &PP, - PragmaIntroducerKind Introducer, - Token &Tok) { - unsigned ID = PP.getDiagnostics().getCustomDiagID( - DiagnosticsEngine::Error, "'#pragma init_seg' not implemented"); - PP.Diag(Tok.getLocation(), ID); +/// \brief Handle all MS pragmas. Simply forwards the tokens after inserting +/// an annotation token. +void PragmaMSPragma::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + Token EoF, AnnotTok; + EoF.startToken(); + EoF.setKind(tok::eof); + AnnotTok.startToken(); + AnnotTok.setKind(tok::annot_pragma_ms_pragma); + AnnotTok.setLocation(Tok.getLocation()); + SmallVector TokenVector; + // Suck up all of the tokens before the eod. + for (; Tok.isNot(tok::eod); PP.Lex(Tok)) + TokenVector.push_back(Tok); + // Add a sentinal EoF token to the end of the list. + TokenVector.push_back(EoF); + // We must allocate this array with new because EnterTokenStream is going to + // delete it later. + Token *TokenArray = new Token[TokenVector.size()]; + std::copy(TokenVector.begin(), TokenVector.end(), TokenArray); + auto Value = new (PP.getPreprocessorAllocator()) + std::pair(std::make_pair(TokenArray, TokenVector.size())); + AnnotTok.setAnnotationValue(Value); + PP.EnterToken(AnnotTok); } /// \brief Handle the Microsoft \#pragma detect_mismatch extension. diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 7254eb3c11..0fbb764fde 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -350,6 +350,10 @@ Retry: HandlePragmaMSPointersToMembers(); return StmtEmpty(); + case tok::annot_pragma_ms_pragma: + ProhibitAttributes(Attrs); + HandlePragmaMSPragma(); + return StmtEmpty(); } // If we reached this code, the statement must end in a semicolon. @@ -828,6 +832,9 @@ void Parser::ParseCompoundStatementLeadingPragmas() { case tok::annot_pragma_ms_pointers_to_members: HandlePragmaMSPointersToMembers(); break; + case tok::annot_pragma_ms_pragma: + HandlePragmaMSPragma(); + break; default: checkForPragmas = false; break; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 9936a5a3ab..9d3f251a55 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -631,6 +631,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::annot_pragma_ms_vtordisp: HandlePragmaMSVtorDisp(); return DeclGroupPtrTy(); + case tok::annot_pragma_ms_pragma: + HandlePragmaMSPragma(); + return DeclGroupPtrTy(); case tok::semi: // Either a C++11 empty-declaration or attribute-declaration. SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(), diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 3612bb962c..a0d64ac2af 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -79,7 +79,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), - VisContext(0), + DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr), + CodeSegStack(nullptr), VisContext(0), IsBuildingRecoveryCallExpr(false), ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0), IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0), diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 2e344ff930..f5905842fd 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -325,6 +325,112 @@ void Sema::ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind, } } +template +void Sema::PragmaStack::Act(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + ValueType Value) { + if (Action == PSK_Reset) { + CurrentValue = nullptr; + return; + } + if (Action & PSK_Push) + Stack.push_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation)); + else if (Action & PSK_Pop) { + if (!StackSlotLabel.empty()) { + // If we've got a label, try to find it and jump there. + auto I = std::find_if(Stack.rbegin(), Stack.rend(), + [&](const Slot &x) { return x.StackSlotLabel == StackSlotLabel; }); + // If we found the label so pop from there. + if (I != Stack.rend()) { + CurrentValue = I->Value; + CurrentPragmaLocation = I->PragmaLocation; + Stack.erase(std::prev(I.base()), Stack.end()); + } + } else if (!Stack.empty()) { + // We don't have a label, just pop the last entry. + CurrentValue = Stack.back().Value; + CurrentPragmaLocation = Stack.back().PragmaLocation; + Stack.pop_back(); + } + } + if (Action & PSK_Set) { + CurrentValue = Value; + CurrentPragmaLocation = PragmaLocation; + } +} + +bool Sema::UnifySection(const StringRef &SectionName, + int SectionFlags, + DeclaratorDecl *Decl) { + auto Section = SectionInfos.find(SectionName); + if (Section == SectionInfos.end()) { + SectionInfos[SectionName] = + SectionInfo(Decl, SourceLocation(), SectionFlags); + return false; + } + // A pre-declared section takes precedence w/o diagnostic. + if (Section->second.SectionFlags == SectionFlags || + !(Section->second.SectionFlags & PSF_Implicit)) + return false; + auto OtherDecl = Section->second.Decl; + Diag(Decl->getLocation(), diag::err_section_conflict) + << Decl << OtherDecl; + Diag(OtherDecl->getLocation(), diag::note_declared_at) + << OtherDecl->getName(); + if (auto A = Decl->getAttr()) + if (A->isImplicit()) + Diag(A->getLocation(), diag::note_pragma_entered_here); + if (auto A = OtherDecl->getAttr()) + if (A->isImplicit()) + Diag(A->getLocation(), diag::note_pragma_entered_here); + return false; +} + +bool Sema::UnifySection(const StringRef &SectionName, + int SectionFlags, + SourceLocation PragmaSectionLocation) { + auto Section = SectionInfos.find(SectionName); + if (Section != SectionInfos.end()) { + if (Section->second.SectionFlags == SectionFlags) + return false; + if (!(Section->second.SectionFlags & PSF_Implicit)) { + Diag(PragmaSectionLocation, diag::err_section_conflict) + << "this" << "a prior #pragma section"; + Diag(Section->second.PragmaSectionLocation, + diag::note_pragma_entered_here); + return true; + } + } + SectionInfos[SectionName] = + SectionInfo(nullptr, PragmaSectionLocation, SectionFlags); + return false; +} + +/// \brief Called on well formed \#pragma bss_seg(). +void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName, + llvm::StringRef PragmaName) { + PragmaStack *Stack = + llvm::StringSwitch *>(PragmaName) + .Case("data_seg", &DataSegStack) + .Case("bss_seg", &BSSSegStack) + .Case("const_seg", &ConstSegStack) + .Case("code_seg", &CodeSegStack); + if (Action & PSK_Pop && Stack->Stack.empty()) + Diag(PragmaLocation, diag::warn_pragma_pop_failed) << PragmaName + << "stack empty"; + Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName); +} + +/// \brief Called on well formed \#pragma bss_seg(). +void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation, + int SectionFlags, StringLiteral *SegmentName) { + UnifySection(SegmentName->getString(), SectionFlags, PragmaLocation); +} + void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, SourceLocation PragmaLoc) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 6a013a7138..cc461ef141 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7059,6 +7059,17 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setInvalidDecl(); } + if (D.isFunctionDefinition() && CodeSegStack.CurrentValue && + !NewFD->hasAttr()) { + NewFD->addAttr( + SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate, + CodeSegStack.CurrentValue->getString(), + CodeSegStack.CurrentPragmaLocation)); + if (UnifySection(CodeSegStack.CurrentValue->getString(), + PSF_Implicit | PSF_Execute | PSF_Read, NewFD)) + NewFD->dropAttr(); + } + // Handle attributes. ProcessDeclAttributes(S, NewFD, D); @@ -8929,6 +8940,29 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Diag(var->getLocation(), diag::note_use_thread_local); } + if (var->isThisDeclarationADefinition() && + ActiveTemplateInstantiations.empty()) { + PragmaStack *Stack = nullptr; + int SectionFlags = PSF_Implicit | PSF_Read; + if (var->getType().isConstQualified()) + Stack = &ConstSegStack; + else if (!var->getInit()) { + Stack = &BSSSegStack; + SectionFlags |= PSF_Write; + } else { + Stack = &DataSegStack; + SectionFlags |= PSF_Write; + } + if (!var->hasAttr() && Stack->CurrentValue) + var->addAttr( + SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate, + Stack->CurrentValue->getString(), + Stack->CurrentPragmaLocation)); + if (const SectionAttr *SA = var->getAttr()) + if (UnifySection(SA->getName(), SectionFlags, var)) + var->dropAttr(); + } + // All the following checks are C++ only. if (!getLangOpts().CPlusPlus) return; diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 3f37efa7c1..75dc5cfd90 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1969,8 +1969,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc)); if (const SectionAttr *SA = property->getAttr()) - GetterMethod->addAttr(SectionAttr::CreateImplicit(Context, SA->getName(), - Loc)); + GetterMethod->addAttr( + SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section, + SA->getName(), Loc)); if (getLangOpts().ObjCAutoRefCount) CheckARCMethodDecl(GetterMethod); @@ -2022,8 +2023,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, if (lexicalDC) SetterMethod->setLexicalDeclContext(lexicalDC); if (const SectionAttr *SA = property->getAttr()) - SetterMethod->addAttr(SectionAttr::CreateImplicit(Context, - SA->getName(), Loc)); + SetterMethod->addAttr( + SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section, + SA->getName(), Loc)); // It's possible for the user to have set a very odd custom // setter selector that causes it to have a method family. if (getLangOpts().ObjCAutoRefCount) diff --git a/test/CodeGen/function-sections.c b/test/CodeGen/function-sections.c new file mode 100644 index 0000000000..7994acf4dc --- /dev/null +++ b/test/CodeGen/function-sections.c @@ -0,0 +1,28 @@ +// REQUIRES: x86-registered-target + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -o - < %s | FileCheck %s --check-prefix=PLAIN +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -fno-function-sections -o - < %s | FileCheck %s --check-prefix=PLAIN + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-function-sections -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-data-sections -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT + +const int hello = 123; +void world() {} + +// PLAIN-NOT: section +// PLAIN: world: +// PLAIN: section .rodata, +// PLAIN: hello: + +// FUNC_SECT: section .text.world, +// FUNC_SECT: world: +// FUNC_SECT: section .rodata, +// FUNC_SECT: hello: + +// DATA_SECT-NOT: section +// DATA_SECT: world: +// DATA_SECT: .section .rodata.hello, +// DATA_SECT: hello: diff --git a/test/CodeGen/sections.c b/test/CodeGen/sections.c index 7994acf4dc..6e44e77f5b 100644 --- a/test/CodeGen/sections.c +++ b/test/CodeGen/sections.c @@ -1,28 +1,51 @@ -// REQUIRES: x86-registered-target +// RUN: %clang_cc1 -emit-llvm -fms-extensions -xc++ -o - < %s | FileCheck %s -// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -o - < %s | FileCheck %s --check-prefix=PLAIN -// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -fno-function-sections -o - < %s | FileCheck %s --check-prefix=PLAIN +#ifdef __cplusplus +extern "C" { +#endif +#pragma const_seg(".my_const") +#pragma bss_seg(".my_bss") +int D = 1; +#pragma data_seg(".data") +int a = 1; +#pragma data_seg(push, label, ".data2") +extern const int b; +const int b = 1; +const char* s = "my string!"; +#pragma data_seg(push, ".my_seg") +int c = 1; +#pragma data_seg(pop, label) +int d = 1; +int e; +#pragma bss_seg(".c") +int f; +void g(void){} +#pragma code_seg(".my_code") +void h(void){} +#pragma bss_seg() +int i; +#pragma bss_seg(".bss1") +#pragma bss_seg(push, test, ".bss2") +#pragma bss_seg() +#pragma bss_seg() +int TEST1; +#pragma bss_seg(pop) +int TEST2; +#ifdef __cplusplus +} +#endif -// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT -// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-function-sections -ffunction-sections -o - < %s | FileCheck %s --check-prefix=FUNC_SECT - -// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT -// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S -fno-data-sections -fdata-sections -o - < %s | FileCheck %s --check-prefix=DATA_SECT - -const int hello = 123; -void world() {} - -// PLAIN-NOT: section -// PLAIN: world: -// PLAIN: section .rodata, -// PLAIN: hello: - -// FUNC_SECT: section .text.world, -// FUNC_SECT: world: -// FUNC_SECT: section .rodata, -// FUNC_SECT: hello: - -// DATA_SECT-NOT: section -// DATA_SECT: world: -// DATA_SECT: .section .rodata.hello, -// DATA_SECT: hello: +//CHECK: @D = global i32 1 +//CHECK: @a = global i32 1, section ".data" +//CHECK: @b = constant i32 1, section ".my_const" +//CHECK: @[[MYSTR:.*]] = linkonce_odr unnamed_addr constant [11 x i8] c"my string!\00" +//CHECK: @s = global i8* getelementptr inbounds ([11 x i8]* @[[MYSTR]], i32 0, i32 0), section ".data2" +//CHECK: @c = global i32 1, section ".my_seg" +//CHECK: @d = global i32 1, section ".data" +//CHECK: @e = global i32 0, section ".my_bss" +//CHECK: @f = global i32 0, section ".c" +//CHECK: @i = global i32 0 +//CHECK: @TEST1 = global i32 0 +//CHECK: @TEST2 = global i32 0, section ".bss1" +//CHECK: define void @g() +//CHECK: define void @h() {{.*}} section ".my_code" diff --git a/test/Sema/pragma-section.c b/test/Sema/pragma-section.c new file mode 100644 index 0000000000..3b6147b093 --- /dev/null +++ b/test/Sema/pragma-section.c @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s + +#pragma const_seg(".my_const") // expected-note 2 {{#pragma entered here}} +extern const int a; +const int a = 1; // expected-note 2 {{declared here}} +#pragma data_seg(".my_const") // expected-note {{#pragma entered here}} +int b = 1; // expected-error {{'b' causes a section type conflict with 'a'}} +#pragma data_seg() +int c = 1; +__declspec(allocate(".my_const")) int d = 1; // expected-error {{'d' causes a section type conflict with 'a'}} + +#pragma section(".my_seg", execute) // expected-note 2 {{#pragma entered her}} +__declspec(allocate(".my_seg")) int int_my_seg; +#pragma code_seg(".my_seg") +void fn_my_seg(void){} + +__declspec(allocate(".bad_seg")) int int_bad_seg = 1; // expected-note {{declared here}} +#pragma code_seg(".bad_seg") // expected-note {{#pragma entered here}} +void fn_bad_seg(void){} // expected-error {{'fn_bad_seg' causes a section type conflict with 'int_bad_seg'}} + +#pragma bss_seg // expected-warning {{missing '(' after '#pragma bss_seg' - ignoring}} +#pragma bss_seg(L".my_seg") // expected-warning {{expected push, pop or a string literal for the section name in '#pragma bss_seg' - ignored}} +#pragma bss_seg(1) // expected-warning {{expected push, pop or a string literal for the section name in '#pragma bss_seg' - ignored}} +#pragma bss_seg(push) +#pragma bss_seg(push, ".my_seg") +#pragma bss_seg(push, 1) // expected-warning {{expected a stack label or a string literal for the section name in '#pragma bss_seg'}} +#pragma bss_seg ".my_seg" // expected-warning {{missing '(' after '#pragma bss_seg' - ignoring}} +#pragma bss_seg(push, my_label, 1) // expected-warning {{expected a string literal for the section name in '#pragma bss_seg' - ignored}} +#pragma bss_seg(".my_seg", 1) // expected-warning {{missing ')' after '#pragma bss_seg' - ignoring}} +#pragma bss_seg(".my_seg" // expected-warning {{missing ')' after '#pragma bss_seg' - ignoring}} + +#pragma section // expected-warning {{missing '(' after '#pragma section' - ignoring}} +#pragma section( // expected-warning {{expected a string literal for the section name in '#pragma section' - ignored}} +#pragma section(L".my_seg") // expected-warning {{expected a string literal for the section name in '#pragma section' - ignored}} +#pragma section(".my_seg" // expected-warning {{missing ')' after '#pragma section' - ignoring}} +#pragma section(".my_seg" 1 // expected-warning {{missing ')' after '#pragma section' - ignoring}} +#pragma section(".my_seg", // expected-warning {{expected action or ')' in '#pragma section' - ignored}} +#pragma section(".my_seg", read) // expected-error {{this causes a section type conflict with a prior #pragma section}} +#pragma section(".my_seg", bogus) // expected-warning {{unknown action 'bogus' for '#pragma section' - ignored}} +#pragma section(".my_seg", nopage) // expected-warning {{known but unsupported action 'nopage' for '#pragma section' - ignored}} +#pragma section(".my_seg", read, write) // expected-error {{this causes a section type conflict with a prior #pragma section}} +#pragma section(".my_seg", read, write, 1) // expected-warning {{expected action or ')' in '#pragma section' - ignored}}