Skip to content

[clang-repl] Create virtual files for input_line_N buffers#182044

Merged
vgvassilev merged 2 commits into
llvm:mainfrom
devajithvs:verify-clangrepl
Mar 4, 2026
Merged

[clang-repl] Create virtual files for input_line_N buffers#182044
vgvassilev merged 2 commits into
llvm:mainfrom
devajithvs:verify-clangrepl

Conversation

@devajithvs

@devajithvs devajithvs commented Feb 18, 2026

Copy link
Copy Markdown
Contributor

Instead of using memory buffers without file backing, this patch input_line_N buffers as virtual files.

This patch enables us to use input line numbers when verifying tests clang-repl.

@devajithvs devajithvs marked this pull request as ready for review February 18, 2026 16:37
@devajithvs devajithvs marked this pull request as draft February 18, 2026 16:37
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Feb 18, 2026
@llvmbot

llvmbot commented Feb 18, 2026

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-clang

Author: Devajith (devajithvs)

Changes

In clang-repl, input buffers (e.g., input_line_1) are virtual and not tracked by the FileManager. This patch enables us to use input line numbers when verifying tests in clang-repl.


Full diff: https://github.com/llvm/llvm-project/pull/182044.diff

2 Files Affected:

  • (modified) clang/lib/Frontend/VerifyDiagnosticConsumer.cpp (+39-7)
  • (added) clang/test/Interpreter/verify-diagnostics.cpp (+13)
diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
index e263e10bb065a..73abb538f35e0 100644
--- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
+++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp
@@ -556,17 +556,41 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM,
           OptionalFileEntryRef File =
               PP->LookupFile(Pos, Filename, false, nullptr, nullptr, nullptr,
                              nullptr, nullptr, nullptr, nullptr, nullptr);
