Szelethus created this revision.
Szelethus added reviewers: NoQ, xazax.hun, a_sidorin, baloghadamsoftware, 
rnkovacs, dcoughlin.
Szelethus added a project: clang.
Herald added subscribers: cfe-commits, Charusso, gamesh411, dkrupp, donat.nagy, 
mikhail.ramalho, a.sidorin, szepet, whisperity.

For the following terminator statement:

  if (A && B && C && D)

The built CFG is the following:

  [B5 (ENTRY)]
    Succs (1): B4
  
  [B1]
    1: 10
    2: j
    3: [B1.2] (ImplicitCastExpr, LValueToRValue, int)
    4: [B1.1] / [B1.3]
    5: int x = 10 / j;
    Preds (1): B2
    Succs (1): B0
  
  [B2]
    1: C
    2: [B2.1] (ImplicitCastExpr, LValueToRValue, _Bool)
    T: if [B4.4] && [B3.2] && [B2.2]
    Preds (1): B3
    Succs (2): B1 B0
  
  [B3]
    1: B
    2: [B3.1] (ImplicitCastExpr, LValueToRValue, _Bool)
    T: [B4.4] && [B3.2] && ...
    Preds (1): B4
    Succs (2): B2 B0
  
  [B4]
    1: 0
    2: int j = 0;
    3: A
    4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool)
    T: [B4.4] && ...
    Preds (1): B5
    Succs (2): B3 B0
  
  [B0 (EXIT)]
    Preds (4): B1 B2 B3 B4

However, even though the path of execution in B2 <https://reviews.llvm.org/B2> 
only depends on C's value, `CFGBlock::getCondition()` would return the entire 
condition (`A && B && C`). For B3 <https://reviews.llvm.org/B3>, it would 
return `A && B`. I changed this the actual condition.

The tests show an addition of an extra arrow for `ObjCForCollectionStmt`, all 
of them similar to this:
F9306419: image.png <https://reviews.llvm.org/F9306419>
(the first arrow the addition)


Repository:
  rC Clang

https://reviews.llvm.org/D63538

Files:
  clang/include/clang/Analysis/CFG.h
  clang/lib/Analysis/CFG.cpp
  clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
  clang/test/Analysis/Inputs/expected-plists/plist-output.m.plist

Index: clang/test/Analysis/Inputs/expected-plists/plist-output.m.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/plist-output.m.plist
+++ clang/test/Analysis/Inputs/expected-plists/plist-output.m.plist
@@ -5743,11 +5743,45 @@
       </array>
     </dict>
     <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>160</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>160</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>160</integer>
+           <key>col</key><integer>18</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>160</integer>
+           <key>col</key><integer>20</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
      <key>kind</key><string>event</string>
      <key>location</key>
      <dict>
       <key>line</key><integer>160</integer>
-      <key>col</key><integer>8</integer>
+      <key>col</key><integer>18</integer>
       <key>file</key><integer>0</integer>
      </dict>
      <key>ranges</key>
@@ -5755,12 +5789,12 @@
        <array>
         <dict>
          <key>line</key><integer>160</integer>
-         <key>col</key><integer>8</integer>
+         <key>col</key><integer>18</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
          <key>line</key><integer>160</integer>
-         <key>col</key><integer>13</integer>
+         <key>col</key><integer>20</integer>
          <key>file</key><integer>0</integer>
         </dict>
        </array>
@@ -5780,12 +5814,12 @@
          <array>
           <dict>
            <key>line</key><integer>160</integer>
-           <key>col</key><integer>3</integer>
+           <key>col</key><integer>18</integer>
            <key>file</key><integer>0</integer>
           </dict>
           <dict>
            <key>line</key><integer>160</integer>
-           <key>col</key><integer>5</integer>
+           <key>col</key><integer>20</integer>
            <key>file</key><integer>0</integer>
           </dict>
          </array>
Index: clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
+++ clang/test/Analysis/Inputs/expected-plists/edges-new.mm.plist
@@ -2182,11 +2182,45 @@
       </array>
     </dict>
     <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>131</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>131</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>131</integer>
+           <key>col</key><integer>15</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>131</integer>
+           <key>col</key><integer>15</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
      <key>kind</key><string>event</string>
      <key>location</key>
      <dict>
       <key>line</key><integer>131</integer>
-      <key>col</key><integer>8</integer>
+      <key>col</key><integer>15</integer>
       <key>file</key><integer>0</integer>
      </dict>
      <key>ranges</key>
