[clang] 85b1354 - [C++20][Modules][HU 5/5] Add fdirectives-only mode for preprocessing output.

Iain Sandoe via cfe-commits cfe-commits at lists.llvm.org
Sun Mar 27 23:38:34 PDT 2022


Author: Iain Sandoe
Date: 2022-03-28T07:38:22+01:00
New Revision: 85b1354098ba0a665fdd47204d0e53e63d09d9ab

URL: https://github.com/llvm/llvm-project/commit/85b1354098ba0a665fdd47204d0e53e63d09d9ab
DIFF: https://github.com/llvm/llvm-project/commit/85b1354098ba0a665fdd47204d0e53e63d09d9ab.diff

LOG: [C++20][Modules][HU 5/5] Add fdirectives-only mode for preprocessing output.

When the -fdirectives-only option is used together with -E, the preprocessor
output reflects evaluation of if/then/else directives.

As such, it preserves defines and undefs of macros that are still live after
such processing.  The intent is that this output could be consumed as input
to generate considered a C++20 header unit.

We strip out any (unused) defines that come from built-in, built-in-file or
command line; these are re-added when the preprocessed source is consumed.

Differential Revision: https://reviews.llvm.org/D121099

Added: 
    clang/test/Modules/cxx20-hu-06.cpp

Modified: 
    clang/include/clang/Driver/Options.td
    clang/include/clang/Frontend/PreprocessorOutputOptions.h
    clang/lib/Frontend/CompilerInvocation.cpp
    clang/lib/Frontend/PrintPreprocessedOutput.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 488692e16145f..ac2f479f159eb 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1873,6 +1873,8 @@ defm rewrite_includes : BoolFOption<"rewrite-includes",
   PreprocessorOutputOpts<"RewriteIncludes">, DefaultFalse,
   PosFlag<SetTrue, [CC1Option]>, NegFlag<SetFalse>>;
 
+defm directives_only : OptInCC1FFlag<"directives-only", "">;
+
 defm delete_null_pointer_checks : BoolFOption<"delete-null-pointer-checks",
   CodeGenOpts<"NullPointerIsValid">, DefaultFalse,
   NegFlag<SetTrue, [CC1Option], "Do not treat usage of null pointers as undefined behavior">,

diff  --git a/clang/include/clang/Frontend/PreprocessorOutputOptions.h b/clang/include/clang/Frontend/PreprocessorOutputOptions.h
index 257538ee06065..d542032431b14 100644
--- a/clang/include/clang/Frontend/PreprocessorOutputOptions.h
+++ b/clang/include/clang/Frontend/PreprocessorOutputOptions.h
@@ -25,6 +25,7 @@ class PreprocessorOutputOptions {
   unsigned RewriteIncludes : 1;    ///< Preprocess include directives only.
   unsigned RewriteImports  : 1;    ///< Include contents of transitively-imported modules.
   unsigned MinimizeWhitespace : 1; ///< Ignore whitespace from input.
+  unsigned DirectivesOnly : 1; ///< Process directives but do not expand macros.
 
 public:
   PreprocessorOutputOptions() {
@@ -38,6 +39,7 @@ class PreprocessorOutputOptions {
     RewriteIncludes = 0;
     RewriteImports = 0;
     MinimizeWhitespace = 0;
+    DirectivesOnly = 0;
   }
 };
 

diff  --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index 5bb480a599713..b222119889522 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -4413,6 +4413,8 @@ static void GeneratePreprocessorOutputArgs(
     GenerateArg(Args, OPT_dM, SA);
   if (!Generate_dM && Opts.ShowMacros)
     GenerateArg(Args, OPT_dD, SA);
+  if (Opts.DirectivesOnly)
+    GenerateArg(Args, OPT_fdirectives_only, SA);
 }
 
 static bool ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
@@ -4435,6 +4437,7 @@ static bool ParsePreprocessorOutputArgs(PreprocessorOutputOptions &Opts,
 
   Opts.ShowCPP = isStrictlyPreprocessorAction(Action) && !Args.hasArg(OPT_dM);
   Opts.ShowMacros = Args.hasArg(OPT_dM) || Args.hasArg(OPT_dD);
+  Opts.DirectivesOnly = Args.hasArg(OPT_fdirectives_only);
 
   return Diags.getNumErrors() == NumErrorsBefore;
 }

diff  --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
index e2fc862849ad1..7737d043043d5 100644
--- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -96,6 +96,7 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
   bool UseLineDirectives;
   bool IsFirstFileEntered;
   bool MinimizeWhitespace;
+  bool DirectivesOnly;
 
   Token PrevTok;
   Token PrevPrevTok;
@@ -103,12 +104,13 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
 public:
   PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream &os, bool lineMarkers,
                            bool defines, bool DumpIncludeDirectives,
-                           bool UseLineDirectives, bool MinimizeWhitespace)
+                           bool UseLineDirectives, bool MinimizeWhitespace,
+                           bool DirectivesOnly)
       : PP(pp), SM(PP.getSourceManager()), ConcatInfo(PP), OS(os),
         DisableLineMarkers(lineMarkers), DumpDefines(defines),
         DumpIncludeDirectives(DumpIncludeDirectives),
         UseLineDirectives(UseLineDirectives),
