[clang] [ExprConstant] Handle shift overflow the same way as other kinds of overflow (PR #99579)

Eli Friedman via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 19 12:17:51 PDT 2024


https://github.com/efriedma-quic updated https://github.com/llvm/llvm-project/pull/99579

>From 1137011c51285b083cab6c15de670e64337d3de0 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Thu, 18 Jul 2024 14:51:13 -0700
Subject: [PATCH 1/5] [ExprConstant] Handle shift overflow the same way as
 other kinds of overflow

We have a mechanism to allow folding expressions that aren't ICEs as an
extension; use it more consistently.

This ends up causing bad effects on diagnostics in a few cases, but
that's not specific to shifts; it's a general issue with the way those
uses handle overflow diagnostics.
---
 clang/lib/AST/ExprConstant.cpp           | 24 +++++++++++++++---------
 clang/lib/AST/Interp/Interp.h            | 21 +++++++++++++--------
 clang/test/AST/Interp/shifts.cpp         | 13 +++----------
 clang/test/CXX/basic/basic.types/p10.cpp |  2 +-
 clang/test/Sema/constant-builtins-2.c    | 12 ++++--------
 clang/test/Sema/shift-count-negative.c   | 15 ++++++++-------
 clang/test/Sema/shift-count-overflow.c   | 13 +++++++------
 clang/test/Sema/shift-negative-value.c   | 18 ++++++++----------
 8 files changed, 59 insertions(+), 59 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 0aeac9d03eed3..bd69dc54a93dc 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2849,19 +2849,23 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
     if (SA != RHS) {
       Info.CCEDiag(E, diag::note_constexpr_large_shift)
         << RHS << E->getType() << LHS.getBitWidth();
+      if (!Info.noteUndefinedBehavior())
+        return false;
     } else if (LHS.isSigned() && !Info.getLangOpts().CPlusPlus20) {
       // C++11 [expr.shift]p2: A signed left shift must have a non-negative
       // operand, and must not overflow the corresponding unsigned type.
       // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
       // E1 x 2^E2 module 2^N.
-      if (LHS.isNegative())
+      if (LHS.isNegative()) {
         Info.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS;
-      else if (LHS.countl_zero() < SA)
+        if (!Info.noteUndefinedBehavior())
+          return false;
+      } else if (LHS.countl_zero() < SA) {
         Info.CCEDiag(E, diag::note_constexpr_lshift_discards);
+        if (!Info.noteUndefinedBehavior())
+          return false;
+      }
     }
-    if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
-        Info.getLangOpts().CPlusPlus11)
-      return false;
     Result = LHS << SA;
     return true;
   }
@@ -2875,6 +2879,8 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
       // During constant-folding, a negative shift is an opposite shift. Such a
       // shift is not a constant expression.
       Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
+      if (!Info.noteUndefinedBehavior())
+        return false;
       RHS = -RHS;
       goto shift_left;
     }
@@ -2882,13 +2888,13 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
     // C++11 [expr.shift]p1: Shift width must be less than the bit width of the
     // shifted type.
     unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
-    if (SA != RHS)
+    if (SA != RHS) {
       Info.CCEDiag(E, diag::note_constexpr_large_shift)
         << RHS << E->getType() << LHS.getBitWidth();
+      if (!Info.noteUndefinedBehavior())
+        return false;
+    }
 
-    if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
-        Info.getLangOpts().CPlusPlus11)
-      return false;
     Result = LHS >> SA;
     return true;
   }
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index c7d8604c7dc2a..1b17db61d7bac 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -137,7 +137,8 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
   if (RHS.isNegative()) {
     const SourceInfo &Loc = S.Current->getSource(OpPC);
     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
-    return false;
+    if (!S.noteUndefinedBehavior())
+      return false;
   }
 
   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
@@ -147,17 +148,23 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
     const APSInt Val = RHS.toAPSInt();
     QualType Ty = E->getType();
     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