@@ -2194,12 +2228,12 @@
        <array>
         <dict>
          <key>line</key><integer>131</integer>
-         <key>col</key><integer>8</integer>
+         <key>col</key><integer>15</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
          <key>line</key><integer>131</integer>
-         <key>col</key><integer>10</integer>
+         <key>col</key><integer>15</integer>
          <key>file</key><integer>0</integer>
         </dict>
        </array>
@@ -2219,12 +2253,12 @@
          <array>
           <dict>
            <key>line</key><integer>131</integer>
-           <key>col</key><integer>3</integer>
+           <key>col</key><integer>15</integer>
            <key>file</key><integer>0</integer>
           </dict>
           <dict>
            <key>line</key><integer>131</integer>
-           <key>col</key><integer>5</integer>
+           <key>col</key><integer>15</integer>
            <key>file</key><integer>0</integer>
           </dict>
          </array>
@@ -2457,11 +2491,45 @@
       </array>
     </dict>
     <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>137</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>137</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>137</integer>
+           <key>col</key><integer>18</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>137</integer>
+           <key>col</key><integer>20</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
      <key>kind</key><string>event</string>
      <key>location</key>
      <dict>
       <key>line</key><integer>137</integer>
-      <key>col</key><integer>8</integer>
+      <key>col</key><integer>18</integer>
       <key>file</key><integer>0</integer>
      </dict>
      <key>ranges</key>
@@ -2469,12 +2537,12 @@
        <array>
         <dict>
          <key>line</key><integer>137</integer>
-         <key>col</key><integer>8</integer>
+         <key>col</key><integer>18</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
          <key>line</key><integer>137</integer>
-         <key>col</key><integer>13</integer>
+         <key>col</key><integer>20</integer>
          <key>file</key><integer>0</integer>
         </dict>
        </array>
@@ -2494,12 +2562,12 @@
          <array>
           <dict>
            <key>line</key><integer>137</integer>
-           <key>col</key><integer>3</integer>
+           <key>col</key><integer>18</integer>
            <key>file</key><integer>0</integer>
           </dict>
           <dict>
            <key>line</key><integer>137</integer>
-           <key>col</key><integer>5</integer>
+           <key>col</key><integer>20</integer>
            <key>file</key><integer>0</integer>
           </dict>
          </array>
@@ -13397,11 +13465,45 @@
       </array>
     </dict>
     <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>16</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>20</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
      <key>kind</key><string>event</string>
      <key>location</key>
      <dict>
       <key>line</key><integer>467</integer>
-      <key>col</key><integer>8</integer>
+      <key>col</key><integer>16</integer>
       <key>file</key><integer>0</integer>
      </dict>
      <key>ranges</key>
@@ -13409,12 +13511,12 @@
        <array>
         <dict>
          <key>line</key><integer>467</integer>
-         <key>col</key><integer>8</integer>
+         <key>col</key><integer>16</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
          <key>line</key><integer>467</integer>
-         <key>col</key><integer>11</integer>
+         <key>col</key><integer>20</integer>
          <key>file</key><integer>0</integer>
         </dict>
        </array>
@@ -13434,12 +13536,12 @@
          <array>
           <dict>
            <key>line</key><integer>467</integer>
-           <key>col</key><integer>3</integer>
+           <key>col</key><integer>16</integer>
            <key>file</key><integer>0</integer>
           </dict>
           <dict>
            <key>line</key><integer>467</integer>
-           <key>col</key><integer>5</integer>
+           <key>col</key><integer>20</integer>
            <key>file</key><integer>0</integer>
           </dict>
          </array>
@@ -14021,11 +14123,45 @@
       </array>
     </dict>
     <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>16</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>20</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
      <key>kind</key><string>event</string>
      <key>location</key>
      <dict>
       <key>line</key><integer>467</integer>
-      <key>col</key><integer>8</integer>
+      <key>col</key><integer>16</integer>
       <key>file</key><integer>0</integer>
      </dict>
      <key>ranges</key>
@@ -14033,12 +14169,12 @@
        <array>
         <dict>
          <key>line</key><integer>467</integer>
-         <key>col</key><integer>8</integer>
+         <key>col</key><integer>16</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
          <key>line</key><integer>467</integer>
-         <key>col</key><integer>11</integer>
+         <key>col</key><integer>20</integer>
          <key>file</key><integer>0</integer>
         </dict>
        </array>
