}
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,
Keyword<"__multiple_inheritance">,
Keyword<"__virtual_inheritance">,
Keyword<"__unspecified_inheritance">];
+ let Documentation = [SectionDocs];
let AdditionalMembers = [{
static bool hasVBPtrOffsetField(Spelling Inheritance) {
return Inheritance == Keyword_unspecified_inheritance;
}];
}
+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 = [{
"missing ')' after '#pragma %0' - ignoring">, InGroup<IgnoredPragmas>;
def warn_pragma_expected_identifier : Warning<
"expected identifier in '#pragma %0' - ignored">, InGroup<IgnoredPragmas>;
+def warn_pragma_expected_section_name : Warning<
+ "expected a string literal for the section name in '#pragma %0' - ignored">,
+ InGroup<IgnoredPragmas>;
+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<IgnoredPragmas>;
+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<IgnoredPragmas>;
def warn_pragma_expected_integer : Warning<
"expected integer between %0 and %1 inclusive in '#pragma %2' - ignored">,
InGroup<IgnoredPragmas>;
"invalid alignment option in '#pragma %select{align|options align}0' - ignored">,
InGroup<IgnoredPragmas>;
// - #pragma pack
+def warn_pragma_unsupported_action : Warning<
+ "known but unsupported action '%1' for '#pragma %0' - ignored">,
+ InGroup<IgnoredPragmas>;
+def warn_pragma_invalid_specific_action : Warning<
+ "unknown action '%1' for '#pragma %0' - ignored">,
+ InGroup<IgnoredPragmas>;
+def warn_pragma_expected_action_or_r_paren : Warning<
+ "expected action or ')' in '#pragma %0' - ignored">,
+ InGroup<IgnoredPragmas>;
def warn_pragma_invalid_action : Warning<
"unknown action for '#pragma %0' - ignored">,
InGroup<IgnoredPragmas>;
Warning<"ms_struct may not produce MSVC-compatible layouts for classes "
"with base classes or virtual functions">,
DefaultError, InGroup<IncompatibleMSStruct>;
+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'">,
// 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.
std::unique_ptr<PragmaHandler> MSPointersToMembers;
std::unique_ptr<PragmaHandler> MSVtorDisp;
std::unique_ptr<PragmaHandler> MSInitSeg;
+ std::unique_ptr<PragmaHandler> MSDataSeg;
+ std::unique_ptr<PragmaHandler> MSBSSSeg;
+ std::unique_ptr<PragmaHandler> MSConstSeg;
+ std::unique_ptr<PragmaHandler> MSCodeSeg;
+ std::unique_ptr<PragmaHandler> MSSection;
std::unique_ptr<CommentHandler> CommentSemaHandler;
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();
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:
///
/// \brief Source location for newly created implicit MSInheritanceAttrs
SourceLocation ImplicitMSInheritanceAttrLoc;
+ template<typename ValueType>
+ 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<Slot, 2> 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<StringLiteral *> DataSegStack;
+ PragmaStack<StringLiteral *> BSSSegStack;
+ PragmaStack<StringLiteral *> ConstSegStack;
+ PragmaStack<StringLiteral *> CodeSegStack;
+
/// VisContext - Manages the stack for \#pragma GCC visibility.
void *VisContext; // Really a "PragmaVisStack*"
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<SectionInfo> 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);
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<NamedDecl>(TagDecl));
//
//===----------------------------------------------------------------------===//
+#include "RAIIObjectsForParser.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
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;
};
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());
}
}
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());
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<Token*, size_t> *)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<PragmaHandler>(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<StringLiteral>(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<Sema::PragmaSectionFlag>(
+ 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<StringLiteral>(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'
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<Token, 8> 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<Token*, size_t>(std::make_pair(TokenArray, TokenVector.size()));
+ AnnotTok.setAnnotationValue(Value);
+ PP.EnterToken(AnnotTok);
}
/// \brief Handle the Microsoft \#pragma detect_mismatch extension.
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.
case tok::annot_pragma_ms_pointers_to_members:
HandlePragmaMSPointersToMembers();
break;
+ case tok::annot_pragma_ms_pragma:
+ HandlePragmaMSPragma();
+ break;
default:
checkForPragmas = false;
break;
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(),
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),
}
}
+template<typename ValueType>
+void Sema::PragmaStack<ValueType>::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<SectionAttr>())
+ if (A->isImplicit())
+ Diag(A->getLocation(), diag::note_pragma_entered_here);
+ if (auto A = OtherDecl->getAttr<SectionAttr>())
+ 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<StringLiteral *> *Stack =
+ llvm::StringSwitch<PragmaStack<StringLiteral *> *>(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) {
NewFD->setInvalidDecl();
}
+ if (D.isFunctionDefinition() && CodeSegStack.CurrentValue &&
+ !NewFD->hasAttr<SectionAttr>()) {
+ 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<SectionAttr>();
+ }
+
// Handle attributes.
ProcessDeclAttributes(S, NewFD, D);
Diag(var->getLocation(), diag::note_use_thread_local);
}
+ if (var->isThisDeclarationADefinition() &&
+ ActiveTemplateInstantiations.empty()) {
+ PragmaStack<StringLiteral *> *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<SectionAttr>() && Stack->CurrentValue)
+ var->addAttr(
+ SectionAttr::CreateImplicit(Context, SectionAttr::Declspec_allocate,
+ Stack->CurrentValue->getString(),
+ Stack->CurrentPragmaLocation));
+ if (const SectionAttr *SA = var->getAttr<SectionAttr>())
+ if (UnifySection(SA->getName(), SectionFlags, var))
+ var->dropAttr<SectionAttr>();
+ }
+
// All the following checks are C++ only.
if (!getLangOpts().CPlusPlus) return;
ObjCReturnsInnerPointerAttr::CreateImplicit(Context, Loc));
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
- GetterMethod->addAttr(SectionAttr::CreateImplicit(Context, SA->getName(),
- Loc));
+ GetterMethod->addAttr(
+ SectionAttr::CreateImplicit(Context, SectionAttr::GNU_section,
+ SA->getName(), Loc));
if (getLangOpts().ObjCAutoRefCount)
CheckARCMethodDecl(GetterMethod);
if (lexicalDC)
SetterMethod->setLexicalDeclContext(lexicalDC);
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
- 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)
--- /dev/null
+// 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:
-// 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"
--- /dev/null
+// 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}}