Delay finishing the C++ translation unit until we reach the real EOF. (#6489)

Instead of parsing a complete C++ translation unit and then interacting
with the translation unit further after the fact, delay finishing the
translation unit until we finish the Carbon check phase. This fixes some
issues where we would produce duplicated or incorrect diagnostics at the
end of the C++ translation unit, particularly for unused declarations.
Now we're in control of how we parse the translation unit, also disable
parsing of C++20 modules if the syntax appears within `import Cpp
inline` code.

Keep the same clang parser alive throughout check, and use it instead of
building a new one when parsing macros. This resolves issues where the
translation unit scope was destroyed too early, resulting in unqualified
lookup within macros being unable to find global scope entities.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
Richard Smith
2025-12-13 00:56:30 +00:00
committed by GitHub
co-authored by Jon Ross-Perkins
parent 77caf3b9d8
commit a8eca2ece6
11 changed files with 213 additions and 57 deletions
+1 -5
View File
@@ -25,7 +25,7 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
clang::Sema& sema = context.clang_sema();
clang::Preprocessor& preprocessor = sema.getPreprocessor();
clang::Parser parser(preprocessor, sema, false);
auto& parser = context.cpp_context()->parser();
llvm::SmallVector<clang::Token> tokens(macro_info->tokens().begin(),
macro_info->tokens().end());
@@ -45,11 +45,7 @@ auto TryEvaluateMacroToConstant(Context& context, SemIR::LocId loc_id,
/*IsReinject=*/false);
parser.ConsumeAnyToken(true);
// TODO: Identifiers are still only available if prefixed with "::" (e.g.
// "#define M_Var ::myVar").
parser.EnterScope(clang::Scope::DeclScope);
clang::ExprResult result = parser.ParseConstantExpression();
parser.ExitScope();
clang::Expr* result_expr = result.get();