diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 12f3923f8e11..2ca3d12edb77 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -9427,7 +9427,8 @@ void Sema::CheckUnsequencedOperations(Expr *E) { void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, bool IsConstexpr) { CheckImplicitConversions(E, CheckLoc); - CheckUnsequencedOperations(E); + if (!E->isInstantiationDependent()) + CheckUnsequencedOperations(E); if (!IsConstexpr && !E->isValueDependent()) CheckForIntOverflow(E); } diff --git a/clang/test/SemaCXX/warn-unsequenced.cpp b/clang/test/SemaCXX/warn-unsequenced.cpp index 54e16a5e6d50..9e8a5b46c218 100644 --- a/clang/test/SemaCXX/warn-unsequenced.cpp +++ b/clang/test/SemaCXX/warn-unsequenced.cpp @@ -113,3 +113,58 @@ void test() { (__builtin_object_size(&(++a, a), 0) ? 1 : 0) + ++a; // ok (__builtin_expect(++a, 0) ? 1 : 0) + ++a; // expected-warning {{multiple unsequenced modifications}} } + +namespace templates { + +template +struct Bar { + T get() { return 0; } +}; + +template +struct Foo { + int Run(); + Bar bar; +}; + +enum E {e1, e2}; +bool operator&&(E, E); + +void foo(int, int); + +template +int Foo::Run() { + char num = 0; + + // Before instantiation, Clang may consider the builtin operator here as + // unresolved function calls, and treat the arguments as unordered when + // the builtin operator evaluatation is well-ordered. Waiting until + // instantiation to check these expressions will prevent false positives. + if ((num = bar.get()) < 5 && num < 10) { } + if ((num = bar.get()) < 5 || num < 10) { } + if (static_cast((num = bar.get()) < 5) || static_cast(num < 10)) { } + + if (static_cast((num = bar.get()) < 5) && static_cast(num < 10)) { } + // expected-warning@-1 {{unsequenced modification and access to 'num'}} + + foo(num++, num++); + // expected-warning@-1 2{{multiple unsequenced modifications to 'num'}} + return 1; +} + +int x = Foo().Run(); +// expected-note@-1 {{in instantiation of member function 'templates::Foo::Run'}} + + +template +int Run2() { + T t = static_cast(0); + return (t = static_cast(1)) && t; + // expected-warning@-1 {{unsequenced modification and access to 't'}} +} + +int y = Run2(); +int z = Run2(); +// expected-note@-1{{in instantiation of function template specialization 'templates::Run2' requested here}} + +}