jackhong12 updated this revision to Diff 443447.
jackhong12 added a comment.
Herald added subscribers: mstorsjo, MaskRay.
Herald added a reviewer: sscalpone.
Herald added a project: clang-tools-extra.

I added two flags, `-driver-define` and `-driver-undefine`, to indicate macros 
that the driver defines. And I moved driver-defined macros from `<command 
line>` file to `<built-in>` file, like

  # 1 "<built-in>" 3
  #define __llvm__ 1
  #define __clang__ 1
  ...
  # 1 "<command line>" 1
  #define __WHY_NOT_ME__ 1
  #undef __STDC__
  # 1 "<built-in>" 2
  #define __GCC_HAVE_DWARF2_CFI_ASM 1
  ...


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D129061/new/

https://reviews.llvm.org/D129061

Files:
  clang-tools-extra/test/pp-trace/pp-trace-include.cpp
  clang/include/clang/Basic/SourceManager.h
  clang/include/clang/Driver/Options.td
  clang/include/clang/Lex/PreprocessorOptions.h
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/Frontend/InitPreprocessor.cpp
  clang/lib/Lex/PPDirectives.cpp
  clang/test/Driver/cl-runtime-flags.c
  clang/test/Driver/mingw.cpp
  clang/test/Preprocessor/macro-command-line-diagnosis.c

Index: clang/test/Preprocessor/macro-command-line-diagnosis.c
===================================================================
--- /dev/null
+++ clang/test/Preprocessor/macro-command-line-diagnosis.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -Wreserved-identifier -D__WHY_NOT_ME__ -U__STDC__ %s -o - 2>&1 | FileCheck %s
+
+// CHECK:      warning: macro name is a reserved identifier [-Wreserved-macro-identifier]
+// CHECK-NEXT: #define __WHY_NOT_ME__ 1
+// CHECK:      warning: macro name is a reserved identifier [-Wreserved-macro-identifier]
+// CHECK-NEXT: #undef __STDC__
Index: clang/test/Driver/mingw.cpp
===================================================================
--- clang/test/Driver/mingw.cpp
+++ clang/test/Driver/mingw.cpp
@@ -61,7 +61,7 @@
 // RUN: %clang -target i686-windows-gnu -E -### %s 2>&1 | FileCheck -check-prefix=CHECK_MINGW_NO_UNICODE %s
 // RUN: %clang -target i686-windows-gnu -E -### %s -municode 2>&1 | FileCheck -check-prefix=CHECK_MINGW_UNICODE %s
 // CHECK_MINGW_NO_UNICODE-NOT: "-DUNICODE"
-// CHECK_MINGW_UNICODE: "-DUNICODE"
+// CHECK_MINGW_UNICODE: "-driver-define UNICODE"
 
 // RUN: %clang -target i686-windows-gnu -### %s 2>&1 | FileCheck -check-prefix=CHECK_NO_SUBSYS %s
 // RUN: %clang -target i686-windows-gnu -### %s -mwindows -mconsole 2>&1 | FileCheck -check-prefix=CHECK_SUBSYS_CONSOLE %s
Index: clang/test/Driver/cl-runtime-flags.c
===================================================================
--- clang/test/Driver/cl-runtime-flags.c
+++ clang/test/Driver/cl-runtime-flags.c
@@ -3,85 +3,85 @@
 
 // First check that regular clang doesn't do any of this stuff.
 // RUN: %clang -### %s 2>&1 | FileCheck -check-prefix=CHECK-CLANG %s
-// CHECK-CLANG-NOT: "-D_DEBUG"
-// CHECK-CLANG-NOT: "-D_MT"
-// CHECK-CLANG-NOT: "-D_DLL"
+// CHECK-CLANG-NOT: "-driver-define _DEBUG"
+// CHECK-CLANG-NOT: "-driver-define _MT"
+// CHECK-CLANG-NOT: "-driver-define _DLL"
 // CHECK-CLANG-NOT: --dependent-lib
 
 // RUN: %clang_cl -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-MT %s
 // RUN: %clang_cl -### /MT -- %s 2>&1 | FileCheck -check-prefix=CHECK-MT %s
-// CHECK-MT-NOT: "-D_DEBUG"
-// CHECK-MT: "-D_MT"
-// CHECK-MT-NOT: "-D_DLL"
+// CHECK-MT-NOT: "-driver-define _DEBUG"
+// CHECK-MT: "-driver-define _MT"
+// CHECK-MT-NOT: "-driver-define _DLL"
 // CHECK-MT: "-flto-visibility-public-std"
 // CHECK-MT: "--dependent-lib=libcmt"
 // CHECK-MT: "--dependent-lib=oldnames"
 
 // RUN: %clang_cl -### /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTd %s
 // RUN: %clang_cl -### /LD /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTd %s