-        MinimizeWhitespace(MinimizeWhitespace) {
+        MinimizeWhitespace(MinimizeWhitespace), DirectivesOnly(DirectivesOnly) {
     CurLine = 0;
     CurFilename += "<uninit>";
     EmittedTokensOnThisLine = false;
@@ -467,12 +469,21 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) {
 void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
                                             const MacroDirective *MD) {
   const MacroInfo *MI = MD->getMacroInfo();
-  // Only print out macro definitions in -dD mode.
-  if (!DumpDefines ||
+  // Print out macro definitions in -dD mode and when we have -fdirectives-only
+  // for C++20 header units.
+  if ((!DumpDefines && !DirectivesOnly) ||
       // Ignore __FILE__ etc.
-      MI->isBuiltinMacro()) return;
+      MI->isBuiltinMacro())
+    return;
 
-  MoveToLine(MI->getDefinitionLoc(), /*RequireStartOfLine=*/true);
+  SourceLocation DefLoc = MI->getDefinitionLoc();
+  if (DirectivesOnly && !MI->isUsed()) {
+    SourceManager &SM = PP.getSourceManager();
+    if (SM.isWrittenInBuiltinFile(DefLoc) ||
+        SM.isWrittenInCommandLineFile(DefLoc))
+      return;
+  }
+  MoveToLine(DefLoc, /*RequireStartOfLine=*/true);
   PrintMacroDefinition(*MacroNameTok.getIdentifierInfo(), *MI, PP, OS);
   setEmittedDirectiveOnThisLine();
 }
@@ -480,8 +491,10 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
 void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
                                               const MacroDefinition &MD,
                                               const MacroDirective *Undef) {
-  // Only print out macro definitions in -dD mode.
-  if (!DumpDefines) return;
+  // Print out macro definitions in -dD mode and when we have -fdirectives-only
+  // for C++20 header units.
+  if (!DumpDefines && !DirectivesOnly)
+    return;
 
   MoveToLine(MacroNameTok.getLocation(), /*RequireStartOfLine=*/true);
   OS << "#undef " << MacroNameTok.getIdentifierInfo()->getName();
@@ -959,7 +972,7 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
   PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(
       PP, *OS, !Opts.ShowLineMarkers, Opts.ShowMacros,
       Opts.ShowIncludeDirectives, Opts.UseLineDirectives,
-      Opts.MinimizeWhitespace);
+      Opts.MinimizeWhitespace, Opts.DirectivesOnly);
 
   // Expand macros in pragmas with -fms-extensions.  The assumption is that
   // the majority of pragmas in such a file will be Microsoft pragmas.
@@ -995,6 +1008,8 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
 
   // After we have configured the preprocessor, enter the main file.
   PP.EnterMainSourceFile();
+  if (Opts.DirectivesOnly)
+    PP.SetMacroExpansionOnlyInDirectives();
 
   // Consume all of the tokens that come from the predefines buffer.  Those
   // should not be emitted into the output and are guaranteed to be at the

diff  --git a/clang/test/Modules/cxx20-hu-06.cpp b/clang/test/Modules/cxx20-hu-06.cpp
new file mode 100644
index 0000000000000..1048e49164523
--- /dev/null
+++ b/clang/test/Modules/cxx20-hu-06.cpp
@@ -0,0 +1,68 @@
+// Test check that consuming -E -fdirectives-only output produces the expected
+// header unit.
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+// RUN: cd %t
+
+// RUN: %clang_cc1 -std=c++20 -E -fdirectives-only -xc++-user-header hu-01.h \
+// RUN: -o hu-01.iih
+
+// RUN: %clang_cc1 -std=c++20 -emit-header-unit \
+// RUN: -xc++-user-header-cpp-output hu-01.iih -o hu-01.pcm
+
+// RUN: %clang_cc1 -std=c++20 -emit-header-unit -xc++-user-header hu-02.h \
+// RUN: -DFOO -fmodule-file=hu-01.pcm -o hu-02.pcm -Rmodule-import 2>&1 | \
+// RUN: FileCheck --check-prefix=CHECK-IMP %s -DTDIR=%t
+
+//--- hu-01.h
+#ifndef __GUARD
+#define __GUARD
+
+int baz(int);
+#define FORTYTWO 42
+
+#define SHOULD_NOT_BE_DEFINED -1
+#undef SHOULD_NOT_BE_DEFINED
+
+#endif // __GUARD
+// expected-no-diagnostics
+
+//--- hu-02.h
+export import "hu-01.h";
+#if !defined(FORTYTWO) || FORTYTWO != 42
+#error FORTYTWO missing in hu-02
+#endif
+
+#ifndef __GUARD
+#error __GUARD missing in hu-02
+#endif
+
+#ifdef SHOULD_NOT_BE_DEFINED
+#error SHOULD_NOT_BE_DEFINED is visible
+#endif
+
+// Make sure that we have not discarded macros from the builtin file.
+#ifndef __cplusplus
+#error we dropped a defined macro
+#endif
+
+#define KAP 6174
+
+#ifdef FOO
+#define FOO_BRANCH(X) (X) + 1
+inline int foo(int x) {
+  if (x == FORTYTWO)
+    return FOO_BRANCH(x);
+  return FORTYTWO;
+}
+#else
+#define BAR_BRANCH(X) (X) + 2
+inline int bar(int x) {
+  if (x == FORTYTWO)
+    return BAR_BRANCH(x);
+  return FORTYTWO;
+}
+#endif
+// CHECK-IMP: remark: importing module './hu-01.h' from 'hu-01.pcm'


        


More information about the cfe-commits mailing list