diff options
author | Mariya Podchishchaeva <mariya.podchishchaeva@intel.com> | 2025-04-17 15:15:07 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-17 15:15:07 +0200 |
commit | 40417915a161e87b398f1cc3e9b7c159207abd77 (patch) | |
tree | 157a654f92de61a301c939c3d664941734142c09 /clang | |
parent | 0348ff515854438cab8a48b79e8839cb99d48701 (diff) | |
download | llvm-40417915a161e87b398f1cc3e9b7c159207abd77.zip llvm-40417915a161e87b398f1cc3e9b7c159207abd77.tar.gz llvm-40417915a161e87b398f1cc3e9b7c159207abd77.tar.bz2 |
[clang] Implement StmtPrinter for EmbedExpr (#135957)
Tries to avoid memory leaks previously caused by saving filename by
allocating memory in the preprocessor.
Fixes https://github.com/llvm/llvm-project/issues/132641
Fixes https://github.com/llvm/llvm-project/issues/107869
---------
Co-authored-by: Aaron Ballman <aaron@aaronballman.com>
Diffstat (limited to 'clang')
-rw-r--r-- | clang/docs/ReleaseNotes.rst | 3 | ||||
-rw-r--r-- | clang/include/clang/AST/Expr.h | 4 | ||||
-rw-r--r-- | clang/include/clang/Lex/Preprocessor.h | 3 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 2 | ||||
-rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Lex/PPDirectives.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Parse/ParseInit.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 3 | ||||
-rw-r--r-- | clang/test/Preprocessor/embed_weird.cpp | 40 |
9 files changed, 72 insertions, 7 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4f64069..0ea8498 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -426,6 +426,9 @@ Bug Fixes in This Version using C++23 "deducing this" did not have a diagnostic location (#GH135522) - Fixed a crash when a ``friend`` function is redefined as deleted. (#GH135506) +- Fixed a crash when ``#embed`` appears as a part of a failed constant + evaluation. The crashes were happening during diagnostics emission due to + unimplemented statement printer. (#GH132641) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 529c622..a83320a 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -4961,6 +4961,9 @@ private: /// Stores data related to a single #embed directive. struct EmbedDataStorage { StringLiteral *BinaryData; + // FileName string already includes braces, i.e. it is <files/my_file> for a + // directive #embed <files/my_file>. + StringRef FileName; size_t getDataElementCount() const { return BinaryData->getByteLength(); } }; @@ -5007,6 +5010,7 @@ public: SourceLocation getEndLoc() const { return EmbedKeywordLoc; } StringLiteral *getDataStringLiteral() const { return Data->BinaryData; } + StringRef getFileName() const { return Data->FileName; } EmbedDataStorage *getData() const { return Data; } unsigned getStartingElementPos() const { return Begin; } diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 24bb524..19d54ed 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2762,7 +2762,7 @@ private: const FileEntry *LookupFromFile = nullptr); void HandleEmbedDirectiveImpl(SourceLocation HashLoc, const LexEmbedParametersResult &Params, - StringRef BinaryContents); + StringRef BinaryContents, StringRef FileName); // File inclusion. void HandleIncludeDirective(SourceLocation HashLoc, Token &Tok, @@ -3066,6 +3066,7 @@ public: /// preprocessor to the parser through an annotation token. struct EmbedAnnotationData { StringRef BinaryData; + StringRef FileName; }; /// Registry of pragma handlers added by plugins diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fe37fd7..c167f8d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7256,7 +7256,7 @@ public: // #embed ExprResult ActOnEmbedExpr(SourceLocation EmbedKeywordLoc, - StringLiteral *BinaryData); + StringLiteral *BinaryData, StringRef FileName); // Build a potentially resolved SourceLocExpr. ExprResult BuildSourceLocExpr(SourceLocIdentKind Kind, QualType ResultTy, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index aae10fd3..c6c49c6 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1284,7 +1284,11 @@ void StmtPrinter::VisitSourceLocExpr(SourceLocExpr *Node) { } void StmtPrinter::VisitEmbedExpr(EmbedExpr *Node) { - llvm::report_fatal_error("Not implemented"); + // FIXME: Embed parameters are not reflected in the AST, so there is no way to + // print them yet. + OS << "#embed "; + OS << Node->getFileName(); + OS << NL; } void StmtPrinter::VisitConstantExpr(ConstantExpr *Node) { diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 8411526..49a4e24 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -3909,7 +3909,7 @@ Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) { void Preprocessor::HandleEmbedDirectiveImpl( SourceLocation HashLoc, const LexEmbedParametersResult &Params, - StringRef BinaryContents) { + StringRef BinaryContents, StringRef FileName) { if (BinaryContents.empty()) { // If we have no binary contents, the only thing we need to emit are the // if_empty tokens, if any. @@ -3940,6 +3940,7 @@ void Preprocessor::HandleEmbedDirectiveImpl( EmbedAnnotationData *Data = new (BP) EmbedAnnotationData; Data->BinaryData = BinaryContents; + Data->FileName = FileName; Toks[CurIdx].startToken(); Toks[CurIdx].setKind(tok::annot_embed); @@ -4049,5 +4050,16 @@ void Preprocessor::HandleEmbedDirective(SourceLocation HashLoc, Token &EmbedTok, if (Callbacks) Callbacks->EmbedDirective(HashLoc, Filename, isAngled, MaybeFileRef, *Params); - HandleEmbedDirectiveImpl(HashLoc, *Params, BinaryContents); + // getSpelling() may return a buffer from the token itself or it may use the + // SmallString buffer we provided. getSpelling() may also return a string that + // is actually longer than FilenameTok.getLength(), so we first pass a + // locally created buffer to getSpelling() to get the string of real length + // and then we allocate a long living buffer because the buffer we used + // previously will only live till the end of this function and we need + // filename info to live longer. + void *Mem = BP.Allocate(OriginalFilename.size(), alignof(char *)); + memcpy(Mem, OriginalFilename.data(), OriginalFilename.size()); + StringRef FilenameToGo = + StringRef(static_cast<char *>(Mem), OriginalFilename.size()); + HandleEmbedDirectiveImpl(HashLoc, *Params, BinaryContents, FilenameToGo); } diff --git a/clang/lib/Parse/ParseInit.cpp b/clang/lib/Parse/ParseInit.cpp index 471b3ea..8669632 100644 --- a/clang/lib/Parse/ParseInit.cpp +++ b/clang/lib/Parse/ParseInit.cpp @@ -451,7 +451,7 @@ ExprResult Parser::createEmbedExpr() { StringLiteral *BinaryDataArg = CreateStringLiteralFromStringRef( Data->BinaryData, Context.UnsignedCharTy); - Res = Actions.ActOnEmbedExpr(StartLoc, BinaryDataArg); + Res = Actions.ActOnEmbedExpr(StartLoc, BinaryDataArg, Data->FileName); } return Res; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 6830bb5..01117e7 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -16903,9 +16903,10 @@ ExprResult Sema::BuildSourceLocExpr(SourceLocIdentKind Kind, QualType ResultTy, } ExprResult Sema::ActOnEmbedExpr(SourceLocation EmbedKeywordLoc, - StringLiteral *BinaryData) { + StringLiteral *BinaryData, StringRef FileName) { EmbedDataStorage *Data = new (Context) EmbedDataStorage; Data->BinaryData = BinaryData; + Data->FileName = FileName; return new (Context) EmbedExpr(Context, EmbedKeywordLoc, Data, /*NumOfElements=*/0, Data->getDataElementCount()); diff --git a/clang/test/Preprocessor/embed_weird.cpp b/clang/test/Preprocessor/embed_weird.cpp index 9a984e4..e44aff5 100644 --- a/clang/test/Preprocessor/embed_weird.cpp +++ b/clang/test/Preprocessor/embed_weird.cpp @@ -136,3 +136,43 @@ constexpr struct HasChar c = { c-error {{constexpr initializer evaluates to 255 which is not exactly representable in type 'signed char'}} }; + +#if __cplusplus +namespace std { +typedef decltype(sizeof(int)) size_t; + +template <class _E> class initializer_list { + const _E *__begin_; + size_t __size_; + + constexpr initializer_list(const _E *__b, size_t __s) + : __begin_(__b), __size_(__s) {} + +public: + constexpr initializer_list() : __begin_(nullptr), __size_(0) {} +}; +} // namespace std + +class S2 { +public: + constexpr S2(std::initializer_list<char>) { // cxx-error {{constexpr constructor never produces a constant expression}} + 1/0; // cxx-warning {{division by zero is undefined}} + // cxx-warning@-1 {{unused}} + // cxx-note@-2 4{{division by zero}} + } +}; + + +constexpr S2 s2 { // cxx-error {{must be initialized by a constant expression}} + // cxx-note-re@-1 {{in call to 'S2{{.*}} #embed <jk.txt>}} +#embed <jk.txt> prefix(0x2c, 0x20, )limit(5) +}; +constexpr S2 s3 {1, // cxx-error {{must be initialized by a constant expression}} + // cxx-note-re@-1 {{in call to 'S2{{.*}} #embed "jk.txt"}} +#embed "jk.txt" +}; +constexpr S2 s4 { // cxx-error {{must be initialized by a constant expression}} + // cxx-note-re@-1 {{in call to 'S2{{.*}}"jk"}} +#embed "jk.txt" +}; +#endif |