mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-04 16:26:46 +00:00
[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 llvm-svn: 205810
This commit is contained in:
parent
f7813c56b4
commit
c3b18967ed
@ -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;
|
||||
|
@ -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 = [{
|
||||
|
@ -771,6 +771,15 @@ def warn_pragma_expected_rparen : Warning<
|
||||
"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>;
|
||||
@ -793,6 +802,15 @@ def warn_pragma_align_invalid_option : Warning<
|
||||
"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>;
|
||||
|
@ -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<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'">,
|
||||
|
@ -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.
|
||||
|
@ -155,6 +155,11 @@ class Parser : public CodeCompletionHandler {
|
||||
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;
|
||||
|
||||
@ -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();
|
||||
|
@ -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<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*"
|
||||
|
||||
@ -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<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);
|
||||
|
||||
|
@ -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<NamedDecl>(TagDecl));
|
||||
|
@ -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<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'
|
||||
@ -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<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.
|
||||
|
@ -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;
|
||||
|
@ -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(),
|
||||
|
@ -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),
|
||||
|
@ -325,6 +325,112 @@ void Sema::ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind,
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
|
@ -7059,6 +7059,17 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||
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);
|
||||
|
||||
@ -8929,6 +8940,29 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
|
||||
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;
|
||||
|
||||
|
@ -1969,8 +1969,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
|
||||
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);
|
||||
@ -2022,8 +2023,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property,
|
||||
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)
|
||||
|
28
clang/test/CodeGen/function-sections.c
Normal file
28
clang/test/CodeGen/function-sections.c
Normal file
@ -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:
|
@ -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"
|
||||
|
42
clang/test/Sema/pragma-section.c
Normal file
42
clang/test/Sema/pragma-section.c
Normal file
@ -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}}
|
Loading…
x
Reference in New Issue
Block a user