-          if (!File) {
+
+          FileID FID;
+          if (File) {
+            FID = SM.translateFile(*File);
+            if (FID.isInvalid()) {
+              FID = SM.createFileID(*File, Pos, SrcMgr::C_User);
+            }
+          } else if (Filename.starts_with("input_line_")) {
+            // clang-repl buffers (e.g., input_line_1) are virtual and not
+            // tracked by the FileManager. We need to manually scan the
+            // SourceManager's local SLocEntry table to find the buffer matching
+            // this name.
+            for (unsigned i = 0; i < SM.local_sloc_entry_size(); ++i) {
+              const SrcMgr::SLocEntry &Entry = SM.getLocalSLocEntry(i);
+              if (!Entry.isFile())
+                continue;
+              if (auto Buffer =
+                      Entry.getFile().getContentCache().getBufferIfLoaded()) {
+                if (Buffer->getBufferIdentifier() == Filename) {
+                  SourceLocation EntryLoc =
+                      SourceLocation::getFromRawEncoding(Entry.getOffset());
+                  FID = SM.getFileID(EntryLoc);
+                  break;
+                }
+              }
+            }
+          }
+
+          if (FID.isInvalid()) {
             Diags.Report(Pos.getLocWithOffset(PH.C - PH.Begin),
                          diag::err_verify_missing_file)
                 << Filename << KindStr;
             continue;
           }
 
-          FileID FID = SM.translateFile(*File);
-          if (FID.isInvalid())
-            FID = SM.createFileID(*File, Pos, SrcMgr::C_User);
-
           if (PH.Next(Line) && Line > 0)
             ExpectedLoc = SM.translateLineCol(FID, Line, 1);
           else if (PH.Next("*")) {
@@ -949,11 +973,19 @@ static bool IsFromSameFile(SourceManager &SM, SourceLocation DirectiveLoc,
   if (SM.isWrittenInSameFile(DirectiveLoc, DiagnosticLoc))
     return true;
 
-  const FileEntry *DiagFile = SM.getFileEntryForID(SM.getFileID(DiagnosticLoc));
+  FileID DiagFID = SM.getFileID(DiagnosticLoc);
+  FileID DirFID = SM.getFileID(DirectiveLoc);
+
+  // If they are the exact same buffer, we're done.
+  if (DiagFID == DirFID)
+    return true;
+
+  const FileEntry *DiagFile = SM.getFileEntryForID(DiagFID);
+
   if (!DiagFile && SM.isWrittenInMainFile(DirectiveLoc))
     return true;
 
-  return (DiagFile == SM.getFileEntryForID(SM.getFileID(DirectiveLoc)));
+  return DiagFile == SM.getFileEntryForID(DirFID);
 }
 
 /// CheckLists - Compare expected to seen diagnostic lists and return the
diff --git a/clang/test/Interpreter/verify-diagnostics.cpp b/clang/test/Interpreter/verify-diagnostics.cpp
new file mode 100644
index 0000000000000..f64655575314c
--- /dev/null
+++ b/clang/test/Interpreter/verify-diagnostics.cpp
@@ -0,0 +1,13 @@
+// REQUIRES: host-supports-jit
+// RUN: cat %s | clang-repl -Xcc -Xclang -Xcc -verify
+
+auto x = unknown_val;
+// expected-error@input_line_3:1 {{use of undeclared identifier 'unknown_val'}}
+
+int get_int() { return 42; }
+char* ptr = get_int();
+// expected-error@input_line_7:1 {{cannot initialize a variable of type 'char *' with an rvalue of type 'int'}}
+
+// Verify without input_line_*
+int y = ;
+// expected-error {{expected expression}}

@devajithvs

Copy link
Copy Markdown
Contributor Author

CC: @vgvassilev
This will enable us use -verify with {input_line*} like in cling.

@vgvassilev

Copy link
Copy Markdown
Contributor

Looks reasonable to me but I'd like some more input from Ian and Aaron.

@jansvoboda11

Copy link
Copy Markdown
Contributor

Instead of increasing complexity in Clang, why doesn't clang-repl register these as virtual files in FileManager so that they don't require special-casing here?

@llvmbot llvmbot added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Feb 19, 2026
@devajithvs devajithvs changed the title [clang-repl] Enable VerifyDiagnostic support for virtual buffers [clang-repl] Create virtual files for input_line_N buffers Feb 19, 2026
@devajithvs

Copy link
Copy Markdown
Contributor Author

why doesn't clang-repl register these as virtual files in FileManager so that they don't require special-casing here?

Thanks @jansvoboda11. This is exactly what we do in cling.

But after 84df7a0, we need to ensure HeaderFileInfo exists before lookup to prevent assertion.

As a part of reducing our internal clang patches in cling, I thought I will adapt to what clang-repl does (without registering these as virtual files)

I have updated the PR and the description (we still need minor changes in VerifyDiagnosticConsumer.cpp ).

Comment on lines +569 to +571
// Check if the file was virtual
if (!File)
File = SM.getFileManager().getOptionalFileRef(Filename);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How come PP->LookupFile() can't find virtual files? I think it should just work, but maybe we need to provide the Includers argument? Or could we make the virtual file paths absolute by prefixing /?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's the problem. Easiest way to fix this would be to prepend incremental parsing source files with ./ or /.

But that would mean all the warnings/errors will have that prefix.

In file included from <<< inputs >>>:1:                                                                                                                                                                                                                       
./input_line_4:1:10: error: use of undeclared identifier 'unknown_val'                                                                                                                                                                                          
    1 | auto x = unknown_val;                                                                                                                                                                                                                                 
      |          ^~~~~~~~~~~  

and we do:

// expected-error@./input_line_4:1 {{use of undeclared identifier 'unknown_val'}}

Which looks a bit weird (and will need to update the test-cases in clang-repl with this change)
CC: @vgvassilev

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it'd be great if we can avoid that prefix..

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also have something like this in HeaderSearch, but I don't know if that is ideal:

diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 5f52d62bd36e..795e91673de3 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -1021,9 +1021,20 @@ OptionalFileEntryRef HeaderSearch::LookupFile(
         assert(HFI && "includer without file info");
         return HFI->DirInfo != SrcMgr::C_User;
       }();
-      if (OptionalFileEntryRef FE = getFileAndSuggestModule(
-              TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
-              RequestingModule, SuggestedModule)) {
+
+      OptionalFileEntryRef FE = getFileAndSuggestModule(
+          TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
+          RequestingModule, SuggestedModule);
+
+      // Check if it is a virtual file from incremental buffer
+      if (!FE && IncluderAndDir.second.getName() == "." &&
+          Filename.starts_with("input_line_")) {
+        FE = getFileAndSuggestModule(
+            Filename, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader,
+            RequestingModule, SuggestedModule);
+      }
+
+      if (FE) {
         diagnoseHeaderShadowing(Filename, FE, DiagnosedShadowing, IncludeLoc,
                                 FromDir, Includers, isAngled,
                                 &IncluderAndDir - Includers.begin(), nullptr);

Instead of using memory buffers without file backing, this patch
registers `input_line_N` buffers as virtual files.

This patch enables us to use input line numbers when verifying tests
in `clang-repl`.
@devajithvs

Copy link
Copy Markdown
Contributor Author

I've added the check isIncrementalProcessingEnabled() to make this specific to incremental inputs. Closing: #182070 as these changes will fix the issue there.

@jansvoboda11 jansvoboda11 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vgvassilev vgvassilev merged commit 9cc0df9 into llvm:main Mar 4, 2026
10 checks passed
@vgvassilev vgvassilev added this to the LLVM 22.x Release milestone Mar 4, 2026
@github-project-automation github-project-automation Bot moved this to Needs Triage in LLVM Release Status Mar 4, 2026
@github-project-automation github-project-automation Bot moved this from Needs Triage to Done in LLVM Release Status Mar 4, 2026
@vgvassilev

Copy link
Copy Markdown
Contributor

/cherry-pick 9cc0df9

@devajithvs

Copy link
Copy Markdown
Contributor Author

Thanks @vgvassilev

@llvmbot

llvmbot commented Mar 4, 2026

Copy link
Copy Markdown
Member

/pull-request #184600

sahas3 pushed a commit to sahas3/llvm-project that referenced this pull request Mar 4, 2026
…2044)

Instead of using memory buffers without file backing, this patch
`input_line_N` buffers as virtual files.
    
This patch enables us to use input line numbers when verifying tests
`clang-repl`.

Co-authored-by: Vassil Vassilev <v.g.vassilev@gmail.com>
sujianIBM pushed a commit to sujianIBM/llvm-project that referenced this pull request Mar 5, 2026
…2044)

Instead of using memory buffers without file backing, this patch
`input_line_N` buffers as virtual files.
    
This patch enables us to use input line numbers when verifying tests
`clang-repl`.

Co-authored-by: Vassil Vassilev <v.g.vassilev@gmail.com>
dyung pushed a commit to llvmbot/llvm-project that referenced this pull request Mar 6, 2026
…2044)

Instead of using memory buffers without file backing, this patch
`input_line_N` buffers as virtual files.

This patch enables us to use input line numbers when verifying tests
`clang-repl`.

Co-authored-by: Vassil Vassilev <v.g.vassilev@gmail.com>
(cherry picked from commit 9cc0df9)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

Development

Successfully merging this pull request may close these issues.

4 participants