-// CHECK-MTd: "-D_DEBUG"
-// CHECK-MTd: "-D_MT"
-// CHECK-MTd-NOT: "-D_DLL"
+// CHECK-MTd: "-driver-define _DEBUG"
+// CHECK-MTd: "-driver-define _MT"
+// CHECK-MTd-NOT: "-driver-define _DLL"
 // CHECK-MTd: "-flto-visibility-public-std"
 // CHECK-MTd: "--dependent-lib=libcmtd"
 // CHECK-MTd: "--dependent-lib=oldnames"
 
 // RUN: %clang_cl -### /MD -- %s 2>&1 | FileCheck -check-prefix=CHECK-MD %s
-// CHECK-MD-NOT: "-D_DEBUG"
-// CHECK-MD: "-D_MT"
-// CHECK-MD: "-D_DLL"
+// CHECK-MD-NOT: "-driver-define _DEBUG"
+// CHECK-MD: "-driver-define _MT"
+// CHECK-MD: "-driver-define _DLL"
 // CHECK-MD: "--dependent-lib=msvcrt"
 // CHECK-MD: "--dependent-lib=oldnames"
 
 // RUN: %clang_cl -### /MDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MDd %s
-// CHECK-MDd: "-D_DEBUG"
-// CHECK-MDd: "-D_MT"
-// CHECK-MDd: "-D_DLL"
+// CHECK-MDd: "-driver-define _DEBUG"
+// CHECK-MDd: "-driver-define _MT"
+// CHECK-MDd: "-driver-define _DLL"
 // CHECK-MDd: "--dependent-lib=msvcrtd"
 // CHECK-MDd: "--dependent-lib=oldnames"
 
 // RUN: %clang_cl -### /LD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LD %s
 // RUN: %clang_cl -### /LD /MT -- %s 2>&1 | FileCheck -check-prefix=CHECK-LD %s
-// CHECK-LD-NOT: "-D_DEBUG"
-// CHECK-LD: "-D_MT"
-// CHECK-LD-NOT: "-D_DLL"
+// CHECK-LD-NOT: "-driver-define _DEBUG"
+// CHECK-LD: "-driver-define _MT"
+// CHECK-LD-NOT: "-driver-define _DLL"
 // CHECK-LD: "--dependent-lib=libcmt"
 
 // RUN: %clang_cl -### /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDd %s
 // RUN: %clang_cl -### /LDd /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDd %s
-// CHECK-LDd: "-D_DEBUG"
-// CHECK-LDd: "-D_MT"
-// CHECK-LDd-NOT: "-D_DLL"
+// CHECK-LDd: "-driver-define _DEBUG"
+// CHECK-LDd: "-driver-define _MT"
+// CHECK-LDd-NOT: "-driver-define _DLL"
 // CHECK-LDd: "--dependent-lib=libcmtd"
 
 // RUN: %clang_cl -### /LDd /MT -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMT %s
 // RUN: %clang_cl -### /MT /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMT %s
-// CHECK-LDdMT: "-D_DEBUG"
-// CHECK-LDdMT: "-D_MT"
-// CHECK-LDdMT-NOT: "-D_DLL"
+// CHECK-LDdMT: "-driver-define _DEBUG"
+// CHECK-LDdMT: "-driver-define _MT"
+// CHECK-LDdMT-NOT: "-driver-define _DLL"
 // CHECK-LDdMT: "--dependent-lib=libcmt"
 
 // RUN: %clang_cl -### /LD /MD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMD %s
 // RUN: %clang_cl -### /MD /LD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMD %s
-// CHECK-LDMD-NOT: "-D_DEBUG"
-// CHECK-LDMD: "-D_MT"
-// CHECK-LDMD: "-D_DLL"
+// CHECK-LDMD-NOT: "-driver-define _DEBUG"
+// CHECK-LDMD: "-driver-define _MT"
+// CHECK-LDMD: "-driver-define _DLL"
 // CHECK-LDMD: "--dependent-lib=msvcrt"
 
 // RUN: %clang_cl -### /LDd /MD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMD %s
 // RUN: %clang_cl -### /MD /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDdMD %s
-// CHECK-LDdMD: "-D_DEBUG"
-// CHECK-LDdMD: "-D_MT"
-// CHECK-LDdMD: "-D_DLL"
+// CHECK-LDdMD: "-driver-define _DEBUG"
+// CHECK-LDdMD: "-driver-define _MT"
+// CHECK-LDdMD: "-driver-define _DLL"
 // CHECK-LDdMD: "--dependent-lib=msvcrt"
 
 // RUN: %clang_cl -### /LD /MDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
 // RUN: %clang_cl -### /MDd /LD -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
 // RUN: %clang_cl -### /LDd /MDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
 // RUN: %clang_cl -### /MDd /LDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-LDMDd %s