@@ -14058,12 +14194,12 @@
          <array>
           <dict>
            <key>line</key><integer>467</integer>
-           <key>col</key><integer>3</integer>
+           <key>col</key><integer>16</integer>
            <key>file</key><integer>0</integer>
           </dict>
           <dict>
            <key>line</key><integer>467</integer>
-           <key>col</key><integer>5</integer>
+           <key>col</key><integer>20</integer>
            <key>file</key><integer>0</integer>
           </dict>
          </array>
@@ -15564,11 +15700,45 @@
       </array>
     </dict>
     <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>16</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>20</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
      <key>kind</key><string>event</string>
      <key>location</key>
      <dict>
       <key>line</key><integer>467</integer>
-      <key>col</key><integer>8</integer>
+      <key>col</key><integer>16</integer>
       <key>file</key><integer>0</integer>
      </dict>
      <key>ranges</key>
@@ -15576,12 +15746,12 @@
        <array>
         <dict>
          <key>line</key><integer>467</integer>
-         <key>col</key><integer>8</integer>
+         <key>col</key><integer>16</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
          <key>line</key><integer>467</integer>
-         <key>col</key><integer>11</integer>
+         <key>col</key><integer>20</integer>
          <key>file</key><integer>0</integer>
         </dict>
        </array>
@@ -15601,12 +15771,12 @@
          <array>
           <dict>
            <key>line</key><integer>467</integer>
-           <key>col</key><integer>3</integer>
+           <key>col</key><integer>16</integer>
            <key>file</key><integer>0</integer>
           </dict>
           <dict>
            <key>line</key><integer>467</integer>
-           <key>col</key><integer>5</integer>
+           <key>col</key><integer>20</integer>
            <key>file</key><integer>0</integer>
           </dict>
          </array>
@@ -17234,11 +17404,45 @@
       </array>
     </dict>
     <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>16</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>20</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
      <key>kind</key><string>event</string>
      <key>location</key>
      <dict>
       <key>line</key><integer>467</integer>
-      <key>col</key><integer>8</integer>
+      <key>col</key><integer>16</integer>
       <key>file</key><integer>0</integer>
      </dict>
      <key>ranges</key>
@@ -17246,12 +17450,12 @@
        <array>
         <dict>
          <key>line</key><integer>467</integer>
-         <key>col</key><integer>8</integer>
+         <key>col</key><integer>16</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
          <key>line</key><integer>467</integer>
-         <key>col</key><integer>11</integer>
+         <key>col</key><integer>20</integer>
          <key>file</key><integer>0</integer>
         </dict>
        </array>
@@ -17271,12 +17475,12 @@
          <array>
           <dict>
            <key>line</key><integer>467</integer>
-           <key>col</key><integer>3</integer>
+           <key>col</key><integer>16</integer>
            <key>file</key><integer>0</integer>
           </dict>
           <dict>
            <key>line</key><integer>467</integer>
-           <key>col</key><integer>5</integer>
+           <key>col</key><integer>20</integer>
            <key>file</key><integer>0</integer>
           </dict>
          </array>
@@ -19129,11 +19333,45 @@
       </array>
     </dict>
     <dict>
+     <key>kind</key><string>control</string>
+     <key>edges</key>
+      <array>
+       <dict>
+        <key>start</key>
+         <array>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>3</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>5</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+        <key>end</key>
+         <array>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>16</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+          <dict>
+           <key>line</key><integer>467</integer>
+           <key>col</key><integer>20</integer>
+           <key>file</key><integer>0</integer>
+          </dict>
+         </array>
+       </dict>
+      </array>
+    </dict>
+    <dict>
      <key>kind</key><string>event</string>
      <key>location</key>
      <dict>
       <key>line</key><integer>467</integer>
-      <key>col</key><integer>8</integer>
+      <key>col</key><integer>16</integer>
       <key>file</key><integer>0</integer>
      </dict>
      <key>ranges</key>
@@ -19141,12 +19379,12 @@
        <array>
         <dict>
          <key>line</key><integer>467</integer>
-         <key>col</key><integer>8</integer>
+         <key>col</key><integer>16</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
          <key>line</key><integer>467</integer>
-         <key>col</key><integer>11</integer>
+         <key>col</key><integer>20</integer>
          <key>file</key><integer>0</integer>
         </dict>
        </array>
@@ -19166,12 +19404,12 @@
          <array>
           <dict>
            <key>line</key><integer>467</integer>
