Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -1716,6 +1716,24 @@ let Documentation = [MSInheritanceDocs]; } +def MSSegment : Attr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let Args = [StringArgument<"SegName">, UnsignedArgument<"kind">]; + + let AdditionalMembers = [{ + enum Kind { + DataSeg, + BSSSeg, + ConstSeg, + CodeSeg + }; + + Kind getSegKind() const { return Kind(kind); } + }]; + let Documentation = [Undocumented]; +} + def MSVtorDisp : InheritableAttr { // This attribute has no spellings as it is only ever created implicitly. let Spellings = []; Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -771,6 +771,8 @@ "missing ')' after '#pragma %0' - ignoring">, InGroup; def warn_pragma_expected_identifier : Warning< "expected identifier in '#pragma %0' - ignored">, InGroup; +def warn_pragma_expected_string : Warning< + "expected string literal in '#pragma %0' - ignored">, InGroup; def warn_pragma_expected_integer : Warning< "expected integer between %0 and %1 inclusive in '#pragma %2' - ignored">, InGroup; 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 @@ -154,6 +154,10 @@ std::unique_ptr MSDetectMismatchHandler; std::unique_ptr MSPointersToMembers; std::unique_ptr MSVtorDisp; + std::unique_ptr MSDataSeg; + std::unique_ptr MSBSSSeg; + std::unique_ptr MSConstSeg; + std::unique_ptr MSCodeSeg; std::unique_ptr CommentSemaHandler; @@ -475,6 +479,8 @@ void HandlePragmaMSVtorDisp(); + void HandlePragmaMSPragma(); + /// \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,30 @@ /// \brief Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; + template + struct PragmaStack { + struct Slot { + llvm::StringRef StackSlotLabel; + ValueType Value; + SourceLocation 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*" @@ -7030,6 +7063,30 @@ void ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind, SourceLocation PragmaLoc, MSVtorDispAttr::Mode Value); + /// \brief Called on well formed \#pragma data_seg(). + void ActOnPragmaMSDataSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName); + + /// \brief Called on well formed \#pragma bss_seg(). + void ActOnPragmaMSBSSSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName); + + /// \brief Called on well formed \#pragma const_seg(). + void ActOnPragmaMSConstSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName); + + /// \brief Called on well formed \#pragma code_seg(). + void ActOnPragmaMSCodeSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName); + /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch void ActOnPragmaDetectMismatch(StringRef Name, StringRef Value); Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -704,6 +704,9 @@ if (const SectionAttr *SA = D->getAttr()) GV->setSection(SA->getName()); + if (D->hasAttr()) + GV->setSection(D->getAttr()->getSegName()); + // Alias cannot have attributes. Filter them here. if (!isa(GV)) getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this); Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -2646,6 +2646,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,6 +125,12 @@ Token &FirstToken) override; }; +struct PragmaMSPragma : public PragmaHandler { + explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {} + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + } // end namespace void Parser::initializePragmaHandlers() { @@ -175,6 +182,14 @@ PP.AddPragmaHandler(MSPointersToMembers.get()); MSVtorDisp.reset(new PragmaMSVtorDisp()); PP.AddPragmaHandler(MSVtorDisp.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()); } } @@ -214,6 +229,14 @@ MSPointersToMembers.reset(); PP.RemovePragmaHandler(MSVtorDisp.get()); MSVtorDisp.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("STDC", FPContractHandler.get()); @@ -400,6 +423,96 @@ 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 PragmaLoc = ConsumeToken(); // The annotation token. + assert(Tok.isAnyIdentifier()); + llvm::StringRef PragmaName = Tok.getIdentifierInfo()->getName(); + // Note! BalancedDelimiterTracker throws an error if it fails to match + // correctly. This is different than MSVCs behvaior that malformed pragmas + // are ignored with a warning. + BalancedDelimiterTracker Parens(*this, tok::l_paren, tok::eof); + 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. + enum PragmaMSKind { DataSeg, BSSSeg, ConstSeg, CodeSeg } Kind = + llvm::StringSwitch(PragmaName) + .Case("data_seg", DataSeg) + .Case("bss_seg", BSSSeg) + .Case("const_seg", ConstSeg) + .Case("code_seg", CodeSeg); + llvm::StringRef SlotLabel; + if (Parens.consumeOpen()) + goto ERROR_RETURN; + Sema::PragmaMsStackAction Action = Sema::PSK_Reset; + 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 { + PP.Diag(PragmaLoc, diag::warn_pragma_invalid_action) << PragmaName; + goto ERROR_RETURN; + } + 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 + 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)) { + PP.Diag(PragmaLoc, diag::warn_pragma_expected_punc) << PragmaName; + goto ERROR_RETURN; + } + } + } else if (Tok.isNot(tok::r_paren)) { + PP.Diag(PragmaLoc, diag::warn_pragma_expected_punc) << PragmaName; + goto ERROR_RETURN; + } + } + } + // Grab the string literal for our section name. + StringLiteral *SegmentName = nullptr; + if (Tok.isNot(tok::r_paren)) { + ExprResult SegmentNameExpr = ParseStringLiteralExpression(); + if (SegmentNameExpr.isInvalid()) { + PP.Diag(PragmaLoc, diag::warn_pragma_expected_string) << PragmaName; + goto ERROR_RETURN; + } + SegmentName = cast(SegmentNameExpr.get()); + // Setting section "" has no effect + if (SegmentName->getLength()) + Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); + } + if (Parens.consumeClose()) + goto ERROR_RETURN; + if (Tok.isNot(tok::eof)) { + PP.Diag(PragmaLoc, diag::warn_pragma_extra_tokens_at_eol) << PragmaName; + goto ERROR_RETURN; + } + PP.Lex(Tok); // eof + if (Kind == DataSeg) + Actions.ActOnPragmaMSDataSeg(PragmaLoc, Action, SlotLabel, SegmentName); + else if (Kind == BSSSeg) + Actions.ActOnPragmaMSBSSSeg(PragmaLoc, Action, SlotLabel, SegmentName); + else if (Kind == ConstSeg) + Actions.ActOnPragmaMSConstSeg(PragmaLoc, Action, SlotLabel, SegmentName); + else if (Kind == CodeSeg) + Actions.ActOnPragmaMSCodeSeg(PragmaLoc, Action, SlotLabel, SegmentName); + return; +ERROR_RETURN: + SkipUntil(tok::eof); + PP.Lex(Tok); // tok::eof +} + // #pragma GCC visibility comes in two variants: // 'push' '(' [visibility] ')' // 'pop' @@ -1204,6 +1317,33 @@ PP.EnterToken(AnnotTok); } +/// \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()]; + memcpy(TokenArray, TokenVector.data(), sizeof(Token) * TokenVector.size()); + 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. /// /// The syntax is: 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,102 @@ } } +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({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; + } +} + +/// \brief Called on well formed \#pragma bss_seg(). +void Sema::ActOnPragmaMSBSSSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName) { + if (Action & PSK_Pop && BSSSegStack.Stack.empty()) + Diag(PragmaLocation, diag::warn_pragma_pop_failed) << "bss_seg" + << "stack empty"; + BSSSegStack.Act(PragmaLocation, Action, StackSlotLabel, SegmentName); +} + +/// \brief Called on well formed \#pragma data_seg(). +void Sema::ActOnPragmaMSDataSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName) { + if (Action & PSK_Pop && DataSegStack.Stack.empty()) + Diag(PragmaLocation, diag::warn_pragma_pop_failed) << "data_seg" + << "stack empty"; + DataSegStack.Act(PragmaLocation, Action, StackSlotLabel, SegmentName); +} + +/// \brief Called on well formed \#pragma bss_seg(). +void Sema::ActOnPragmaMSConstSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName) { + if (Action & PSK_Pop && ConstSegStack.Stack.empty()) + Diag(PragmaLocation, diag::warn_pragma_pop_failed) << "const_seg" + << "stack empty"; + ConstSegStack.Act(PragmaLocation, Action, StackSlotLabel, SegmentName); +} + +/// \brief Called on well formed \#pragma code_seg(). +void Sema::ActOnPragmaMSCodeSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName) { + if (Action & PSK_Pop && CodeSegStack.Stack.empty()) + Diag(PragmaLocation, diag::warn_pragma_pop_failed) << "code_seg" + << "stack empty"; + CodeSegStack.Act(PragmaLocation, Action, StackSlotLabel, SegmentName); +} + void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, SourceLocation PragmaLoc) { Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -6974,6 +6974,11 @@ NewFD->setInvalidDecl(); } + if (D.isFunctionDefinition() && CodeSegStack.CurrentValue) + NewFD->addAttr(MSSegmentAttr::CreateImplicit( + Context, CodeSegStack.CurrentValue->getString(), + MSSegmentAttr::CodeSeg, CodeSegStack.CurrentPragmaLocation)); + // Handle attributes. ProcessDeclAttributes(S, NewFD, D); @@ -8838,6 +8843,26 @@ Diag(var->getLocation(), diag::note_use_thread_local); } + if (var->isThisDeclarationADefinition() && + ActiveTemplateInstantiations.empty()) { + if (var->getType().isConstQualified()) { + if (ConstSegStack.CurrentValue) + var->addAttr(MSSegmentAttr::CreateImplicit( + Context, ConstSegStack.CurrentValue->getString(), + MSSegmentAttr::ConstSeg, ConstSegStack.CurrentPragmaLocation)); + } + else if (!var->getInit()) { + if (BSSSegStack.CurrentValue) + var->addAttr(MSSegmentAttr::CreateImplicit( + Context, BSSSegStack.CurrentValue->getString(), + MSSegmentAttr::BSSSeg, BSSSegStack.CurrentPragmaLocation)); + } + else if (DataSegStack.CurrentValue) + var->addAttr(MSSegmentAttr::CreateImplicit( + Context, DataSegStack.CurrentValue->getString(), + MSSegmentAttr::DataSeg, DataSegStack.CurrentPragmaLocation)); + } + // All the following checks are C++ only. if (!getLangOpts().CPlusPlus) return;