-// CHECK-LDMDd: "-D_DEBUG"
-// CHECK-LDMDd: "-D_MT"
-// CHECK-LDMDd: "-D_DLL"
+// CHECK-LDMDd: "-driver-define _DEBUG"
+// CHECK-LDMDd: "-driver-define _MT"
+// CHECK-LDMDd: "-driver-define _DLL"
 // CHECK-LDMDd: "--dependent-lib=msvcrtd"
 
 // RUN: %clang_cl /MD /MT -### -- %s 2>&1 | FileCheck -check-prefix=MTOVERRIDE %s
@@ -89,9 +89,9 @@
 
 // RUN: %clang_cl -### /Zl -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTZl %s
 // RUN: %clang_cl -### /MT /Zl -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTZl %s
-// CHECK-MTZl-NOT: "-D_DEBUG"
-// CHECK-MTZl: "-D_MT"
-// CHECK-MTZl-NOT: "-D_DLL"
-// CHECK-MTZl-SAME: "-D_VC_NODEFAULTLIB"
+// CHECK-MTZl-NOT: "-driver-define _DEBUG"
+// CHECK-MTZl: "-driver-define _MT"
+// CHECK-MTZl-NOT: "-driver-define _DLL"
+// CHECK-MTZl-SAME: "-driver-define _VC_NODEFAULTLIB"
 // CHECK-MTZl-NOT: "--dependent-lib=libcmt"
 // CHECK-MTZl-NOT: "--dependent-lib=oldnames"
Index: clang/lib/Lex/PPDirectives.cpp
===================================================================
--- clang/lib/Lex/PPDirectives.cpp
+++ clang/lib/Lex/PPDirectives.cpp
@@ -352,8 +352,10 @@
   SourceLocation MacroNameLoc = MacroNameTok.getLocation();
   if (ShadowFlag)
     *ShadowFlag = false;