-           <key>col</key><integer>3</integer>
+           <key>col</key><integer>16</integer>
            <key>file</key><integer>0</integer>
           </dict>
           <dict>
            <key>line</key><integer>467</integer>
-           <key>col</key><integer>5</integer>
+           <key>col</key><integer>20</integer>
            <key>file</key><integer>0</integer>
           </dict>
          </array>
Index: clang/lib/Analysis/CFG.cpp
===================================================================
--- clang/lib/Analysis/CFG.cpp
+++ clang/lib/Analysis/CFG.cpp
@@ -5615,69 +5615,27 @@
   Out << JsonFormat(TempOut.str(), AddQuotes);
 }
 
-Stmt *CFGBlock::getTerminatorCondition(bool StripParens) {
-  Stmt *Terminator = getTerminatorStmt();
-  if (!Terminator)
+const Expr *CFGBlock::getTerminatorCondition(bool StripParens) const {
+  // If the terminator is a temporary dtor or a virtual base, etc, we can't
+  // retrieve a meaningful condition, bail out.
+  if (rbegin()->getKind() != CFGElement::Kind::Statement)
     return nullptr;
 
-  Expr *E = nullptr;
+  // This should be the condition of the terminator block.
+  const Stmt *S = rbegin()->castAs<CFGStmt>().getStmt();
+  assert(S);
 
-  switch (Terminator->getStmtClass()) {
-    default:
-      break;
-
-    case Stmt::CXXForRangeStmtClass:
-      E = cast<CXXForRangeStmt>(Terminator)->getCond();
-      break;
-
-    case Stmt::ForStmtClass:
-      E = cast<ForStmt>(Terminator)->getCond();
-      break;
-
-    case Stmt::WhileStmtClass:
-      E = cast<WhileStmt>(Terminator)->getCond();
-      break;
-
-    case Stmt::DoStmtClass:
-      E = cast<DoStmt>(Terminator)->getCond();
-      break;
-
-    case Stmt::IfStmtClass:
-      E = cast<IfStmt>(Terminator)->getCond();
-      break;
-
-    case Stmt::ChooseExprClass:
-      E = cast<ChooseExpr>(Terminator)->getCond();
-      break;
-
-    case Stmt::IndirectGotoStmtClass:
-      E = cast<IndirectGotoStmt>(Terminator)->getTarget();
-      break;
-
-    case Stmt::SwitchStmtClass:
-      E = cast<SwitchStmt>(Terminator)->getCond();
-      break;
-
-    case Stmt::BinaryConditionalOperatorClass:
-      E = cast<BinaryConditionalOperator>(Terminator)->getCond();
-      break;
+  const Expr *Cond;
 
-    case Stmt::ConditionalOperatorClass:
-      E = cast<ConditionalOperator>(Terminator)->getCond();
-      break;
+  if (!(Cond = dyn_cast<Expr>(S))) {
+    // Only ObjCForCollectionStmt is known not to be a non-Expr terminator.
+    const auto *O = cast<ObjCForCollectionStmt>(S);
 
-    case Stmt::BinaryOperatorClass: // '&&' and '||'
-      E = cast<BinaryOperator>(Terminator)->getLHS();
-      break;
-
-    case Stmt::ObjCForCollectionStmtClass:
-      return Terminator;
+    Cond = O->getCollection();
   }
 
-  if (!StripParens)
-    return E;
-
-  return E ? E->IgnoreParens() : nullptr;
+  assert(Cond);
+  return StripParens ? Cond->IgnoreParens() : Cond;
 }
 
 //===----------------------------------------------------------------------===//
Index: clang/include/clang/Analysis/CFG.h
===================================================================
--- clang/include/clang/Analysis/CFG.h
+++ clang/include/clang/Analysis/CFG.h
@@ -860,11 +860,9 @@
   Stmt *getTerminatorStmt() { return Terminator.getStmt(); }
   const Stmt *getTerminatorStmt() const { return Terminator.getStmt(); }
 
-  Stmt *getTerminatorCondition(bool StripParens = true);
-
-  const Stmt *getTerminatorCondition(bool StripParens = true) const {
-    return const_cast<CFGBlock*>(this)->getTerminatorCondition(StripParens);
-  }
+  /// \returns the condition of the terminator (condition of an if statement,
+  /// for loop, etc).
+  const Expr *getTerminatorCondition(bool StripParens = true) const;
 
   const Stmt *getLoopTarget() const { return LoopTarget; }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to