https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127097

            Bug ID: 127097
           Summary: [modules] Alternate include of a header unit reads
                    stdin
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: alexey.klimkin at intel dot com
  Target Milestone: ---

When a C++ header unit is imported and the same physical header is later
included textually through an alternate pathname, GCC reads from file
descriptor 0 instead of reopening the source header. This produces a misleading
"file is shorter than expected" warning followed by duplicate definition
errors.

The problem is in libcpp/files.cc::_cpp_find_header_unit. It closes the header
source descriptor and records file->fd = 0, but read_file uses -1 as the
closed-descriptor sentinel when deciding whether to reopen a file. A later
alternate-path include therefore skips reopening the source and passes
descriptor 0 to read, consuming stdin. The file->fd > 0 close condition also
fails when opening the header legitimately returns descriptor 0.

Reproducer
==========

Create an existing directory for the alternate path:

  mkdir sys

header.H:

  #pragma once

  inline int f()
  {
    return 1;
  }

use.C:

  import "header.H";
  #include "sys/../header.H"

  int main()
  {
    return f() != 1;
  }

Build:

  g++ -std=c++20 -fmodule-header -c header.H
  g++ -std=c++20 -fmodules -c use.C

Actual result
=============

  use.C:2:10: warning: header.H is shorter than expected
  header.H:3:12: error: redefinition of 'int f()'

Expected result
===============

The alternate spelling should be recognized as the already-imported, once-only
header. Compilation should succeed without reading stdin or processing the
header twice.

Proposed fix
============

Close every valid descriptor (file->fd != -1) and restore the established
closed sentinel:

  close (file->fd);
  file->fd = -1;

A regression test imports a header unit and then includes it through an
alternate sys/../ spelling. It fails on unpatched trunk and compiles, links,
and runs after the fix.
  • [Bug c++/127097] New: [module... alexey.klimkin at intel dot com via Gcc-bugs

Reply via email to