-  if (!SourceMgr.isInSystemHeader(MacroNameLoc) &&
-      (SourceMgr.getBufferName(MacroNameLoc) != "<built-in>")) {
+  PresumedLoc PL = SourceMgr.getPresumedLoc(MacroNameLoc);
+  const char *const FileName = PL.isValid() ? PL.getFilename() : nullptr;
+  if (!SourceMgr.isInSystemHeader(MacroNameLoc) && FileName != nullptr &&
+      strcmp(FileName, "<built-in>") && strcmp(FileName, "<driver define>")) {
     MacroDiag D = MD_NoWarn;
     if (isDefineUndef == MU_Define) {
       D = shouldWarnOnMacroDef(*this, II);
@@ -1589,6 +1591,7 @@
     if (ReadLineMarkerFlags(IsFileEntry, IsFileExit, FileKind, *this))
       return;
     if (!SourceMgr.isWrittenInBuiltinFile(DigitTok.getLocation()) &&
+        !SourceMgr.isWrittenInDriverDefineFile(DigitTok.getLocation()) &&
         !SourceMgr.isWrittenInCommandLineFile(DigitTok.getLocation()))
       Diag(StrTok, diag::ext_pp_gnu_line_directive);
 
Index: clang/lib/Frontend/InitPreprocessor.cpp
===================================================================
--- clang/lib/Frontend/InitPreprocessor.cpp
+++ clang/lib/Frontend/InitPreprocessor.cpp
@@ -1372,6 +1372,15 @@
   if (!PP.getLangOpts().AsmPreprocessor)
     Builder.append("# 1 \"<built-in>\" 2");
 
+  // Process driver defined macros
+  for (unsigned i = 0, e = InitOpts.DriverMacros.size(); i != e; ++i) {
+    if (InitOpts.DriverMacros[i].second) // isUndef
+      Builder.undefineMacro(InitOpts.DriverMacros[i].first);
+    else
+      DefineBuiltinMacro(Builder, InitOpts.DriverMacros[i].first,
+                         PP.getDiagnostics());
+  }
+
   // If -imacros are specified, include them now.  These are processed before
   // any -include directives.
   for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i)
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -4173,6 +4173,10 @@
     GenerateArg(Args, M.second ? OPT_U : OPT_D, M.first, SA);
   }
 
+  for (const auto &DM : Opts.DriverMacros)
+    GenerateArg(Args, DM.second ? OPT_DriverUndefine : OPT_DriverDefine,
+                DM.first, SA);
+
   for (const auto &I : Opts.Includes) {
     // Don't generate OpenCL includes. They are implied by other flags that are
     // generated elsewhere.
@@ -4258,6 +4262,14 @@
       Opts.addMacroUndef(A->getValue());
   }
 
+  // Add driver defined macros
+  for (const auto *A : Args.filtered(OPT_DriverDefine, OPT_DriverUndefine)) {
+    if (A->getOption().matches(OPT_DriverDefine))
+      Opts.addDriverMacroDef(A->getValue());
+    else
+      Opts.addDriverMacroUndef(A->getValue());
+  }
+
   // Add the ordered list of -includes.
   for (const auto *A : Args.filtered(OPT_include))
     Opts.Includes.emplace_back(A->getValue());
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -4915,7 +4915,7 @@
     CmdArgs.push_back("-static-define");
 
   if (Args.hasArg(options::OPT_municode))
-    CmdArgs.push_back("-DUNICODE");
+    CmdArgs.push_back("-driver-define UNICODE");
 
   if (isa<AnalyzeJobAction>(JA))
     RenderAnalyzerOptions(Args, CmdArgs, Triple, Input);
@@ -7178,7 +7178,7 @@
   if ((Triple.isOSBinFormatELF() || Triple.isOSBinFormatMachO()) &&
       (EH || AsyncUnwindTables || UnwindTables ||
        DebugInfoKind != codegenoptions::NoDebugInfo))
-    CmdArgs.push_back("-D__GCC_HAVE_DWARF2_CFI_ASM=1");
+    CmdArgs.push_back("-driver-define__GCC_HAVE_DWARF2_CFI_ASM=1");
 
   if (Arg *A = Args.getLastArg(options::OPT_fsymbol_partition_EQ)) {
     std::string Str = A->getAsString(Args);
@@ -7498,27 +7498,27 @@
   switch (RTOptionID) {
   case options::OPT__SLASH_MD:
     if (Args.hasArg(options::OPT__SLASH_LDd))
-      CmdArgs.push_back("-D_DEBUG");
-    CmdArgs.push_back("-D_MT");
-    CmdArgs.push_back("-D_DLL");
+      CmdArgs.push_back("-driver-define _DEBUG");
+    CmdArgs.push_back("-driver-define _MT");
+    CmdArgs.push_back("-driver-define _DLL");
     FlagForCRT = "--dependent-lib=msvcrt";
     break;
   case options::OPT__SLASH_MDd:
-    CmdArgs.push_back("-D_DEBUG");
-    CmdArgs.push_back("-D_MT");
-    CmdArgs.push_back("-D_DLL");
+    CmdArgs.push_back("-driver-define _DEBUG");
+    CmdArgs.push_back("-driver-define _MT");
+    CmdArgs.push_back("-driver-define _DLL");
     FlagForCRT = "--dependent-lib=msvcrtd";
     break;
   case options::OPT__SLASH_MT:
     if (Args.hasArg(options::OPT__SLASH_LDd))
-      CmdArgs.push_back("-D_DEBUG");
-    CmdArgs.push_back("-D_MT");
+      CmdArgs.push_back("-driver-define _DEBUG");
+    CmdArgs.push_back("-driver-define _MT");
     CmdArgs.push_back("-flto-visibility-public-std");
     FlagForCRT = "--dependent-lib=libcmt";
     break;
   case options::OPT__SLASH_MTd:
-    CmdArgs.push_back("-D_DEBUG");
-    CmdArgs.push_back("-D_MT");
+    CmdArgs.push_back("-driver-define _DEBUG");
+    CmdArgs.push_back("-driver-define _MT");
     CmdArgs.push_back("-flto-visibility-public-std");
     FlagForCRT = "--dependent-lib=libcmtd";
     break;
@@ -7527,7 +7527,7 @@
   }
 
   if (Args.hasArg(options::OPT__SLASH_Zl)) {
-    CmdArgs.push_back("-D_VC_NODEFAULTLIB");
+    CmdArgs.push_back("-driver-define _VC_NODEFAULTLIB");
   } else {
     CmdArgs.push_back(FlagForCRT.data());
 
Index: clang/include/clang/Lex/PreprocessorOptions.h
===================================================================
--- clang/include/clang/Lex/PreprocessorOptions.h
+++ clang/include/clang/Lex/PreprocessorOptions.h
@@ -64,7 +64,7 @@
 /// used in preprocessor initialization to InitializePreprocessor().
 class PreprocessorOptions {
 public:
-  std::vector<std::pair<std::string, bool/*isUndef*/>> Macros;
+  std::vector<std::pair<std::string, bool /*isUndef*/>> Macros, DriverMacros;
   std::vector<std::string> Includes;
   std::vector<std::string> MacroIncludes;
 
@@ -230,6 +230,13 @@
     Macros.emplace_back(std::string(Name), true);
   }
 
+  void addDriverMacroDef(StringRef Name) {
+    DriverMacros.emplace_back(std::string(Name), false);
+  }
+  void addDriverMacroUndef(StringRef Name) {
+    DriverMacros.emplace_back(std::string(Name), true);
+  }
+
   void addRemappedFile(StringRef From, StringRef To) {
     RemappedFiles.emplace_back(std::string(From), std::string(To));
   }
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -661,6 +661,9 @@
 def D : JoinedOrSeparate<["-"], "D">, Group<Preprocessor_Group>,
     Flags<[CC1Option, FlangOption, FC1Option]>, MetaVarName<"<macro>=<value>">,
     HelpText<"Define <macro> to <value> (or 1 if <value> omitted)">;
+def DriverDefine : JoinedOrSeparate<["-"], "driver-define">, Group<Preprocessor_Group>,
+    Flags<[CC1Option, FlangOption, FC1Option]>, MetaVarName<"<macro>=<value>">,
+    HelpText<"Define <macro> to <value> (or 1 if <value> omitted)">;
 def E : Flag<["-"], "E">, Flags<[NoXarchOption,CC1Option, FlangOption, FC1Option]>, Group<Action_Group>,
     HelpText<"Only run the preprocessor">;
 def F : JoinedOrSeparate<["-"], "F">, Flags<[RenderJoined,CC1Option]>,
@@ -769,6 +772,8 @@
   MetaVarName<"<script>">, HelpText<"Specify <script> as linker script">;
 def U : JoinedOrSeparate<["-"], "U">, Group<Preprocessor_Group>,
   Flags<[CC1Option, FlangOption, FC1Option]>, MetaVarName<"<macro>">, HelpText<"Undefine macro <macro>">;
+def DriverUndefine : JoinedOrSeparate<["-"], "driver-undefine">, Group<Preprocessor_Group>,
+  Flags<[CC1Option, FlangOption, FC1Option]>, MetaVarName<"<macro>">, HelpText<"Undefine macro <macro>">;
 def V : JoinedOrSeparate<["-"], "V">, Flags<[NoXarchOption, Unsupported]>;
 def Wa_COMMA : CommaJoined<["-"], "Wa,">,
   HelpText<"Pass the comma separated arguments in <arg> to the assembler">,
Index: clang/include/clang/Basic/SourceManager.h
===================================================================
--- clang/include/clang/Basic/SourceManager.h
+++ clang/include/clang/Basic/SourceManager.h
@@ -1480,6 +1480,15 @@
     return Filename.equals("<built-in>");
   }
 
+  /// Returns whether \p Loc is located in a <driver define> file.
+  bool isWrittenInDriverDefineFile(SourceLocation Loc) const {
+    PresumedLoc Presumed = getPresumedLoc(Loc);
+    if (Presumed.isInvalid())
+      return false;
+    StringRef Filename(Presumed.getFilename());
+    return Filename.equals("<driver define>");
+  }
+
   /// Returns whether \p Loc is located in a <command line> file.
   bool isWrittenInCommandLineFile(SourceLocation Loc) const {
     PresumedLoc Presumed = getPresumedLoc(Loc);
Index: clang-tools-extra/test/pp-trace/pp-trace-include.cpp
===================================================================
--- clang-tools-extra/test/pp-trace/pp-trace-include.cpp
+++ clang-tools-extra/test/pp-trace/pp-trace-include.cpp
@@ -39,13 +39,13 @@
 // CHECK-NEXT:   Reason: EnterFile
 // CHECK-NEXT:   FileType: C_User
 // CHECK-NEXT:   PrevFID: (invalid)
-// CHECK:      - Callback: MacroDefined
 // CHECK:      - Callback: FileChanged
 // CHECK-NEXT:   Loc: "<built-in>:1:1"
 // CHECK-NEXT:   Reason: ExitFile
 // CHECK-NEXT:   FileType: C_User
 // CHECK-NEXT:   PrevFID: (invalid)
-// CHECK-NEXT: - Callback: FileChanged
+// CHECK:      - Callback: MacroDefined
+// CHECK:      - Callback: FileChanged
 // CHECK-NEXT:   Loc: "{{.*}}{{[/\\]}}pp-trace-include.cpp:1:1"
 // CHECK-NEXT:   Reason: ExitFile
 // CHECK-NEXT:   FileType: C_User
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to