-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[SystemZ][z/OS] Implement #pragma export #141671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 13 commits
3341324
a40fc1a
c3bdc3a
9e487ab
66177a4
8da7417
58f1b64
14d0a43
b6885d0
c73bcdc
4a6014c
638db8d
a06b4b3
5679a80
8582eef
01c7419
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -395,6 +395,12 @@ struct PragmaMaxTokensTotalHandler : public PragmaHandler { | |
| Token &FirstToken) override; | ||
| }; | ||
|
|
||
| struct PragmaExportHandler : public PragmaHandler { | ||
| explicit PragmaExportHandler() : PragmaHandler("export") {} | ||
| void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | ||
| Token &FirstToken) override; | ||
| }; | ||
|
|
||
| struct PragmaRISCVHandler : public PragmaHandler { | ||
| PragmaRISCVHandler(Sema &Actions) | ||
| : PragmaHandler("riscv"), Actions(Actions) {} | ||
|
|
@@ -558,6 +564,11 @@ void Parser::initializePragmaHandlers() { | |
| MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>(); | ||
| PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get()); | ||
|
|
||
| if (getLangOpts().ZOSExt) { | ||
| ExportHandler = std::make_unique<PragmaExportHandler>(); | ||
| PP.AddPragmaHandler(ExportHandler.get()); | ||
| } | ||
|
|
||
| if (getTargetInfo().getTriple().isRISCV()) { | ||
| RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(Actions); | ||
| PP.AddPragmaHandler("clang", RISCVPragmaHandler.get()); | ||
|
|
@@ -692,6 +703,11 @@ void Parser::resetPragmaHandlers() { | |
| PP.RemovePragmaHandler("clang", MaxTokensTotalPragmaHandler.get()); | ||
| MaxTokensTotalPragmaHandler.reset(); | ||
|
|
||
| if (getLangOpts().ZOSExt) { | ||
| PP.RemovePragmaHandler(ExportHandler.get()); | ||
| ExportHandler.reset(); | ||
| } | ||
|
|
||
| if (getTargetInfo().getTriple().isRISCV()) { | ||
| PP.RemovePragmaHandler("clang", RISCVPragmaHandler.get()); | ||
| RISCVPragmaHandler.reset(); | ||
|
|
@@ -1386,6 +1402,74 @@ bool Parser::HandlePragmaMSAllocText(StringRef PragmaName, | |
| return true; | ||
| } | ||
|
|
||
| bool Parser::zOSHandlePragmaHelper(tok::TokenKind PragmaKind) { | ||
| assert(Tok.is(PragmaKind)); | ||
|
|
||
| StringRef PragmaName = "export"; | ||
|
|
||
| using namespace clang::charinfo; | ||
| auto *TheTokens = | ||
| (std::pair<std::unique_ptr<Token[]>, size_t> *)Tok.getAnnotationValue(); | ||
| PP.EnterTokenStream(std::move(TheTokens->first), TheTokens->second, true, | ||
| false); | ||
| ConsumeAnnotationToken(); | ||
|
|
||
| do { | ||
| PP.Lex(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::identifier)) { | ||
| PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | ||
| << PragmaName; | ||
| return false; | ||
| } | ||
|
|
||
| IdentifierInfo *IdentName = Tok.getIdentifierInfo(); | ||
| SourceLocation IdentNameLoc = Tok.getLocation(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is unfortunate that Fully Qualified Names aren't supported here. Since we're doing a lookup anyway, way can't we do that? |
||
| PP.Lex(Tok); | ||
|
|
||
| if (Tok.isNot(tok::r_paren)) { | ||
| PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) | ||
| << PragmaName; | ||
| return false; | ||
| } | ||
|
|
||
| PP.Lex(Tok); | ||
| Actions.ActOnPragmaExport(IdentName, IdentNameLoc, getCurScope()); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can |
||
|
|
||
| // Because export is also a C++ keyword, we also check for that. | ||
| if (Tok.is(tok::identifier) || Tok.is(tok::kw_export)) { | ||
| PragmaName = Tok.getIdentifierInfo()->getName(); | ||
| if (PragmaName != "export") | ||
| PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||
| << PragmaName; | ||
| } else if (Tok.isNot(tok::eof)) { | ||
| PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | ||
| << PragmaName; | ||
| return false; | ||
| } | ||
| } while (Tok.isNot(tok::eof)); | ||
| PP.Lex(Tok); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is quite a bit on how htis parsing is working that doesn't seem right to me, but the parser code owner shoudl take a look.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you take a look at the parsing again. I have removed the part that parsed the parameter list as part of removing that form of the pragma syntax. |
||
| return true; | ||
| } | ||
|
|
||
| void Parser::HandlePragmaExport() { | ||
| assert(Tok.is(tok::annot_pragma_export)); | ||
|
|
||
| if (!zOSHandlePragmaHelper(tok::annot_pragma_export)) { | ||
| // Parsing pragma failed, and has been diagnosed. Slurp up the | ||
| // tokens until eof (really end of line) to prevent follow-on errors. | ||
| while (Tok.isNot(tok::eof)) | ||
| PP.Lex(Tok); | ||
| PP.Lex(Tok); | ||
| } | ||
| } | ||
|
|
||
| static std::string PragmaLoopHintString(Token PragmaName, Token Option) { | ||
| StringRef Str = PragmaName.getIdentifierInfo()->getName(); | ||
| std::string ClangLoopStr("clang loop "); | ||
|
|
@@ -4133,6 +4217,43 @@ void PragmaMaxTokensTotalHandler::HandlePragma(Preprocessor &PP, | |
| PP.overrideMaxTokens(MaxTokens, Loc); | ||
| } | ||
|
|
||
| static void zOSPragmaHandlerHelper(Preprocessor &PP, Token &Tok, | ||
| tok::TokenKind TokKind) { | ||
| Token EoF, AnnotTok; | ||
| EoF.startToken(); | ||
| EoF.setKind(tok::eof); | ||
| AnnotTok.startToken(); | ||
| AnnotTok.setKind(TokKind); | ||
| AnnotTok.setLocation(Tok.getLocation()); | ||
| AnnotTok.setAnnotationEndLoc(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); | ||
| AnnotTok.setAnnotationEndLoc(Tok.getLocation()); | ||
| } | ||
| // Add a sentinel EoF token to the end of the list. | ||
| EoF.setLocation(Tok.getLocation()); | ||
| TokenVector.push_back(EoF); | ||
| // We must allocate this array with new because EnterTokenStream is going to | ||
| // delete it later. | ||
| markAsReinjectedForRelexing(TokenVector); | ||
| auto TokenArray = std::make_unique<Token[]>(TokenVector.size()); | ||
| std::copy(TokenVector.begin(), TokenVector.end(), TokenArray.get()); | ||
| auto Value = new (PP.getPreprocessorAllocator()) | ||
| std::pair<std::unique_ptr<Token[]>, size_t>(std::move(TokenArray), | ||
| TokenVector.size()); | ||
| AnnotTok.setAnnotationValue(Value); | ||
| PP.EnterToken(AnnotTok, /*IsReinject*/ false); | ||
| } | ||
|
|
||
| /// Handle #pragma export. | ||
| void PragmaExportHandler::HandlePragma(Preprocessor &PP, | ||
| PragmaIntroducer Introducer, | ||
| Token &FirstToken) { | ||
| zOSPragmaHandlerHelper(PP, FirstToken, tok::annot_pragma_export); | ||
| } | ||
|
|
||
| // Handle '#pragma clang riscv intrinsic vector'. | ||
| // '#pragma clang riscv intrinsic sifive_vector'. | ||
| // '#pragma clang riscv intrinsic andes_vector'. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1327,6 +1327,59 @@ void Sema::AddImplicitMSFunctionNoBuiltinAttr(FunctionDecl *FD) { | |
| FD->addAttr(NoBuiltinAttr::CreateImplicit(Context, V.data(), V.size())); | ||
| } | ||
|
|
||
| NamedDecl *Sema::lookupExternCName(IdentifierInfo *IdentId, | ||
| SourceLocation NameLoc, Scope *curScope) { | ||
| LookupResult Result(*this, IdentId, NameLoc, LookupOrdinaryName); | ||
| LookupName(Result, curScope); | ||
| if (!getLangOpts().CPlusPlus) | ||
| return Result.getAsSingle<NamedDecl>(); | ||
| for (LookupResult::iterator I = Result.begin(); I != Result.end(); ++I) { | ||
| NamedDecl *D = (*I)->getUnderlyingDecl(); | ||
| if (auto *FD = dyn_cast<FunctionDecl>(D->getCanonicalDecl())) | ||
| if (FD->isExternC()) | ||
| return D; | ||
| if (isa<VarDecl>(D->getCanonicalDecl())) | ||
| return D; | ||
| } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this lookup is quite right. We should probably be just doing normal name lookup rather than this. Also, this doesn't support dependent names, which we definitely should be doing. |
||
| return nullptr; | ||
| } | ||
|
|
||
| void Sema::ActOnPragmaExport(IdentifierInfo *IdentId, SourceLocation NameLoc, Scope *curScope) { | ||
| SymbolLabel Label; | ||
| Label.NameLoc = NameLoc; | ||
| Label.Used = false; | ||
|
|
||
| NamedDecl *PrevDecl = lookupExternCName(IdentId, NameLoc, curScope); | ||
| if (!PrevDecl) { | ||
| PendingExportedNames[IdentId] = Label; | ||
| return; | ||
| } | ||
|
|
||
| if (auto *FD = dyn_cast<FunctionDecl>(PrevDecl->getCanonicalDecl())) { | ||
| if (!FD->hasExternalFormalLinkage()) { | ||
| Diag(NameLoc, diag::warn_pragma_not_applied) << "export" << PrevDecl; | ||
| return; | ||
| } | ||
| if (FD->hasBody()) { | ||
| Diag(NameLoc, diag::warn_pragma_not_applied_to_defined_symbol) | ||
| << "export"; | ||
| return; | ||
| } | ||
| } else if (auto *VD = dyn_cast<VarDecl>(PrevDecl->getCanonicalDecl())) { | ||
| if (!VD->hasExternalFormalLinkage()) { | ||
| Diag(NameLoc, diag::warn_pragma_not_applied) << "export" << PrevDecl; | ||
| return; | ||
| } | ||
| if (VD->hasDefinition() == VarDecl::Definition) { | ||
| Diag(NameLoc, diag::warn_pragma_not_applied_to_defined_symbol) | ||
| << "export"; | ||
| return; | ||
| } | ||
| } | ||
| mergeVisibilityType(PrevDecl->getCanonicalDecl(), NameLoc, | ||
| VisibilityAttr::Default); | ||
| } | ||
|
|
||
| typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack; | ||
| enum : unsigned { NoVisibility = ~0U }; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't particularly ZOS specific other than for compiler compat, right? Is there a good reason we couldn't allow this syntax on other compilers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pragma duplicates on a limited scope the functionality of the visibility attribute. We're adding the pragma for compatibility with the z/OS XL C/C++ compiler. I'm more that happy to make it available everywhere. I just didn't want to cause confusion by providing yet another mechanism for specifying visibility especially since it is limited to which C++ declarations it can be applied too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think I should enable this for all platforms?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDK why I didn't see the comment response here... I think doing these based on the target here is somewhat reasonable, it harms portability of this attribute, but in a way that I don't think is particularly challenging thanks to the ZOSExt flag being required.