diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -984,6 +984,9 @@ def err_super_in_lambda_unsupported : Error< "use of '__super' inside a lambda is unsupported">; +def err_pragma_alloc_text_scope : Error< + "'#pragma alloc_text' can't be used inside a function">; + def warn_pragma_unused_undeclared_var : Warning< "undeclared variable %0 used as an argument for '#pragma unused'">, InGroup; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -198,6 +198,7 @@ std::unique_ptr MSIntrinsic; std::unique_ptr MSOptimize; std::unique_ptr MSFenvAccess; + std::unique_ptr MSAllocText; std::unique_ptr CUDAForceHostDeviceHandler; std::unique_ptr OptimizeHandler; std::unique_ptr LoopHintHandler; @@ -720,6 +721,8 @@ SourceLocation PragmaLocation); bool HandlePragmaMSInitSeg(StringRef PragmaName, SourceLocation PragmaLocation); + bool HandlePragmaMSAllocText(StringRef PragmaName, + SourceLocation PragmaLocation); /// Handle the annotation token produced for /// #pragma align... diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -724,6 +724,9 @@ StringLiteral *CurInitSeg; SourceLocation CurInitSegLoc; + /// Sections used with #pragma alloc_text + llvm::StringMap FunctionToSectionMap; + /// VisContext - Manages the stack for \#pragma GCC visibility. void *VisContext; // Really a "PragmaVisStack*" @@ -10189,6 +10192,11 @@ void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation, StringLiteral *SegmentName); + /// Called on well-formed \#pragma alloc_text(). + void ActOnPragmaMSAllocText(SourceLocation PragmaLocation, + StringRef Section, + const SmallVector &Functions); + /// Called on #pragma clang __debug dump II void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II); @@ -10325,6 +10333,8 @@ /// with attribute optnone. void AddRangeBasedOptnone(FunctionDecl *FD); + void AddSectionMSAllocText(FunctionDecl *FD); + /// Adds the 'optnone' attribute to the function declaration if there /// are no conflicts; Loc represents the location causing the 'optnone' /// attribute to be added (usually because of a pragma). diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -445,6 +445,8 @@ PP.AddPragmaHandler(MSCodeSeg.get()); MSSection = std::make_unique("section"); PP.AddPragmaHandler(MSSection.get()); + MSAllocText = std::make_unique("alloc_text"); + PP.AddPragmaHandler(MSAllocText.get()); MSRuntimeChecks = std::make_unique(); PP.AddPragmaHandler(MSRuntimeChecks.get()); MSIntrinsic = std::make_unique(); @@ -554,6 +556,8 @@ MSCodeSeg.reset(); PP.RemovePragmaHandler(MSSection.get()); MSSection.reset(); + PP.RemovePragmaHandler(MSAllocText.get()); + MSAllocText.reset(); PP.RemovePragmaHandler(MSRuntimeChecks.get()); MSRuntimeChecks.reset(); PP.RemovePragmaHandler(MSIntrinsic.get()); @@ -912,7 +916,8 @@ .Case("const_seg", &Parser::HandlePragmaMSSegment) .Case("code_seg", &Parser::HandlePragmaMSSegment) .Case("section", &Parser::HandlePragmaMSSection) - .Case("init_seg", &Parser::HandlePragmaMSInitSeg); + .Case("init_seg", &Parser::HandlePragmaMSInitSeg) + .Case("alloc_text", &Parser::HandlePragmaMSAllocText); if (!(this->*Handler)(PragmaName, PragmaLocation)) { // Pragma handling failed, and has been diagnosed. Slurp up the tokens @@ -1149,6 +1154,72 @@ return true; } +bool Parser::HandlePragmaMSAllocText(StringRef PragmaName, + SourceLocation PragmaLocation) { + Token FirstTok = Tok; + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) + << PragmaName; + return false; + } + PP.Lex(Tok); + + if (Tok.isNot(tok::string_literal)) { + PP.Diag(PragmaLocation, diag::warn_pragma_expected_section_name) + << PragmaName; + return false; + } + ExprResult StringResult = ParseStringLiteralExpression(); + if (StringResult.isInvalid()) + return false; // Already diagnosed. + StringLiteral *SegmentName = cast(StringResult.get()); + if (SegmentName->getCharByteWidth() != 1) { + PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string) + << PragmaName; + return false; + } + + if (Tok.isNot(tok::comma)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_comma) << PragmaName; + return false; + } + PP.Lex(Tok); + + SmallVector Functions; + while (true) { + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) + << PragmaName; + return false; + } + + IdentifierInfo *II = Tok.getIdentifierInfo(); + Functions.emplace_back(II->getName()); + + PP.Lex(Tok); + if (Tok.isNot(tok::comma)) + break; + PP.Lex(Tok); + } + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName; + return false; + } + PP.Lex(Tok); + + if (Tok.isNot(tok::eof)) { + PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol) + << PragmaName; + return false; + } + PP.Lex(Tok); + + Actions.ActOnPragmaMSAllocText( + FirstTok.getLocation(), SegmentName->getString(), Functions); + return true; +} + namespace { struct PragmaLoopHintInfo { Token PragmaName; diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -741,6 +741,18 @@ CurInitSegLoc = PragmaLocation; } +void Sema::ActOnPragmaMSAllocText(SourceLocation PragmaLocation, + StringRef Section, + const SmallVector &Functions) { + if (!CurContext->getRedeclContext()->isFileContext()) { + Diag(PragmaLocation, diag::err_pragma_alloc_text_scope); + return; + } + + for (auto &Function : Functions) + FunctionToSectionMap[Function] = Section; +} + void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, SourceLocation PragmaLoc) { @@ -1072,6 +1084,17 @@ AddOptnoneAttributeIfNoConflicts(FD, OptimizeOffPragmaLocation); } +void Sema::AddSectionMSAllocText(FunctionDecl *FD) { + if (!FD->getIdentifier()) + return; + + StringRef Name = FD->getName(); + auto It = FunctionToSectionMap.find(Name); + if (It != FunctionToSectionMap.end()) + if (FD->isExternC() && !FD->hasAttr()) + FD->addAttr(SectionAttr::CreateImplicit(Context, It->second)); +} + void Sema::AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc) { // Don't add a conflicting attribute. No diagnostic is needed. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10220,8 +10220,10 @@ // If this is a function definition, check if we have to apply optnone due to // a pragma. - if(D.isFunctionDefinition()) + if(D.isFunctionDefinition()) { AddRangeBasedOptnone(NewFD); + AddSectionMSAllocText(NewFD); + } // If this is the first declaration of an extern C variable, update // the map of such variables.