steplong updated this revision to Diff 428456. steplong added a comment. - Changed pragma-ms-functions.c to only check that the no-builtin attributes are added to the functions - Moved pragma handler to Parser - Changed scope check to only file scope. MSVC accepts stuff like that we don't:
struct S { int a; #pragma function(memset) }; Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D124702/new/ https://reviews.llvm.org/D124702 Files: clang/include/clang/Basic/DiagnosticSemaKinds.td clang/include/clang/Parse/Parser.h clang/include/clang/Sema/Sema.h clang/lib/Parse/ParsePragma.cpp clang/lib/Sema/SemaAttr.cpp clang/lib/Sema/SemaDecl.cpp clang/test/CodeGen/pragma-ms-function.c clang/test/Preprocessor/pragma_microsoft.c
Index: clang/test/Preprocessor/pragma_microsoft.c =================================================================== --- clang/test/Preprocessor/pragma_microsoft.c +++ clang/test/Preprocessor/pragma_microsoft.c @@ -201,6 +201,26 @@ #pragma clang diagnostic pop #pragma intrinsic(asdf) // expected-warning {{'asdf' is not a recognized builtin; consider including <intrin.h>}} +// Test pragma function +#pragma function(memset) // no-warning +#pragma function(memcpy, strlen, strlen) // no-warning +#pragma function() // no-warning +#pragma function(asdf) // expected-warning {{'asdf' is not a recognized builtin; consider including <intrin.h>}} +#pragma function(main) // expected-warning {{'main' is not a recognized builtin; consider including <intrin.h>}} +#pragma function( // expected-warning {{missing ')' after}} +#pragma function(int) // expected-warning {{missing ')' after}} +#pragma function(strcmp) asdf // expected-warning {{extra tokens at end}} + +#define __INTRIN_H // there should be no notes after defining __INTRIN_H +#pragma function(asdf) // expected-warning-re {{'asdf' is not a recognized builtin{{$}}}} +#pragma function(memset) // no-warning +#undef __INTRIN_H +#pragma function(asdf) // expected-warning {{'asdf' is not a recognized builtin; consider including <intrin.h>}} + +void pragma_function_foo() { +#pragma function(memset) // expected-error {{'#pragma function' can only appear at file scope}} +} + #pragma optimize // expected-warning{{missing '(' after '#pragma optimize'}} #pragma optimize( // expected-warning{{expected string literal in '#pragma optimize'}} #pragma optimize(a // expected-warning{{expected string literal in '#pragma optimize'}} Index: clang/test/CodeGen/pragma-ms-function.c =================================================================== --- /dev/null +++ clang/test/CodeGen/pragma-ms-function.c @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -emit-llvm -fms-extensions -o - %s | FileCheck %s + +typedef typeof(sizeof(0)) size_t; + +void bar(char *s); +void *memset(void *s, int c, size_t n); +void *memcpy(void *d, const void *s, size_t n); + +// CHECK: define{{.*}} void @foo1({{.*}}) #[[NO_NOBUILTIN:[0-9]+]] +void foo1(char *s, char *d, size_t n) { + bar(s); + memset(s, 0, n); + memcpy(d, s, n); +} + +#pragma function(strlen, memset) + +// CHECK: define{{.*}} void @foo2({{.*}}) #[[NOBUILTIN_MEMSET:[0-9]+]] +void foo2(char *s, char *d, size_t n) { + bar(s); + memset(s, 1, n); + memcpy(d, s, n); +} + +#pragma function(memcpy) + +// CHECK: define{{.*}} void @foo3({{.*}}) #[[NOBUILTIN_MEMSET_MEMCPY:[0-9]+]] +void foo3(char *s, char *d, size_t n) { + bar(s); + memset(s, 2, n); + memcpy(d, s, n); +} + +// CHECK-NOT: attributes #[[NO_NOBUILTIN]] = {{{.*}}"no-builtin-memset"{{.*}}} +// CHECK-NOT: attributes #[[NO_NOBUILTIN]] = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}} +// CHECK: attributes #[[NOBUILTIN_MEMSET]] = {{{.*}}"no-builtin-memset"{{.*}}} +// CHECK-NOT: attributes #[[NOBUILTIN_MEMSET]] = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}} +// CHECK: attributes #[[NOBUILTIN_MEMSET_MEMCPY]] = {{{.*}}"no-builtin-memcpy"{{.*}}"no-builtin-memset"{{.*}}} Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -10218,10 +10218,12 @@ // marking the function. AddCFAuditedAttribute(NewFD); - // If this is a function definition, check if we have to apply optnone due to - // a pragma. - if(D.isFunctionDefinition()) + // If this is a function definition, check if we have to apply any + // attributes (i.e. optnone and no_builtin) due to a pragma. + if (D.isFunctionDefinition()) { AddRangeBasedOptnone(NewFD); + AddRangeBasedNoBuiltin(NewFD); + } // If this is the first declaration of an extern C variable, update // the map of such variables. Index: clang/lib/Sema/SemaAttr.cpp =================================================================== --- clang/lib/Sema/SemaAttr.cpp +++ clang/lib/Sema/SemaAttr.cpp @@ -1065,6 +1065,16 @@ OptimizeOffPragmaLocation = PragmaLoc; } +void Sema::ActOnPragmaMSFunction( + SourceLocation Loc, const llvm::SmallVectorImpl<StringRef> &NoBuiltins) { + if (!CurContext->getRedeclContext()->isFileContext()) { + Diag(Loc, diag::err_pragma_intrinsic_function_scope) << "function"; + return; + } + + MSFunctionNoBuiltins.insert(NoBuiltins.begin(), NoBuiltins.end()); +} + void Sema::AddRangeBasedOptnone(FunctionDecl *FD) { // In the future, check other pragmas if they're implemented (e.g. pragma // optimize 0 will probably map to this functionality too). @@ -1086,6 +1096,13 @@ FD->addAttr(NoInlineAttr::CreateImplicit(Context, Loc)); } +void Sema::AddRangeBasedNoBuiltin(FunctionDecl *FD) { + SmallVector<StringRef> V(MSFunctionNoBuiltins.begin(), + MSFunctionNoBuiltins.end()); + if (!MSFunctionNoBuiltins.empty()) + FD->addAttr(NoBuiltinAttr::CreateImplicit(Context, V.data(), V.size())); +} + typedef std::vector<std::pair<unsigned, SourceLocation> > VisStack; enum : unsigned { NoVisibility = ~0U }; Index: clang/lib/Parse/ParsePragma.cpp =================================================================== --- clang/lib/Parse/ParsePragma.cpp +++ clang/lib/Parse/ParsePragma.cpp @@ -445,6 +445,8 @@ PP.AddPragmaHandler(MSCodeSeg.get()); MSSection = std::make_unique<PragmaMSPragma>("section"); PP.AddPragmaHandler(MSSection.get()); + MSFunction = std::make_unique<PragmaMSPragma>("function"); + PP.AddPragmaHandler(MSFunction.get()); MSRuntimeChecks = std::make_unique<PragmaMSRuntimeChecksHandler>(); PP.AddPragmaHandler(MSRuntimeChecks.get()); MSIntrinsic = std::make_unique<PragmaMSIntrinsicHandler>(); @@ -554,6 +556,8 @@ MSCodeSeg.reset(); PP.RemovePragmaHandler(MSSection.get()); MSSection.reset(); + PP.RemovePragmaHandler(MSFunction.get()); + MSFunction.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("function", &Parser::HandlePragmaMSFunction); if (!(this->*Handler)(PragmaName, PragmaLocation)) { // Pragma handling failed, and has been diagnosed. Slurp up the tokens @@ -3547,6 +3552,41 @@ << "intrinsic"; } +bool Parser::HandlePragmaMSFunction(StringRef PragmaName, + SourceLocation PragmaLocation) { + Token FirstTok = Tok; + + if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen, + PragmaName)) + return false; + + bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H"); + + llvm::SmallVector<StringRef> NoBuiltins; + while (Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (!II->getBuiltinID()) + PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin) + << II << SuggestIntrinH; + else + NoBuiltins.emplace_back(II->getName()); + + PP.Lex(Tok); + if (Tok.isNot(tok::comma)) + break; + PP.Lex(Tok); // , + } + + if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen, + PragmaName) || + ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol, + PragmaName)) + return false; + + Actions.ActOnPragmaMSFunction(FirstTok.getLocation(), NoBuiltins); + return true; +} + // #pragma optimize("gsty", on|off) void PragmaMSOptimizeHandler::HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -755,6 +755,9 @@ /// optimizations are currently "on", this is set to an invalid location. SourceLocation OptimizeOffPragmaLocation; + /// Set of no-builtin functions listed by \#pragma function. + llvm::SmallSetVector<StringRef, 4> MSFunctionNoBuiltins; + /// Flag indicating if Sema is building a recovery call expression. /// /// This flag is used to avoid building recovery call expressions @@ -10322,6 +10325,11 @@ /// Called on well formed \#pragma clang optimize. void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc); + /// Call on well formed \#pragma function. + void + ActOnPragmaMSFunction(SourceLocation Loc, + const llvm::SmallVectorImpl<StringRef> &NoBuiltins); + /// Get the location for the currently active "\#pragma clang optimize /// off". If this location is invalid, then the state of the pragma is "on". SourceLocation getOptimizeOffPragmaLocation() const { @@ -10338,6 +10346,11 @@ /// attribute to be added (usually because of a pragma). void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc); + /// Only called on function definitions; if there is a pragma in scope + /// with the effect of a range-based no_builtin, consider marking the function + /// with attribute no_builtin. + void AddRangeBasedNoBuiltin(FunctionDecl *FD); + /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. void AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, bool IsPackExpansion); Index: clang/include/clang/Parse/Parser.h =================================================================== --- clang/include/clang/Parse/Parser.h +++ clang/include/clang/Parse/Parser.h @@ -196,6 +196,7 @@ std::unique_ptr<PragmaHandler> MSSection; std::unique_ptr<PragmaHandler> MSRuntimeChecks; std::unique_ptr<PragmaHandler> MSIntrinsic; + std::unique_ptr<PragmaHandler> MSFunction; std::unique_ptr<PragmaHandler> MSOptimize; std::unique_ptr<PragmaHandler> MSFenvAccess; std::unique_ptr<PragmaHandler> CUDAForceHostDeviceHandler; @@ -722,6 +723,8 @@ SourceLocation PragmaLocation); bool HandlePragmaMSInitSeg(StringRef PragmaName, SourceLocation PragmaLocation); + bool HandlePragmaMSFunction(StringRef PragmaName, + SourceLocation PragmaLocation); /// Handle the annotation token produced for /// #pragma align... Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -988,6 +988,9 @@ def err_super_in_lambda_unsupported : Error< "use of '__super' inside a lambda is unsupported">; +def err_pragma_intrinsic_function_scope : Error< + "'#pragma %0' can only appear at file scope">; + def warn_pragma_unused_undeclared_var : Warning< "undeclared variable %0 used as an argument for '#pragma unused'">, InGroup<IgnoredPragmas>;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits