tint/uniformity: Rework generation of diagnostics

Flip the diagnostics so that the trigger location is on the builtin
that requires uniformity.

We also now show the place at which control flow diverges regardless
of where it is in the function call stack.

Change-Id: Id739a137b9011c900649b74165a6600a95d87ca4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/116691
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: James Price <jrprice@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/resolver/uniformity.cc b/src/tint/resolver/uniformity.cc
index a5aa37d..5fed471 100644
--- a/src/tint/resolver/uniformity.cc
+++ b/src/tint/resolver/uniformity.cc
@@ -15,6 +15,7 @@
 #include "src/tint/resolver/uniformity.h"
 
 #include <limits>
+#include <sstream>
 #include <string>
 #include <utility>
 #include <vector>
@@ -1651,9 +1652,9 @@
     /// @param function the function being analyzed
     /// @param required_to_be_uniform the node to traverse from
     /// @param may_be_non_uniform the node to traverse to
-    void ShowCauseOfNonUniformity(FunctionInfo& function,
-                                  Node* required_to_be_uniform,
-                                  Node* may_be_non_uniform) {
+    void ShowControlFlowDivergence(FunctionInfo& function,
+                                   Node* required_to_be_uniform,
+                                   Node* may_be_non_uniform) {
         // Traverse the graph to generate a path from the node to the source of non-uniformity.
         function.ResetVisited();
         Traverse(required_to_be_uniform);
@@ -1667,7 +1668,7 @@
             non_uniform_source, [](Node* node) { return node->affects_control_flow; });
         if (control_flow) {
             diagnostics_.add_note(diag::System::Resolver,
-                                  "control flow depends on non-uniform value",
+                                  "control flow depends on possibly non-uniform value",
                                   control_flow->ast->source);
             // TODO(jrprice): There are cases where the function with uniformity requirements is not
             // actually inside this control flow construct, for example:
@@ -1677,7 +1678,15 @@
             // the actual cause of divergence.
         }
 
-        auto get_var_type = [&](const sem::Variable* var) {
+        ShowSourceOfNonUniformity(non_uniform_source);
+    }
+
+    /// Add a diagnostic note to show the origin of a non-uniform value.
+    /// @param non_uniform_source the node that represents a non-uniform value
+    void ShowSourceOfNonUniformity(Node* non_uniform_source) {
+        TINT_ASSERT(Resolver, non_uniform_source);
+
+        auto var_type = [&](const sem::Variable* var) {
             switch (var->AddressSpace()) {
                 case ast::AddressSpace::kStorage:
                     return "read_write storage buffer ";
@@ -1686,17 +1695,18 @@
                 case ast::AddressSpace::kPrivate:
                     return "module-scope private variable ";
                 default:
-                    if (ast::HasAttribute<ast::BuiltinAttribute>(var->Declaration()->attributes)) {
-                        return "builtin ";
-                    } else if (ast::HasAttribute<ast::LocationAttribute>(
-                                   var->Declaration()->attributes)) {
-                        return "user-defined input ";
-                    } else {
-                        // TODO(jrprice): Provide more info for this case.
-                    }
-                    break;
+                    return "";
             }
-            return "";
+        };
+        auto param_type = [&](const sem::Parameter* param) {
+            if (ast::HasAttribute<ast::BuiltinAttribute>(param->Declaration()->attributes)) {
+                return "builtin ";
+            } else if (ast::HasAttribute<ast::LocationAttribute>(
+                           param->Declaration()->attributes)) {
+                return "user-defined input ";
+            } else {
+                return "parameter ";
+            }
         };
 
         // Show the source of the non-uniform value.
@@ -1704,19 +1714,23 @@
             non_uniform_source->ast,
             [&](const ast::IdentifierExpression* ident) {
                 auto* var = sem_.Get(ident)->UnwrapLoad()->As<sem::VariableUser>()->Variable();
-                std::string var_type = get_var_type(var);
-                diagnostics_.add_note(diag::System::Resolver,
-                                      "reading from " + var_type + "'" + NameFor(ident) +
-                                          "' may result in a non-uniform value",
-                                      ident->source);
+                std::ostringstream ss;
+                if (auto* param = var->As<sem::Parameter>()) {
+                    auto* func = param->Owner()->As<sem::Function>();
+                    ss << param_type(param) << "'" << NameFor(ident) << "' of '"
+                       << NameFor(func->Declaration()) << "' may be non-uniform";
+                } else {
+                    ss << "reading from " << var_type(var) << "'" << NameFor(ident)
+                       << "' may result in a non-uniform value";
+                }
+                diagnostics_.add_note(diag::System::Resolver, ss.str(), ident->source);
             },
             [&](const ast::Variable* v) {
                 auto* var = sem_.Get(v);
-                std::string var_type = get_var_type(var);
-                diagnostics_.add_note(diag::System::Resolver,
-                                      "reading from " + var_type + "'" + NameFor(v) +
-                                          "' may result in a non-uniform value",
-                                      v->source);
+                std::ostringstream ss;
+                ss << "reading from " << var_type(var) << "'" << NameFor(v)
+                   << "' may result in a non-uniform value";
+                diagnostics_.add_note(diag::System::Resolver, ss.str(), v->source);
             },
             [&](const ast::CallExpression* c) {
                 auto target_name = NameFor(c->target.name);
@@ -1730,11 +1744,10 @@
                     case Node::kFunctionCallArgumentContents: {
                         auto* arg = c->args[non_uniform_source->arg_index];
                         auto* var = sem_.Get(arg)->RootIdentifier();
-                        std::string var_type = get_var_type(var);
-                        diagnostics_.add_note(diag::System::Resolver,
-                                              "reading from " + var_type + "'" +
-                                                  NameFor(var->Declaration()) +
-                                                  "' may result in a non-uniform value",
+                        std::ostringstream ss;
+                        ss << "reading from " << var_type(var) << "'" << NameFor(var->Declaration())
+                           << "' may result in a non-uniform value";
+                        diagnostics_.add_note(diag::System::Resolver, ss.str(),
                                               var->Declaration()->source);
                         break;
                     }
@@ -1750,7 +1763,7 @@
                     case Node::kFunctionCallPointerArgumentResult: {
                         diagnostics_.add_note(
                             diag::System::Resolver,
-                            "pointer contents may become non-uniform after calling '" +
+                            "contents of pointer may become non-uniform after calling '" +
                                 target_name + "'",
                             c->args[non_uniform_source->arg_index]->source);
                         break;
@@ -1773,11 +1786,9 @@
     /// Generate an error message for a uniformity issue.
     /// @param function the function that the diagnostic is being produced for
     /// @param source_node the node that has caused a uniformity issue in `function`
-    /// @param note `true` if the diagnostic should be emitted as a note
-    void MakeError(FunctionInfo& function, Node* source_node, bool note = false) {
-        // Helper to produce a diagnostic message with the severity required by this invocation of
-        // the `MakeError` function.
-        auto report = [&](Source source, std::string msg) {
+    void MakeError(FunctionInfo& function, Node* source_node) {
+        // Helper to produce a diagnostic message, as a note or with the global failure severity.
+        auto report = [&](Source source, std::string msg, bool note) {
             diag::Diagnostic error{};
             auto failureSeverity =
                 kUniformityFailuresAsError ? diag::Severity::Error : diag::Severity::Warning;
@@ -1802,77 +1813,54 @@
         auto* call = cause->ast->As<ast::CallExpression>();
         TINT_ASSERT(Resolver, call);
         auto* target = SemCall(call)->Target();
+        auto func_name = NameFor(call->target.name);
 
-        std::string func_name;
-        if (auto* builtin = target->As<sem::Builtin>()) {
-            func_name = builtin->str();
-        } else if (auto* user = target->As<sem::Function>()) {
-            func_name = NameFor(user->Declaration());
-        }
+        if (cause->type == Node::kFunctionCallArgumentValue ||
+            cause->type == Node::kFunctionCallArgumentContents) {
+            bool is_value = (cause->type == Node::kFunctionCallArgumentValue);
 
-        if (cause->type == Node::kFunctionCallArgumentValue) {
-            // The requirement was on a function parameter.
-            auto* ast_param = target->Parameters()[cause->arg_index]->Declaration();
-            std::string param_name;
-            if (ast_param) {
-                param_name = " '" + NameFor(ast_param) + "'";
+            auto* user_func = target->As<sem::Function>();
+            if (user_func) {
+                // Recurse into the called function to show the reason for the requirement.
+                auto next_function = functions_.Find(user_func->Declaration());
+                auto& param_info = next_function->parameters[cause->arg_index];
+                MakeError(*next_function,
+                          is_value ? param_info.value : param_info.ptr_input_contents);
             }
-            report(call->args[cause->arg_index]->source,
-                   "parameter" + param_name + " of '" + func_name + "' must be uniform");
 
-            // If this is a call to a user-defined function, add a note to show the reason that the
-            // parameter is required to be uniform.
-            if (auto* user = target->As<sem::Function>()) {
-                auto next_function = functions_.Find(user->Declaration());
-                Node* next_cause = next_function->parameters[cause->arg_index].value;
-                MakeError(*next_function, next_cause, true);
-            }
-        } else if (cause->type == Node::kFunctionCallArgumentContents) {
-            // The requirement was on the contents of a function parameter.
-            auto param_name = NameFor(target->Parameters()[cause->arg_index]->Declaration());
-            report(call->args[cause->arg_index]->source, "contents of parameter '" + param_name +
-                                                             "' of '" + func_name +
-                                                             "' must be uniform");
+            // Show the place where the non-uniform argument was passed.
+            // If this is a builtin, this will be the trigger location for the failure.
+            std::ostringstream ss;
+            ss << "possibly non-uniform value passed" << (is_value ? "" : " via pointer")
+               << " here";
+            report(call->args[cause->arg_index]->source, ss.str(), /* note */ user_func != nullptr);
 
-            // If this is a call to a user-defined function, add a note to show the reason that the
-            // parameter is required to be uniform.
-            if (auto* user = target->As<sem::Function>()) {
-                auto next_function = functions_.Find(user->Declaration());
-                Node* next_cause = next_function->parameters[cause->arg_index].ptr_input_contents;
-                MakeError(*next_function, next_cause, true);
-            }
+            // Show the origin of non-uniformity for the value or data that is being passed.
+            ShowSourceOfNonUniformity(source_node->visited_from);
         } else {
-            // The requirement was on a function callsite.
-            report(call->source,
-                   "'" + func_name + "' must only be called from uniform control flow");
-
-            // If this is a call to a user-defined function, add a note to show the builtin that
-            // causes the uniformity requirement.
-            auto* innermost_call = FindBuiltinThatRequiresUniformity(call);
-            if (innermost_call != call) {
-                auto* sem_call = SemCall(call);
-                auto* sem_innermost_call = SemCall(innermost_call);
-
-                // Determine whether the builtin is being called directly or indirectly.
-                bool indirect = false;
-                if (sem_call->Target()->As<sem::Function>() !=
-                    sem_innermost_call->Stmt()->Function()) {
-                    indirect = true;
-                }
-
-                auto* builtin = sem_innermost_call->Target()->As<sem::Builtin>();
-                diagnostics_.add_note(diag::System::Resolver,
-                                      "'" + func_name + "' requires uniformity because it " +
-                                          (indirect ? "indirectly " : "") + "calls " +
-                                          builtin->str(),
-                                      innermost_call->source);
+            auto* builtin_call = FindBuiltinThatRequiresUniformity(call);
+            {
+                // Show a builtin was reachable from this call (which may be the call itself).
+                // This will be the trigger location for the failure.
+                std::ostringstream ss;
+                ss << "'" << NameFor(builtin_call->target.name)
+                   << "' must only be called from uniform control flow";
+                report(builtin_call->source, ss.str(), /* note */ false);
             }
-        }
 
-        // Show the cause of non-uniformity (starting at the top-level error).
-        if (!note) {
-            ShowCauseOfNonUniformity(function, function.required_to_be_uniform,
-                                     function.may_be_non_uniform);
+            if (builtin_call != call) {
+                // The call was to a user function, so show that call too.
+                std::ostringstream ss;
+                ss << "called ";
+                if (target->As<sem::Function>() != SemCall(builtin_call)->Stmt()->Function()) {
+                    ss << "indirectly ";
+                }
+                ss << "by '" << func_name << "' from '" << function.name << "'";
+                report(call->source, ss.str(), /* note */ true);
+            }
+
+            // Show the point at which control-flow depends on a non-uniform value.
+            ShowControlFlowDivergence(function, cause, source_node);
         }
     }
 
diff --git a/src/tint/resolver/uniformity_test.cc b/src/tint/resolver/uniformity_test.cc
index 51e607a..5052a1f 100644
--- a/src/tint/resolver/uniformity_test.cc
+++ b/src/tint/resolver/uniformity_test.cc
@@ -326,7 +326,6 @@
     bool should_pass = !(MayBeNonUniform(condition) && RequiredToBeUniform(function));
     RunTest(src, should_pass);
     if (!should_pass) {
-        EXPECT_THAT(error_, ::testing::StartsWith("test:31:5 warning: "));
         EXPECT_THAT(error_, ::testing::HasSubstr("must only be called from uniform control flow"));
     }
 }
@@ -408,14 +407,22 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:11:7 warning: parameter 'i' of 'foo' must be uniform
-  foo(rw);
-      ^^
-
-test:6:5 note: 'workgroupBarrier' must only be called from uniform control flow
+              R"(test:6:5 warning: 'workgroupBarrier' must only be called from uniform control flow
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
+test:5:3 note: control flow depends on possibly non-uniform value
+  if (i == 0) {
+  ^^
+
+test:5:7 note: parameter 'i' of 'foo' may be non-uniform
+  if (i == 0) {
+      ^
+
+test:11:7 note: possibly non-uniform value passed here
+  foo(rw);
+      ^^
+
 test:11:7 note: reading from read_write storage buffer 'rw' may result in a non-uniform value
   foo(rw);
       ^^
@@ -465,7 +472,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (foo(rw) == 7) {
   ^^
 
@@ -508,11 +515,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:4:3 note: control flow depends on non-uniform value
+test:4:3 note: control flow depends on possibly non-uniform value
   if (all(vec3(b) == vec3(0u))) {
   ^^
 
-test:4:16 note: reading from builtin 'b' may result in a non-uniform value
+test:4:16 note: builtin 'b' of 'main' may be non-uniform
   if (all(vec3(b) == vec3(0u))) {
                ^
 )");
@@ -543,11 +550,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (all(vec3(s.b) == vec3(0u))) {
   ^^
 
-test:8:16 note: reading from 's' may result in a non-uniform value
+test:8:16 note: parameter 's' of 'main' may be non-uniform
   if (all(vec3(s.b) == vec3(0u))) {
                ^
 )");
@@ -588,11 +595,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (s.num_groups.x == 0u) {
   ^^
 
-test:9:7 note: reading from 's' may result in a non-uniform value
+test:9:7 note: parameter 's' of 'main' may be non-uniform
   if (s.num_groups.x == 0u) {
       ^
 )");
@@ -619,11 +626,11 @@
     dpdx(0.5);
     ^^^^
 
-test:4:3 note: control flow depends on non-uniform value
+test:4:3 note: control flow depends on possibly non-uniform value
   if (u32(vec4(b).x) == 0u) {
   ^^
 
-test:4:16 note: reading from builtin 'b' may result in a non-uniform value
+test:4:16 note: builtin 'b' of 'main' may be non-uniform
   if (u32(vec4(b).x) == 0u) {
                ^
 )");
@@ -653,11 +660,11 @@
     dpdx(0.5);
     ^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (u32(vec4(s.b).x) == 0u) {
   ^^
 
-test:8:16 note: reading from 's' may result in a non-uniform value
+test:8:16 note: parameter 's' of 'main' may be non-uniform
   if (u32(vec4(s.b).x) == 0u) {
                ^
 )");
@@ -690,11 +697,11 @@
     dpdx(0.5);
     ^^^^
 
-test:4:3 note: control flow depends on non-uniform value
+test:4:3 note: control flow depends on possibly non-uniform value
   if (l == 0.0) {
   ^^
 
-test:4:7 note: reading from user-defined input 'l' may result in a non-uniform value
+test:4:7 note: user-defined input 'l' of 'main' may be non-uniform
   if (l == 0.0) {
       ^
 )");
@@ -720,11 +727,11 @@
     dpdx(0.5);
     ^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (s.l == 0.0) {
   ^^
 
-test:8:7 note: reading from 's' may result in a non-uniform value
+test:8:7 note: parameter 's' of 'main' may be non-uniform
   if (s.l == 0.0) {
       ^
 )");
@@ -961,7 +968,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:10:7 note: control flow depends on non-uniform value
+test:10:7 note: control flow depends on possibly non-uniform value
       break if (i == n);
       ^^^^^
 
@@ -1012,7 +1019,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:10:7 note: control flow depends on non-uniform value
+test:10:7 note: control flow depends on possibly non-uniform value
       break if (i == n);
       ^^^^^
 
@@ -1080,7 +1087,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:7:5 note: control flow depends on non-uniform value
+test:7:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -1164,7 +1171,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:13:5 note: control flow depends on non-uniform value
+test:13:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -1202,7 +1209,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:14:3 note: control flow depends on non-uniform value
+test:14:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -1245,7 +1252,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:19:3 note: control flow depends on non-uniform value
+test:19:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -1319,7 +1326,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:19:3 note: control flow depends on non-uniform value
+test:19:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -1360,7 +1367,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:7:5 note: control flow depends on non-uniform value
+test:7:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -1404,7 +1411,7 @@
         workgroupBarrier();
         ^^^^^^^^^^^^^^^^
 
-test:15:7 note: control flow depends on non-uniform value
+test:15:7 note: control flow depends on possibly non-uniform value
       if (v == 0) {
       ^^
 
@@ -1445,7 +1452,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:7:5 note: control flow depends on non-uniform value
+test:7:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -1486,7 +1493,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:7:5 note: control flow depends on non-uniform value
+test:7:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -1604,7 +1611,7 @@
         workgroupBarrier();
         ^^^^^^^^^^^^^^^^
 
-test:15:7 note: control flow depends on non-uniform value
+test:15:7 note: control flow depends on possibly non-uniform value
       if (v == 0) {
       ^^
 
@@ -1666,7 +1673,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   for (var i = 0; i < n; i = i + 1) {
   ^^^
 
@@ -1699,7 +1706,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:7:5 note: control flow depends on non-uniform value
+test:7:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -1754,7 +1761,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -1809,7 +1816,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:7:5 note: control flow depends on non-uniform value
+test:7:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -1870,7 +1877,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:14:3 note: control flow depends on non-uniform value
+test:14:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -1915,7 +1922,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:20:3 note: control flow depends on non-uniform value
+test:20:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -1957,7 +1964,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:7:5 note: control flow depends on non-uniform value
+test:7:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -1998,7 +2005,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:7:5 note: control flow depends on non-uniform value
+test:7:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -2035,7 +2042,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   for (var i = 0; i < 10; i++) {
   ^^^
 
@@ -2131,7 +2138,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:6:3 note: control flow depends on non-uniform value
+test:6:3 note: control flow depends on possibly non-uniform value
   while (i < n) {
   ^^^^^
 
@@ -2168,7 +2175,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:8:5 note: control flow depends on non-uniform value
+test:8:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -2233,7 +2240,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:16:3 note: control flow depends on non-uniform value
+test:16:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -2280,7 +2287,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:22:3 note: control flow depends on non-uniform value
+test:22:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -2323,7 +2330,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:8:5 note: control flow depends on non-uniform value
+test:8:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -2366,7 +2373,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:8:5 note: control flow depends on non-uniform value
+test:8:5 note: control flow depends on possibly non-uniform value
     if (v == 0) {
     ^^
 
@@ -2461,7 +2468,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
   ^^
 
@@ -2489,7 +2496,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
   ^^
 
@@ -2518,7 +2525,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:34 note: control flow depends on non-uniform value
+test:7:34 note: control flow depends on possibly non-uniform value
   if ((non_uniform_global == 42) && false) {
                                  ^^
 
@@ -2547,7 +2554,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (false && (non_uniform_global == 42)) {
   ^^
 
@@ -2576,7 +2583,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:34 note: control flow depends on non-uniform value
+test:7:34 note: control flow depends on possibly non-uniform value
   if ((non_uniform_global == 42) || true) {
                                  ^^
 
@@ -2605,7 +2612,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (true || (non_uniform_global == 42)) {
   ^^
 
@@ -2633,7 +2640,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
   ^^
 
@@ -2664,7 +2671,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -2741,7 +2748,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:14:3 note: control flow depends on non-uniform value
+test:14:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -2824,7 +2831,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:11:3 note: control flow depends on non-uniform value
+test:11:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -2861,7 +2868,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:12:3 note: control flow depends on non-uniform value
+test:12:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -3018,7 +3025,7 @@
   workgroupBarrier();
   ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
   ^^
 
@@ -3055,7 +3062,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   switch (non_uniform) {
   ^^^^^^
 
@@ -3085,7 +3092,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   switch (non_uniform) {
   ^^^^^^
 
@@ -3120,7 +3127,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:8:7 note: control flow depends on non-uniform value
+test:8:7 note: control flow depends on possibly non-uniform value
       if (non_uniform == 42) {
       ^^
 
@@ -3209,7 +3216,7 @@
         workgroupBarrier();
         ^^^^^^^^^^^^^^^^
 
-test:13:7 note: control flow depends on non-uniform value
+test:13:7 note: control flow depends on possibly non-uniform value
       if (x == 0) {
       ^^
 
@@ -3249,7 +3256,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:18:3 note: control flow depends on non-uniform value
+test:18:3 note: control flow depends on possibly non-uniform value
   if (x == 0) {
   ^^
 
@@ -3315,7 +3322,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:17:3 note: control flow depends on non-uniform value
+test:17:3 note: control flow depends on possibly non-uniform value
   if (x == 0) {
   ^^
 
@@ -3384,7 +3391,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:20:3 note: control flow depends on non-uniform value
+test:20:3 note: control flow depends on possibly non-uniform value
   if (x == 0) {
   ^^
 
@@ -3426,7 +3433,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:8:5 note: control flow depends on non-uniform value
+test:8:5 note: control flow depends on possibly non-uniform value
     if (x == 0) {
     ^^
 
@@ -3531,7 +3538,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -3561,7 +3568,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -3626,7 +3633,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 0) {
   ^^
 
@@ -3654,7 +3661,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:6:3 note: control flow depends on non-uniform value
+test:6:3 note: control flow depends on possibly non-uniform value
   if (*&v == 0) {
   ^^
 
@@ -3683,7 +3690,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (*pv == 0) {
   ^^
 
@@ -3711,14 +3718,22 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:12:7 warning: contents of parameter 'p' of 'bar' must be uniform
-  bar(&v);
-      ^
-
-test:6:5 note: 'workgroupBarrier' must only be called from uniform control flow
+              R"(test:6:5 warning: 'workgroupBarrier' must only be called from uniform control flow
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
+test:5:3 note: control flow depends on possibly non-uniform value
+  if (*p == 0) {
+  ^^
+
+test:5:8 note: parameter 'p' of 'bar' may be non-uniform
+  if (*p == 0) {
+       ^
+
+test:12:7 note: possibly non-uniform value passed via pointer here
+  bar(&v);
+      ^
+
 test:11:11 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
   var v = non_uniform;
           ^^^^^^^^^^^
@@ -3743,7 +3758,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:6:3 note: control flow depends on non-uniform value
+test:6:3 note: control flow depends on possibly non-uniform value
   if (*pv == 0) {
   ^^
 
@@ -3772,14 +3787,22 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:13:7 warning: contents of parameter 'p' of 'bar' must be uniform
-  bar(&non_uniform);
-      ^
-
-test:8:5 note: 'workgroupBarrier' must only be called from uniform control flow
+              R"(test:8:5 warning: 'workgroupBarrier' must only be called from uniform control flow
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
+test:7:3 note: control flow depends on possibly non-uniform value
+  if (*p == 0) {
+  ^^
+
+test:7:8 note: parameter 'p' of 'bar' may be non-uniform
+  if (*p == 0) {
+       ^
+
+test:13:7 note: possibly non-uniform value passed via pointer here
+  bar(&non_uniform);
+      ^
+
 test:4:48 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
 @group(0) @binding(0) var<storage, read_write> non_uniform : i32;
                                                ^^^^^^^^^^^
@@ -3809,7 +3832,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:11:3 note: control flow depends on non-uniform value
+test:11:3 note: control flow depends on possibly non-uniform value
   if (0 == bar(&non_uniform)) {
   ^^
 
@@ -3838,14 +3861,22 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:13:7 warning: contents of parameter 'p' of 'bar' must be uniform
-  bar(&v);
-      ^
-
-test:6:5 note: 'workgroupBarrier' must only be called from uniform control flow
+              R"(test:6:5 warning: 'workgroupBarrier' must only be called from uniform control flow
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
+test:5:3 note: control flow depends on possibly non-uniform value
+  if (*p == 0) {
+  ^^
+
+test:5:8 note: parameter 'p' of 'bar' may be non-uniform
+  if (*p == 0) {
+       ^
+
+test:13:7 note: possibly non-uniform value passed via pointer here
+  bar(&v);
+      ^
+
 test:12:11 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
   var v = non_uniform;
           ^^^^^^^^^^^
@@ -3871,14 +3902,22 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:12:7 warning: contents of parameter 'p' of 'bar' must be uniform
-  bar(&v);
-      ^
-
-test:6:5 note: 'workgroupBarrier' must only be called from uniform control flow
+              R"(test:6:5 warning: 'workgroupBarrier' must only be called from uniform control flow
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
+test:5:3 note: control flow depends on possibly non-uniform value
+  if (*p == 0) {
+  ^^
+
+test:5:8 note: parameter 'p' of 'bar' may be non-uniform
+  if (*p == 0) {
+       ^
+
+test:12:7 note: possibly non-uniform value passed via pointer here
+  bar(&v);
+      ^
+
 test:11:11 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
   var v = non_uniform;
           ^^^^^^^^^^^
@@ -3950,7 +3989,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (*p == 0) {
   ^^
 
@@ -3988,7 +4027,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (*local_p == 0) {
   ^^
 
@@ -4025,17 +4064,29 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:21:7 warning: contents of parameter 'p' of 'bar' must be uniform
-  bar(p);
-      ^
+              R"(test:8:5 warning: 'workgroupBarrier' must only be called from uniform control flow
+    workgroupBarrier();
+    ^^^^^^^^^^^^^^^^
 
-test:13:7 note: contents of parameter 'p' of 'zoo' must be uniform
+test:7:3 note: control flow depends on possibly non-uniform value
+  if (*p == 0) {
+  ^^
+
+test:7:8 note: parameter 'p' of 'zoo' may be non-uniform
+  if (*p == 0) {
+       ^
+
+test:13:7 note: possibly non-uniform value passed via pointer here
   zoo(p);
       ^
 
-test:8:5 note: 'workgroupBarrier' must only be called from uniform control flow
-    workgroupBarrier();
-    ^^^^^^^^^^^^^^^^
+test:12:8 note: reading from 'p' may result in a non-uniform value
+fn bar(p : ptr<function, i32>) {
+       ^
+
+test:21:7 note: possibly non-uniform value passed via pointer here
+  bar(p);
+      ^
 
 test:20:14 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
   let p = &v[non_uniform];
@@ -4065,7 +4116,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:10:3 note: control flow depends on non-uniform value
+test:10:3 note: control flow depends on possibly non-uniform value
   if (*p == 0) {
   ^^
 
@@ -4103,17 +4154,29 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:22:7 warning: contents of parameter 'p' of 'bar' must be uniform
-  bar(p);
-      ^
+              R"(test:9:5 warning: 'workgroupBarrier' must only be called from uniform control flow
+    workgroupBarrier();
+    ^^^^^^^^^^^^^^^^
 
-test:14:7 note: contents of parameter 'p' of 'zoo' must be uniform
+test:8:3 note: control flow depends on possibly non-uniform value
+  if (*p == 0) {
+  ^^
+
+test:8:8 note: parameter 'p' of 'zoo' may be non-uniform
+  if (*p == 0) {
+       ^
+
+test:14:7 note: possibly non-uniform value passed via pointer here
   zoo(p);
       ^
 
-test:9:5 note: 'workgroupBarrier' must only be called from uniform control flow
-    workgroupBarrier();
-    ^^^^^^^^^^^^^^^^
+test:13:8 note: reading from 'p' may result in a non-uniform value
+fn bar(p : ptr<function, i32>) {
+       ^
+
+test:22:7 note: possibly non-uniform value passed via pointer here
+  bar(p);
+      ^
 
 test:19:34 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
   var v = array<i32, 4>(0, 0, 0, non_uniform);
@@ -4141,7 +4204,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (*pv == 0) {
   ^^
 
@@ -4189,7 +4252,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -4219,7 +4282,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (*&*&*pv2 == 0) {
   ^^
 
@@ -4251,7 +4314,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:10:3 note: control flow depends on non-uniform value
+test:10:3 note: control flow depends on possibly non-uniform value
   if (*pv1 == 0) {
   ^^
 
@@ -4302,7 +4365,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:10:3 note: control flow depends on non-uniform value
+test:10:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -4352,11 +4415,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:11:3 note: control flow depends on non-uniform value
+test:11:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
-test:10:7 note: pointer contents may become non-uniform after calling 'bar'
+test:10:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
       ^
 )");
@@ -4405,7 +4468,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:11:3 note: control flow depends on non-uniform value
+test:11:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -4439,7 +4502,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:12:3 note: control flow depends on non-uniform value
+test:12:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -4522,7 +4585,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:20:3 note: control flow depends on non-uniform value
+test:20:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -4616,11 +4679,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:17:3 note: control flow depends on non-uniform value
+test:17:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
-test:16:7 note: pointer contents may become non-uniform after calling 'bar'
+test:16:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
       ^
 )");
@@ -4653,11 +4716,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:15:3 note: control flow depends on non-uniform value
+test:15:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
-test:14:7 note: pointer contents may become non-uniform after calling 'bar'
+test:14:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
       ^
 )");
@@ -4690,11 +4753,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:15:3 note: control flow depends on non-uniform value
+test:15:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
-test:14:7 note: pointer contents may become non-uniform after calling 'bar'
+test:14:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
       ^
 )");
@@ -4735,11 +4798,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:23:3 note: control flow depends on non-uniform value
+test:23:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
-test:22:7 note: pointer contents may become non-uniform after calling 'bar'
+test:22:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
       ^
 )");
@@ -4774,11 +4837,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:17:3 note: control flow depends on non-uniform value
+test:17:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
-test:16:7 note: pointer contents may become non-uniform after calling 'bar'
+test:16:7 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&v);
       ^
 )");
@@ -4810,7 +4873,7 @@
       workgroupBarrier();
       ^^^^^^^^^^^^^^^^
 
-test:6:5 note: control flow depends on non-uniform value
+test:6:5 note: control flow depends on possibly non-uniform value
     if (*p == 0) {
     ^^
 
@@ -4846,7 +4909,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:14:3 note: control flow depends on non-uniform value
+test:14:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -4883,7 +4946,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:11:3 note: control flow depends on non-uniform value
+test:11:3 note: control flow depends on possibly non-uniform value
   if (non_uniform_global == 0) {
   ^^
 
@@ -4920,7 +4983,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:11:3 note: control flow depends on non-uniform value
+test:11:3 note: control flow depends on possibly non-uniform value
   if (non_uniform_global == 0) {
   ^^
 
@@ -4961,7 +5024,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:15:3 note: control flow depends on non-uniform value
+test:15:3 note: control flow depends on possibly non-uniform value
   if (non_uniform_global == 0) {
   ^^
 
@@ -5020,7 +5083,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:13:3 note: control flow depends on non-uniform value
+test:13:3 note: control flow depends on possibly non-uniform value
   if (b == 0) {
   ^^
 
@@ -5077,11 +5140,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:13:3 note: control flow depends on non-uniform value
+test:13:3 note: control flow depends on possibly non-uniform value
   if (b == 0) {
   ^^
 
-test:12:11 note: pointer contents may become non-uniform after calling 'bar'
+test:12:11 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&a, &b);
           ^
 )");
@@ -5132,7 +5195,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:11:3 note: control flow depends on non-uniform value
+test:11:3 note: control flow depends on possibly non-uniform value
   if (v == 1) {
   ^^
 
@@ -5170,11 +5233,11 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:13:3 note: control flow depends on non-uniform value
+test:13:3 note: control flow depends on possibly non-uniform value
   if (b == 0) {
   ^^
 
-test:12:11 note: pointer contents may become non-uniform after calling 'bar'
+test:12:11 note: contents of pointer may become non-uniform after calling 'bar'
   bar(&a, &b);
           ^
 )");
@@ -5210,7 +5273,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:15:3 note: control flow depends on non-uniform value
+test:15:3 note: control flow depends on possibly non-uniform value
   if (c == 0) {
   ^^
 
@@ -5277,7 +5340,7 @@
     RunTest(std::move(b), false);
     EXPECT_EQ(error_,
               R"(warning: 'workgroupBarrier' must only be called from uniform control flow
-note: control flow depends on non-uniform value
+note: control flow depends on possibly non-uniform value
 note: reading from module-scope private variable 'non_uniform_global' may result in a non-uniform value)");
 }
 
@@ -5316,7 +5379,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (v[2] == 0) {
   ^^
 
@@ -5345,7 +5408,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (v[2] == 0) {
   ^^
 
@@ -5390,7 +5453,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (v[2] == 0) {
   ^^
 
@@ -5423,7 +5486,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (v[1] == 0) {
   ^^
 
@@ -5541,7 +5604,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (v[1] == 0) {
   ^^
 
@@ -5571,7 +5634,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (v.y == 0) {
   ^^
 
@@ -5604,7 +5667,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (v[1] == 0) {
   ^^
 
@@ -5633,7 +5696,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (any(v == vec4(42))) {
   ^^
 
@@ -5666,7 +5729,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -5770,7 +5833,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -5803,7 +5866,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -5836,7 +5899,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -5870,7 +5933,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -5905,7 +5968,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -5939,7 +6002,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -5969,7 +6032,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -6000,7 +6063,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -6032,7 +6095,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -6064,7 +6127,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -6094,7 +6157,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (m[1][1] == 0.0) {
   ^^
 
@@ -6143,7 +6206,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (s.b == 0) {
   ^^
 
@@ -6176,7 +6239,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:11:3 note: control flow depends on non-uniform value
+test:11:3 note: control flow depends on possibly non-uniform value
   if (s.b == 0) {
   ^^
 
@@ -6229,7 +6292,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:11:3 note: control flow depends on non-uniform value
+test:11:3 note: control flow depends on possibly non-uniform value
   if (s.b == 0) {
   ^^
 
@@ -6266,7 +6329,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:12:3 note: control flow depends on non-uniform value
+test:12:3 note: control flow depends on possibly non-uniform value
   if (s.a == 0) {
   ^^
 
@@ -6304,7 +6367,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:13:3 note: control flow depends on non-uniform value
+test:13:3 note: control flow depends on possibly non-uniform value
   if (s.a == 0) {
   ^^
 
@@ -6342,7 +6405,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:13:3 note: control flow depends on non-uniform value
+test:13:3 note: control flow depends on possibly non-uniform value
   if (s.a == 0) {
   ^^
 
@@ -6397,7 +6460,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:12:3 note: control flow depends on non-uniform value
+test:12:3 note: control flow depends on possibly non-uniform value
   if (s.a == 0) {
   ^^
 
@@ -6498,7 +6561,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:12:3 note: control flow depends on non-uniform value
+test:12:3 note: control flow depends on possibly non-uniform value
   if (s.a == 0) {
   ^^
 
@@ -6534,7 +6597,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:13:3 note: control flow depends on non-uniform value
+test:13:3 note: control flow depends on possibly non-uniform value
   if (s.a == 0) {
   ^^
 
@@ -6570,7 +6633,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:13:3 note: control flow depends on non-uniform value
+test:13:3 note: control flow depends on possibly non-uniform value
   if (s.a == 0) {
   ^^
 
@@ -6607,7 +6670,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:12:3 note: control flow depends on non-uniform value
+test:12:3 note: control flow depends on possibly non-uniform value
   if (s.a == 0) {
   ^^
 
@@ -6648,7 +6711,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (arr[7] == 0) {
   ^^
 
@@ -6677,7 +6740,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (arr[2] == 0) {
   ^^
 
@@ -6722,7 +6785,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (arr[2] == 0) {
   ^^
 
@@ -6753,7 +6816,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (arr[2] == 0) {
   ^^
 
@@ -6786,7 +6849,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (arr[1] == 0) {
   ^^
 
@@ -6833,7 +6896,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (arr[1] == 0) {
   ^^
 
@@ -6866,7 +6929,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (arr[1] == 0) {
   ^^
 
@@ -6899,7 +6962,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (arr[1] == 0) {
   ^^
 
@@ -6932,7 +6995,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:8:3 note: control flow depends on non-uniform value
+test:8:3 note: control flow depends on possibly non-uniform value
   if (arr[1] == 0) {
   ^^
 
@@ -6966,7 +7029,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (arr[1] == 0) {
   ^^
 
@@ -7001,7 +7064,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (arr[1] == 0) {
   ^^
 
@@ -7035,7 +7098,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:9:3 note: control flow depends on possibly non-uniform value
   if (arr[1] == 0) {
   ^^
 
@@ -7181,7 +7244,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (i32(non_uniform_global) == 0) {
   ^^
 
@@ -7208,7 +7271,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (f32(non_uniform_global) == 0.0) {
   ^^
 
@@ -7235,7 +7298,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (bitcast<f32>(non_uniform_global) == 0.0) {
   ^^
 
@@ -7265,7 +7328,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -7295,7 +7358,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:7:3 note: control flow depends on non-uniform value
+test:7:3 note: control flow depends on possibly non-uniform value
   if (v == 0) {
   ^^
 
@@ -7332,7 +7395,7 @@
   let b = (non_uniform_global == 0) && (dpdx(1.0) == 0.0);
                                         ^^^^
 
-test:5:37 note: control flow depends on non-uniform value
+test:5:37 note: control flow depends on possibly non-uniform value
   let b = (non_uniform_global == 0) && (dpdx(1.0) == 0.0);
                                     ^^
 
@@ -7585,7 +7648,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:19:3 note: control flow depends on non-uniform value
+test:19:3 note: control flow depends on possibly non-uniform value
   if (0 == bar(p)) {
   ^^
 
@@ -7650,11 +7713,12 @@
 )";
 
     RunTest(src, false);
-    EXPECT_EQ(error_, R"(test:8:28 warning: parameter of 'workgroupUniformLoad' must be uniform
+    EXPECT_EQ(error_,
+              R"(test:8:28 warning: possibly non-uniform value passed here
   if (workgroupUniformLoad(&data[idx]) > 0) {
                            ^
 
-test:8:34 note: reading from builtin 'idx' may result in a non-uniform value
+test:8:34 note: builtin 'idx' of 'main' may be non-uniform
   if (workgroupUniformLoad(&data[idx]) > 0) {
                                  ^^^
 )");
@@ -7681,15 +7745,20 @@
 )";
 
     RunTest(src, false);
-    EXPECT_EQ(error_, R"(test:14:11 warning: parameter 'p' of 'foo' must be uniform
-  if (foo(&data[idx]) > 0) {
-          ^
-
-test:8:31 note: parameter of 'workgroupUniformLoad' must be uniform
+    EXPECT_EQ(error_,
+              R"(test:8:31 warning: possibly non-uniform value passed here
   return workgroupUniformLoad(p);
                               ^
 
-test:14:17 note: reading from builtin 'idx' may result in a non-uniform value
+test:8:31 note: parameter 'p' of 'foo' may be non-uniform
+  return workgroupUniformLoad(p);
+                              ^
+
+test:14:11 note: possibly non-uniform value passed here
+  if (foo(&data[idx]) > 0) {
+          ^
+
+test:14:17 note: builtin 'idx' of 'main' may be non-uniform
   if (foo(&data[idx]) > 0) {
                 ^^^
 )");
@@ -7712,7 +7781,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (atomicAdd(&a, 1) == 1) {
   ^^
 
@@ -7739,7 +7808,7 @@
     storageBarrier();
     ^^^^^^^^^^^^^^
 
-test:5:3 note: control flow depends on non-uniform value
+test:5:3 note: control flow depends on possibly non-uniform value
   if (atomicAdd(&a, 1) == 1) {
   ^^
 
@@ -7795,7 +7864,7 @@
     RunTest(std::move(b), false);
     EXPECT_EQ(error_,
               R"(warning: 'workgroupBarrier' must only be called from uniform control flow
-note: control flow depends on non-uniform value
+note: control flow depends on possibly non-uniform value
 note: reading from module-scope private variable 'v0' may result in a non-uniform value)");
 }
 
@@ -7820,15 +7889,15 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:10:5 warning: 'foo' must only be called from uniform control flow
-    foo();
-    ^^^
-
-test:5:3 note: 'foo' requires uniformity because it calls workgroupBarrier
+              R"(test:5:3 warning: 'workgroupBarrier' must only be called from uniform control flow
   workgroupBarrier();
   ^^^^^^^^^^^^^^^^
 
-test:9:3 note: control flow depends on non-uniform value
+test:10:5 note: called by 'foo' from 'main'
+    foo();
+    ^^^
+
+test:9:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
   ^^
 
@@ -7863,15 +7932,15 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:18:5 warning: 'foo' must only be called from uniform control flow
-    foo();
-    ^^^
-
-test:5:3 note: 'foo' requires uniformity because it indirectly calls workgroupBarrier
+              R"(test:5:3 warning: 'workgroupBarrier' must only be called from uniform control flow
   workgroupBarrier();
   ^^^^^^^^^^^^^^^^
 
-test:17:3 note: control flow depends on non-uniform value
+test:18:5 note: called indirectly by 'foo' from 'main'
+    foo();
+    ^^^
+
+test:17:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
   ^^
 
@@ -7906,21 +7975,37 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:19:7 warning: parameter 'c' of 'foo' must be uniform
-  foo(non_uniform);
-      ^^^^^^^^^^^
+              R"(test:6:5 warning: 'workgroupBarrier' must only be called from uniform control flow
+    workgroupBarrier();
+    ^^^^^^^^^^^^^^^^
 
-test:15:7 note: parameter 'b' of 'bar' must be uniform
-  bar(c);
+test:5:3 note: control flow depends on possibly non-uniform value
+  if (a == 42) {
+  ^^
+
+test:5:7 note: parameter 'a' of 'zoo' may be non-uniform
+  if (a == 42) {
       ^
 
-test:11:7 note: parameter 'a' of 'zoo' must be uniform
+test:11:7 note: possibly non-uniform value passed here
   zoo(b);
       ^
 
-test:6:5 note: 'workgroupBarrier' must only be called from uniform control flow
-    workgroupBarrier();
-    ^^^^^^^^^^^^^^^^
+test:11:7 note: parameter 'b' of 'bar' may be non-uniform
+  zoo(b);
+      ^
+
+test:15:7 note: possibly non-uniform value passed here
+  bar(c);
+      ^
+
+test:15:7 note: parameter 'c' of 'foo' may be non-uniform
+  bar(c);
+      ^
+
+test:19:7 note: possibly non-uniform value passed here
+  foo(non_uniform);
+      ^^^^^^^^^^^
 
 test:19:7 note: reading from read_write storage buffer 'non_uniform' may result in a non-uniform value
   foo(non_uniform);
@@ -7957,7 +8042,7 @@
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:17:3 note: control flow depends on non-uniform value
+test:17:3 note: control flow depends on possibly non-uniform value
   if (foo() == 42) {
   ^^
 
@@ -7988,15 +8073,15 @@
 
     RunTest(src, false);
     EXPECT_EQ(error_,
-              R"(test:12:5 warning: 'foo' must only be called from uniform control flow
-    foo(0);
-    ^^^
-
-test:6:5 note: 'foo' requires uniformity because it calls workgroupBarrier
+              R"(test:6:5 warning: 'workgroupBarrier' must only be called from uniform control flow
     workgroupBarrier();
     ^^^^^^^^^^^^^^^^
 
-test:11:3 note: control flow depends on non-uniform value
+test:12:5 note: called by 'foo' from 'main'
+    foo(0);
+    ^^^
+
+test:11:3 note: control flow depends on possibly non-uniform value
   if (non_uniform == 42) {
   ^^