-    return !(S.getEvalStatus().Diag && !S.getEvalStatus().Diag->empty() && S.getLangOpts().CPlusPlus11);
+    if (!S.noteUndefinedBehavior())
+      return false;
   }
 
   if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
     const Expr *E = S.Current->getExpr(OpPC);
     // C++11 [expr.shift]p2: A signed left shift must have a non-negative
     // operand, and must not overflow the corresponding unsigned type.
-    if (LHS.isNegative())
+    if (LHS.isNegative()) {
       S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
-    else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS))
+      if (!S.noteUndefinedBehavior())
+        return false;
+    } else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS)) {
       S.CCEDiag(E, diag::note_constexpr_lshift_discards);
+      if (!S.noteUndefinedBehavior())
+        return false;
+    }
   }
 
   // C++2a [expr.shift]p2: [P0907R4]:
@@ -2225,8 +2232,7 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
     // shift is not a constant expression.
     const SourceInfo &Loc = S.Current->getSource(OpPC);
     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
-    if (S.getLangOpts().CPlusPlus11 && S.getEvalStatus().Diag &&
-        !S.getEvalStatus().Diag->empty())
+    if (!S.noteUndefinedBehavior())
       return false;
     RHS = -RHS;
     return DoShift < LT, RT,
@@ -2242,8 +2248,7 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
       // E1 x 2^E2 module 2^N.
       const SourceInfo &Loc = S.Current->getSource(OpPC);
       S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
-      if (S.getLangOpts().CPlusPlus11 && S.getEvalStatus().Diag &&
-          !S.getEvalStatus().Diag->empty())
+      if (!S.noteUndefinedBehavior())
         return false;
     }
   }
diff --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp
index 360b87b7ee04f..2873d6ec1bbfb 100644
--- a/clang/test/AST/Interp/shifts.cpp
+++ b/clang/test/AST/Interp/shifts.cpp
@@ -200,14 +200,7 @@ namespace LongInt {
 };
 
 enum shiftof {
-    X = (1<<-29), // all-error {{expression is not an integral constant expression}} \
-                  // all-note {{negative shift count -29}}
-
-    X2 = (-1<<29), // cxx17-error {{expression is not an integral constant expression}} \
-                   // cxx17-note {{left shift of negative value -1}} \
-                   // ref-cxx17-error {{expression is not an integral constant expression}} \
-                   // ref-cxx17-note {{left shift of negative value -1}}
-
-    X3 = (1<<32) // all-error {{expression is not an integral constant expression}} \
-                 // all-note {{shift count 32 >= width of type 'int'}}
+    X = (1<<-29),
+    X2 = (-1<<29),
+    X3 = (1<<32),
 };
diff --git a/clang/test/CXX/basic/basic.types/p10.cpp b/clang/test/CXX/basic/basic.types/p10.cpp
index a543f248e5371..92d6da0035ea5 100644
--- a/clang/test/CXX/basic/basic.types/p10.cpp
+++ b/clang/test/CXX/basic/basic.types/p10.cpp
@@ -142,7 +142,7 @@ constexpr int arb(int n) { // expected-note {{declared here}}
                expected-note {{function parameter 'n' with unknown value cannot be used in a constant expression}}
 }
 constexpr long Overflow[(1 << 30) << 2]{}; // expected-warning {{requires 34 bits to represent}} \
-                                              expected-warning {{variable length array folded to constant array as an extension}} \
+                                              expected-error {{variable length array declaration not allowed at file scope}} \
                                               expected-warning {{variable length arrays in C++ are a Clang extension}} \
                                               expected-note {{signed left shift discards bits}}
 
diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c
index 00767267cd6c2..37b63cf4f6b32 100644
--- a/clang/test/Sema/constant-builtins-2.c
+++ b/clang/test/Sema/constant-builtins-2.c
@@ -265,10 +265,8 @@ char clz52[__builtin_clzg((unsigned __int128)0x1) == BITSIZE(__int128) - 1 ? 1 :
 char clz53[__builtin_clzg((unsigned __int128)0x1, 42) == BITSIZE(__int128) - 1 ? 1 : -1];
 char clz54[__builtin_clzg((unsigned __int128)0xf) == BITSIZE(__int128) - 4 ? 1 : -1];
 char clz55[__builtin_clzg((unsigned __int128)0xf, 42) == BITSIZE(__int128) - 4 ? 1 : -1];
-char clz56[__builtin_clzg((unsigned __int128)(1 << (BITSIZE(__int128) - 1))) == 0 ? 1 : -1]; // expected-warning {{variable length array folded to constant array as an extension}}
-                                                                                             // expected-note at -1 {{shift count 127 >= width of type 'int' (32 bits)}}
-char clz57[__builtin_clzg((unsigned __int128)(1 << (BITSIZE(__int128) - 1)), 42) == 0 ? 1 : -1]; // expected-warning {{variable length array folded to constant array as an extension}}
-                                                                                                 // expected-note at -1 {{shift count 127 >= width of type 'int' (32 bits)}}
+char clz56[__builtin_clzg((unsigned __int128)(1 << (BITSIZE(__int128) - 1))) == 0 ? 1 : -1]; // expected-error {{variable length array declaration not allowed at file scope}}
+char clz57[__builtin_clzg((unsigned __int128)(1 << (BITSIZE(__int128) - 1)), 42) == 0 ? 1 : -1]; // expected-error {{variable length array declaration not allowed at file scope}}
 #endif
 int clz58 = __builtin_clzg((unsigned _BitInt(128))0); // expected-error {{not a compile-time constant}}
 char clz59[__builtin_clzg((unsigned _BitInt(128))0, 42) == 42 ? 1 : -1];
@@ -276,10 +274,8 @@ char clz60[__builtin_clzg((unsigned _BitInt(128))0x1) == BITSIZE(_BitInt(128)) -
 char clz61[__builtin_clzg((unsigned _BitInt(128))0x1, 42) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
 char clz62[__builtin_clzg((unsigned _BitInt(128))0xf) == BITSIZE(_BitInt(128)) - 4 ? 1 : -1];
 char clz63[__builtin_clzg((unsigned _BitInt(128))0xf, 42) == BITSIZE(_BitInt(128)) - 4 ? 1 : -1];
-char clz64[__builtin_clzg((unsigned _BitInt(128))(1 << (BITSIZE(_BitInt(128)) - 1))) == 0 ? 1 : -1]; // expected-warning {{variable length array folded to constant array as an extension}}
-                                                                                                     // expected-note at -1 {{shift count 127 >= width of type 'int' (32 bits)}}
-char clz65[__builtin_clzg((unsigned _BitInt(128))(1 << (BITSIZE(_BitInt(128)) - 1)), 42) == 0 ? 1 : -1]; // expected-warning {{variable length array folded to constant array as an extension}}
-                                                                                                         // expected-note at -1 {{shift count 127 >= width of type 'int' (32 bits)}}
+char clz64[__builtin_clzg((unsigned _BitInt(128))(1 << (BITSIZE(_BitInt(128)) - 1))) == 0 ? 1 : -1]; // expected-error {{variable length array declaration not allowed at file scope}}
+char clz65[__builtin_clzg((unsigned _BitInt(128))(1 << (BITSIZE(_BitInt(128)) - 1)), 42) == 0 ? 1 : -1]; // expected-error {{variable length array declaration not allowed at file scope}}
 
 char ctz1[__builtin_ctz(1) == 0 ? 1 : -1];
 char ctz2[__builtin_ctz(8) == 3 ? 1 : -1];
diff --git a/clang/test/Sema/shift-count-negative.c b/clang/test/Sema/shift-count-negative.c
index 84c7625187a68..a89d7630d0de4 100644
--- a/clang/test/Sema/shift-count-negative.c
+++ b/clang/test/Sema/shift-count-negative.c
@@ -1,11 +1,12 @@
-// RUN: %clang_cc1 -x c -fsyntax-only -verify=expected,c -pedantic %s
-// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cpp %s
+// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -pedantic %s
 
-// RUN: %clang_cc1 -x c -fsyntax-only -verify=expected,c -pedantic %s -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cpp %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -pedantic %s -fexperimental-new-constant-interpreter
+
+// cpp-no-diagnostics
 
 enum shiftof {
-    X = (1<<-29) // c-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}}
-                 // cpp-error at -1 {{expression is not an integral constant expression}}
-                 // expected-note at -2 {{negative shift count -29}}
+    X = (1<<-29) // expected-warning {{folding it to a constant is a GNU extension}}
+                 // expected-note at -1 {{negative shift count -29}}
 };
diff --git a/clang/test/Sema/shift-count-overflow.c b/clang/test/Sema/shift-count-overflow.c
index b5186586c2272..a7169fc4294f3 100644
--- a/clang/test/Sema/shift-count-overflow.c
+++ b/clang/test/Sema/shift-count-overflow.c
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -fsyntax-only -verify=expected,c -pedantic %s
-// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify=expected,cpp %s
-// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify=expected,cpp %s
+// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify=cxx98 -pedantic %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify -pedantic %s
 
 enum shiftof {
-    X = (1<<32) // c-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}}
-                // cpp-error at -1 {{expression is not an integral constant expression}}
-                // expected-note at -2 {{shift count 32 >= width of type 'int'}}
+    X = (1<<32) // expected-warning {{folding it to a constant is a GNU extension}}
+                // expected-note at -1 {{shift count 32 >= width of type 'int'}}
+                // cxx98-error at -2 {{expression is not an integral constant expression}}
+                // cxx98-note at -3 {{shift count 32 >= width of type 'int'}}
 };
diff --git a/clang/test/Sema/shift-negative-value.c b/clang/test/Sema/shift-negative-value.c
index e7b749c77d88a..fe5e9e91634e2 100644
--- a/clang/test/Sema/shift-negative-value.c
+++ b/clang/test/Sema/shift-negative-value.c
@@ -1,13 +1,11 @@
-// RUN: %clang_cc1 -x c -fsyntax-only -verify=expected,c -pedantic %s
-// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cpp -Wshift-negative-value %s
-// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cpp -Wall %s
-// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify=expected,cpp -Wshift-negative-value %s
-// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify=expected,cpp -Wall %s
-// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify=expected,cpp -Wshift-negative-value %s
-// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify=expected,cpp -Wall %s
+// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify=cpp98 %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify -pedantic %s
 
 enum shiftof {
-    X = (-1<<29) // c-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}}
-                 // cpp-error at -1 {{expression is not an integral constant expression}}
-                 // expected-note at -2 {{left shift of negative value -1}}
+    X = (-1<<29) // expected-warning {{folding it to a constant is a GNU extension}}
+                 // expected-note at -1 {{left shift of negative value -1}}
+                 // cpp98-error at -2 {{expression is not an integral constant expression}}
+                 // cpp98-note at -3 {{left shift of negative value -1}}
 };

>From 788f33c2b33599886dfe61c3c91deee56c0855e9 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Thu, 18 Jul 2024 17:23:42 -0700
Subject: [PATCH 2/5] Fixup! add missing check for negative left shift.

---
 clang/lib/AST/ExprConstant.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index bd69dc54a93dc..f79a5c03e5940 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -2839,6 +2839,8 @@ static bool handleIntIntBinOp(EvalInfo &Info, const BinaryOperator *E,
       // During constant-folding, a negative shift is an opposite shift. Such
       // a shift is not a constant expression.
       Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
+      if (!Info.noteUndefinedBehavior())
+        return false;
       RHS = -RHS;
       goto shift_right;
     }

>From b1f75cd1b9a10179915394284096523820d6214d Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Thu, 18 Jul 2024 17:59:21 -0700
Subject: [PATCH 3/5] Handle overflow in C++ constant expressions more
 strictly.

---
 clang/lib/Sema/SemaExpr.cpp            |  3 ++-
 clang/test/AST/Interp/shifts.cpp       | 13 ++++++++++---
 clang/test/Sema/shift-count-negative.c | 15 +++++++--------
 clang/test/Sema/shift-count-overflow.c | 13 ++++++-------
 clang/test/Sema/shift-negative-value.c | 18 ++++++++++--------
 clang/test/SemaCXX/enum.cpp            |  2 +-
 6 files changed, 36 insertions(+), 28 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 0698c3fbe98d2..2af7cb862b83b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -17007,7 +17007,8 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
   // not a constant expression as a side-effect.
   bool Folded =
       E->EvaluateAsRValue(EvalResult, Context, /*isConstantContext*/ true) &&
-      EvalResult.Val.isInt() && !EvalResult.HasSideEffects;
+      EvalResult.Val.isInt() && !EvalResult.HasSideEffects &&
+      (!getLangOpts().CPlusPlus || !EvalResult.HasUndefinedBehavior);
 
   if (!isa<ConstantExpr>(E))
     E = ConstantExpr::Create(Context, E, EvalResult.Val);
diff --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp
index 2873d6ec1bbfb..360b87b7ee04f 100644
--- a/clang/test/AST/Interp/shifts.cpp
+++ b/clang/test/AST/Interp/shifts.cpp
@@ -200,7 +200,14 @@ namespace LongInt {
 };
 
 enum shiftof {
-    X = (1<<-29),
-    X2 = (-1<<29),
-    X3 = (1<<32),
+    X = (1<<-29), // all-error {{expression is not an integral constant expression}} \
+                  // all-note {{negative shift count -29}}
+
+    X2 = (-1<<29), // cxx17-error {{expression is not an integral constant expression}} \
+                   // cxx17-note {{left shift of negative value -1}} \
+                   // ref-cxx17-error {{expression is not an integral constant expression}} \
+                   // ref-cxx17-note {{left shift of negative value -1}}
+
+    X3 = (1<<32) // all-error {{expression is not an integral constant expression}} \
+                 // all-note {{shift count 32 >= width of type 'int'}}
 };
diff --git a/clang/test/Sema/shift-count-negative.c b/clang/test/Sema/shift-count-negative.c
index a89d7630d0de4..84c7625187a68 100644
--- a/clang/test/Sema/shift-count-negative.c
+++ b/clang/test/Sema/shift-count-negative.c
@@ -1,12 +1,11 @@
-// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s
-// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -x c -fsyntax-only -verify=expected,c -pedantic %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cpp %s
 
-// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s -fexperimental-new-constant-interpreter
-// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -pedantic %s -fexperimental-new-constant-interpreter
-
-// cpp-no-diagnostics
+// RUN: %clang_cc1 -x c -fsyntax-only -verify=expected,c -pedantic %s -fexperimental-new-constant-interpreter
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cpp %s -fexperimental-new-constant-interpreter
 
 enum shiftof {
-    X = (1<<-29) // expected-warning {{folding it to a constant is a GNU extension}}
-                 // expected-note at -1 {{negative shift count -29}}
+    X = (1<<-29) // c-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}}
+                 // cpp-error at -1 {{expression is not an integral constant expression}}
+                 // expected-note at -2 {{negative shift count -29}}
 };
diff --git a/clang/test/Sema/shift-count-overflow.c b/clang/test/Sema/shift-count-overflow.c
index a7169fc4294f3..b5186586c2272 100644
--- a/clang/test/Sema/shift-count-overflow.c
+++ b/clang/test/Sema/shift-count-overflow.c
@@ -1,10 +1,9 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -pedantic %s
-// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify=cxx98 -pedantic %s
-// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,c -pedantic %s
+// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify=expected,cpp %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify=expected,cpp %s
 
 enum shiftof {
-    X = (1<<32) // expected-warning {{folding it to a constant is a GNU extension}}
-                // expected-note at -1 {{shift count 32 >= width of type 'int'}}
-                // cxx98-error at -2 {{expression is not an integral constant expression}}
-                // cxx98-note at -3 {{shift count 32 >= width of type 'int'}}
+    X = (1<<32) // c-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}}
+                // cpp-error at -1 {{expression is not an integral constant expression}}
+                // expected-note at -2 {{shift count 32 >= width of type 'int'}}
 };
diff --git a/clang/test/Sema/shift-negative-value.c b/clang/test/Sema/shift-negative-value.c
index fe5e9e91634e2..e7b749c77d88a 100644
--- a/clang/test/Sema/shift-negative-value.c
+++ b/clang/test/Sema/shift-negative-value.c
@@ -1,11 +1,13 @@
-// RUN: %clang_cc1 -x c -fsyntax-only -verify -pedantic %s
-// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -pedantic %s
-// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify=cpp98 %s
-// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify -pedantic %s
+// RUN: %clang_cc1 -x c -fsyntax-only -verify=expected,c -pedantic %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cpp -Wshift-negative-value %s
+// RUN: %clang_cc1 -x c++ -fsyntax-only -verify=expected,cpp -Wall %s
+// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify=expected,cpp -Wshift-negative-value %s
+// RUN: %clang_cc1 -x c++ -std=c++98 -fsyntax-only -verify=expected,cpp -Wall %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify=expected,cpp -Wshift-negative-value %s
+// RUN: %clang_cc1 -x c++ -std=c++11 -fsyntax-only -verify=expected,cpp -Wall %s
 
 enum shiftof {
-    X = (-1<<29) // expected-warning {{folding it to a constant is a GNU extension}}
-                 // expected-note at -1 {{left shift of negative value -1}}
-                 // cpp98-error at -2 {{expression is not an integral constant expression}}
-                 // cpp98-note at -3 {{left shift of negative value -1}}
+    X = (-1<<29) // c-warning {{expression is not an integer constant expression; folding it to a constant is a GNU extension}}
+                 // cpp-error at -1 {{expression is not an integral constant expression}}
+                 // expected-note at -2 {{left shift of negative value -1}}
 };
diff --git a/clang/test/SemaCXX/enum.cpp b/clang/test/SemaCXX/enum.cpp
index 739d35ec4a06b..f052274b7b6a7 100644
--- a/clang/test/SemaCXX/enum.cpp
+++ b/clang/test/SemaCXX/enum.cpp
@@ -104,7 +104,7 @@ void PR8089() {
 // expressions with UB to be non-constant.
 enum { overflow = 123456 * 234567 };
 #if __cplusplus >= 201103L
-// expected-warning at -2 {{expression is not an integral constant expression; folding it to a constant is a GNU extension}}
+// expected-error at -2 {{expression is not an integral constant expression}}
 // expected-note at -3 {{value 28958703552 is outside the range of representable values of type 'int'}}
 #else
 // expected-error at -5 {{expression is not an integral constant expression}}

>From c96b4aded070fd6f223cbd4e5887d273176f17d1 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Fri, 19 Jul 2024 12:05:30 -0700
Subject: [PATCH 4/5] fixup! add a few more tests.

---
 clang/test/SemaCXX/class.cpp |  5 ++++-
 clang/test/SemaCXX/enum.cpp  | 24 +++++++++++++++++-------
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/clang/test/SemaCXX/class.cpp b/clang/test/SemaCXX/class.cpp
index f874b7be2b70e..44ce151cc86eb 100644
--- a/clang/test/SemaCXX/class.cpp
+++ b/clang/test/SemaCXX/class.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -Wc++11-compat %s 
+// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx11 -Wc++11-compat %s
 // RUN: %clang_cc1 -fsyntax-only -verify -Wc++11-compat %s -std=c++98
 class C {
 public:
@@ -55,6 +55,9 @@ class C {
   // expected-error at -2 {{static const volatile data member must be initialized out of line}}
 #endif
   static const E evi = 0;
+  static const int overflow = 1000000*1000000; // cxx11-error {{in-class initializer for static data member is not a constant expression}}
+                                               // expected-warning at -1 {{overflow in expression}}
+  static const int overflow_shift = 1<<32; // cxx11-error {{in-class initializer for static data member is not a constant expression}}
 
   void m() {
     sx = 0;
diff --git a/clang/test/SemaCXX/enum.cpp b/clang/test/SemaCXX/enum.cpp
index f052274b7b6a7..9c398cc8da886 100644
--- a/clang/test/SemaCXX/enum.cpp
+++ b/clang/test/SemaCXX/enum.cpp
@@ -103,14 +103,14 @@ void PR8089() {
 // This is accepted as a GNU extension. In C++98, there was no provision for
 // expressions with UB to be non-constant.
 enum { overflow = 123456 * 234567 };
-#if __cplusplus >= 201103L
-// expected-error at -2 {{expression is not an integral constant expression}}
-// expected-note at -3 {{value 28958703552 is outside the range of representable values of type 'int'}}
-#else
-// expected-error at -5 {{expression is not an integral constant expression}}
-// expected-note at -6 {{value 28958703552 is outside the range of representable values of type 'int'}}
-// expected-warning at -7 {{overflow in expression; result is -1'106'067'520 with type 'int'}}
+// expected-error at -1 {{expression is not an integral constant expression}}
+// expected-note at -2 {{value 28958703552 is outside the range of representable values of type 'int'}}
+#if __cplusplus < 201103L
+// expected-warning at -4 {{overflow in expression; result is -1'106'067'520 with type 'int'}}
 #endif
+enum { overflow_shift = 1 << 32 };
+// expected-error at -1 {{expression is not an integral constant expression}}
+// expected-note at -2 {{shift count 32 >= width of type 'int' (32 bits)}}
 
 // FIXME: This is not consistent with the above case.
 enum NoFold : int { overflow2 = 123456 * 234567 };
@@ -123,6 +123,16 @@ enum NoFold : int { overflow2 = 123456 * 234567 };
 // expected-error at -7 {{expression is not an integral constant expression}}
 // expected-note at -8 {{value 28958703552 is outside the range of representable values of type 'int'}}
 #endif
+enum : int { overflow2_shift = 1 << 32 };
+#if __cplusplus >= 201103L
+// expected-error at -2 {{enumerator value is not a constant expression}}
+// expected-note at -3 {{shift count 32 >= width of type 'int' (32 bits)}}
+#else
+// expected-error at -5 {{expression is not an integral constant expression}}
+// expected-note at -6 {{shift count 32 >= width of type 'int' (32 bits)}}
+// expected-warning at -7 {{enumeration types with a fixed underlying type are a C++11 extension}}
+#endif
+
 
 // PR28903
 struct PR28903 {

>From 22a511cc9b79bc589ee5fcf78063b5785122f693 Mon Sep 17 00:00:00 2001
From: Eli Friedman <efriedma at quicinc.com>
Date: Fri, 19 Jul 2024 12:17:28 -0700
Subject: [PATCH 5/5] fixup! fix formatting

---
 clang/lib/AST/Interp/Interp.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 1b17db61d7bac..fa74e995edac5 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -160,7 +160,8 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
       S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
       if (!S.noteUndefinedBehavior())
         return false;
-    } else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS)) {
+    } else if (LHS.toUnsigned().countLeadingZeros() <
+               static_cast<unsigned>(RHS)) {
       S.CCEDiag(E, diag::note_constexpr_lshift_discards);
       if (!S.noteUndefinedBehavior())
         return false;



More information about the cfe-commits mailing list