Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -1075,7 +1075,7 @@ } 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 @@ Keyword<"__multiple_inheritance">, Keyword<"__virtual_inheritance">, Keyword<"__unspecified_inheritance">]; + let Documentation = [SectionDocs]; let AdditionalMembers = [{ static bool hasVBPtrOffsetField(Spelling Inheritance) { return Inheritance == Keyword_unspecified_inheritance; Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -27,6 +27,14 @@ }]; } +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 = [{ Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -771,6 +771,15 @@ "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 '#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 @@ "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; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -521,6 +521,7 @@ 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'">, Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -684,6 +684,11 @@ // 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. Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -155,6 +155,11 @@ 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 @@ 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(); Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -274,6 +274,15 @@ 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 @@ /// \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 @@ void ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind, SourceLocation PragmaLoc, MSVtorDispAttr::Mode Value); + enum PragmaMSKind { + PSK_DataSeg, + PSK_BSSSeg, + PSK_ConstSeg, + PSK_CodeSeg, + }; + + enum PragmaSectionFlag { + PSF_None = 0, + PSF_Read = 1, + PSF_Write = 2, + PSF_Execute = 4, + PSF_Implicit = 8, + PSF_Invalid = 0x80000000, + }; + + struct SectionInfo { + DeclaratorDecl *Decl; + SourceLocation PragmaSectionLocation; + int SectionFlags; + SectionInfo() {} + 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); Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -2648,6 +2648,11 @@ 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)); Index: lib/Parse/ParsePragma.cpp =================================================================== --- lib/Parse/ParsePragma.cpp +++ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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. Index: lib/Parse/ParseStmt.cpp =================================================================== --- lib/Parse/ParseStmt.cpp +++ lib/Parse/ParseStmt.cpp @@ -350,6 +350,10 @@ 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 @@ case tok::annot_pragma_ms_pointers_to_members: HandlePragmaMSPointersToMembers(); break; + case tok::annot_pragma_ms_pragma: + HandlePragmaMSPragma(); + break; default: checkForPragmas = false; break; Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -631,6 +631,9 @@ 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(), Index: lib/Sema/Sema.cpp =================================================================== --- lib/Sema/Sema.cpp +++ lib/Sema/Sema.cpp @@ -79,7 +79,8 @@ 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), Index: lib/Sema/SemaAttr.cpp =================================================================== --- lib/Sema/SemaAttr.cpp +++ lib/Sema/SemaAttr.cpp @@ -325,6 +325,128 @@ } } +template Type +PopToName(std::vector& Stack, llvm::StringRef Key) { + if (!ActionTarget.empty()) { + auto I = std::find_if(DataSegStack.rbegin(), DataSegStack.rend(), + [&](const std::pair &x) { + return x.first == ActionTarget; + }); + CurrentDataSegment = I->second; + if (I != DataSegStack.rend()) + DataSegStack.erase(std::prev(I.base()), DataSegStack.end()); + } else if (!DataSegStack.empty()) { + CurrentDataSegment = DataSegStack.back().second; + DataSegStack.pop_back(); + } +} + +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) { Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -7059,6 +7059,17 @@ 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 @@ 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; Index: lib/Sema/SemaObjCProperty.cpp =================================================================== --- lib/Sema/SemaObjCProperty.cpp +++ lib/Sema/SemaObjCProperty.cpp @@ -1969,8 +1969,9 @@ 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 @@ 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) Index: test/CodeGen/function-sections.c =================================================================== --- /dev/null +++ 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: Index: test/CodeGen/sections.c =================================================================== --- test/CodeGen/sections.c +++ 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" Index: test/Sema/pragma-section.c =================================================================== --- /dev/null +++ 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 '#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 '#pragma section' - ignored}} +#pragma section(L".my_seg") // expected-warning {{expected a string literal for the section name '#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}}