[clang] [Clang][Sema] Fix missing warning when comparing mismatched enums in … (PR #81389)

via cfe-commits cfe-commits at lists.llvm.org
Sat Feb 10 15:32:05 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: None (44-2-Kupa-Martin)

<details>
<summary>Changes</summary>

…C mode

Factored logic from `CheckImplicitConversion` into new methods `Expr::getEnumConstantDecl` and `Expr::getEnumCoercedType` for use in `checkEnumArithmeticConversions`.

Fix #<!-- -->29217

---

Patch is 650.51 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81389.diff


9 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+3) 
- (modified) clang/include/clang/AST/Expr.h (+256-269) 
- (modified) clang/lib/AST/Expr.cpp (+585-463) 
- (modified) clang/lib/Sema/SemaChecking.cpp (+1428-1193) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+1534-1453) 
- (modified) clang/test/Sema/builtins-elementwise-math.c (+4) 
- (added) clang/test/Sema/warn-compare-enum-types-mismatch.c (+42) 
- (renamed) clang/test/Sema/warn-conditional-enum-types-mismatch.c (+1-1) 
- (modified) clang/test/Sema/warn-overlap.c (+2-2) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ece6013f672621..00ddf0b9656a31 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -161,6 +161,9 @@ Improvements to Clang's time-trace
 
 Bug Fixes in This Version
 -------------------------
+- Fixed missing warnings when comparing mismatched enumeration constants
+  in C (`#29217 <https://github.com/llvm/llvm-project/issues/29217>`).
+
 - Clang now accepts elaborated-type-specifiers that explicitly specialize
   a member class template for an implicit instantiation of a class template.
 
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index 3fc481a62a78a9..4f11f3eb610564 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -40,26 +40,26 @@
 #include <optional>
 
 namespace clang {
-  class APValue;
-  class ASTContext;
-  class BlockDecl;
-  class CXXBaseSpecifier;
-  class CXXMemberCallExpr;
-  class CXXOperatorCallExpr;
-  class CastExpr;
-  class Decl;
-  class IdentifierInfo;
-  class MaterializeTemporaryExpr;
-  class NamedDecl;
-  class ObjCPropertyRefExpr;
-  class OpaqueValueExpr;
-  class ParmVarDecl;
-  class StringLiteral;
-  class TargetInfo;
-  class ValueDecl;
+class APValue;
+class ASTContext;
+class BlockDecl;
+class CXXBaseSpecifier;
+class CXXMemberCallExpr;
+class CXXOperatorCallExpr;
+class CastExpr;
+class Decl;
+class IdentifierInfo;
+class MaterializeTemporaryExpr;
+class NamedDecl;
+class ObjCPropertyRefExpr;
+class OpaqueValueExpr;
+class ParmVarDecl;
+class StringLiteral;
+class TargetInfo;
+class ValueDecl;
 
 /// A simple array of base specifiers.
-typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath;
+typedef SmallVector<CXXBaseSpecifier *, 4> CXXCastPath;
 
 /// An adjustment to be made to the temporary created when emitting a
 /// reference binding, which accesses a particular subobject of that temporary.
@@ -88,7 +88,7 @@ struct SubobjectAdjustment {
 
   SubobjectAdjustment(const CastExpr *BasePath,
                       const CXXRecordDecl *DerivedClass)
-    : Kind(DerivedToBaseAdjustment) {
+      : Kind(DerivedToBaseAdjustment) {
     DerivedToBase.BasePath = BasePath;
     DerivedToBase.DerivedClass = DerivedClass;
   }
@@ -98,7 +98,7 @@ struct SubobjectAdjustment {
   }
 
   SubobjectAdjustment(const MemberPointerType *MPT, Expr *RHS)
-    : Kind(MemberPointerAdjustment) {
+      : Kind(MemberPointerAdjustment) {
     this->Ptr.MPT = MPT;
     this->Ptr.RHS = RHS;
   }
@@ -112,10 +112,10 @@ class Expr : public ValueStmt {
 
 public:
   Expr() = delete;
-  Expr(const Expr&) = delete;
+  Expr(const Expr &) = delete;
   Expr(Expr &&) = delete;
-  Expr &operator=(const Expr&) = delete;
-  Expr &operator=(Expr&&) = delete;
+  Expr &operator=(const Expr &) = delete;
+  Expr &operator=(Expr &&) = delete;
 
 protected:
   Expr(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK)
@@ -128,7 +128,7 @@ class Expr : public ValueStmt {
   }
 
   /// Construct an empty expression.
-  explicit Expr(StmtClass SC, EmptyShell) : ValueStmt(SC) { }
+  explicit Expr(StmtClass SC, EmptyShell) : ValueStmt(SC) {}
 
   /// Each concrete expr subclass is expected to compute its dependence and call
   /// this in the constructor.
@@ -153,6 +153,12 @@ class Expr : public ValueStmt {
     TR = t;
   }
 
+  /// If this expression is an enumeration constant, return the
+  /// enumeration type under which said constant was declared.
+  /// Otherwise return the expression's type.
+  /// Note this effectively circumvents the weak typing of C's enum constants
+  QualType getEnumCoercedType(const ASTContext &Ctx) const;
+
   ExprDependence getDependence() const {
     return static_cast<ExprDependence>(ExprBits.Dependent);
   }
@@ -294,7 +300,7 @@ class Expr : public ValueStmt {
     MLV_IncompleteVoidType,
     MLV_DuplicateVectorComponents,
     MLV_InvalidExpression,
-    MLV_LValueCast,           // Specialized form of MLV_InvalidExpression.
+    MLV_LValueCast, // Specialized form of MLV_InvalidExpression.
     MLV_IncompleteType,
     MLV_ConstQualified,
     MLV_ConstQualifiedField,
@@ -327,25 +333,26 @@ class Expr : public ValueStmt {
     enum Kinds {
       CL_LValue,
       CL_XValue,
-      CL_Function, // Functions cannot be lvalues in C.
-      CL_Void, // Void cannot be an lvalue in C.
+      CL_Function,        // Functions cannot be lvalues in C.
+      CL_Void,            // Void cannot be an lvalue in C.
       CL_AddressableVoid, // Void expression whose address can be taken in C.
       CL_DuplicateVectorComponents, // A vector shuffle with dupes.
       CL_MemberFunction, // An expression referring to a member function
       CL_SubObjCPropertySetting,
-      CL_ClassTemporary, // A temporary of class type, or subobject thereof.
-      CL_ArrayTemporary, // A temporary of array type.
+      CL_ClassTemporary,    // A temporary of class type, or subobject thereof.
+      CL_ArrayTemporary,    // A temporary of array type.
       CL_ObjCMessageRValue, // ObjC message is an rvalue
-      CL_PRValue // A prvalue for any other reason, of any other type
+      CL_PRValue            // A prvalue for any other reason, of any other type
     };
     /// The results of modification testing.
     enum ModifiableType {
       CM_Untested, // testModifiable was false.
       CM_Modifiable,
-      CM_RValue, // Not modifiable because it's an rvalue
-      CM_Function, // Not modifiable because it's a function; C++ only
+      CM_RValue,     // Not modifiable because it's an rvalue
+      CM_Function,   // Not modifiable because it's a function; C++ only
       CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext
-      CM_NoSetterProperty,// Implicit assignment to ObjC property without setter
+      CM_NoSetterProperty, // Implicit assignment to ObjC property without
+                           // setter
       CM_ConstQualified,
       CM_ConstQualifiedField,
       CM_ConstAddrSpace,
@@ -360,8 +367,7 @@ class Expr : public ValueStmt {
     unsigned short Modifiable;
 
     explicit Classification(Kinds k, ModifiableType m)
-      : Kind(k), Modifiable(m)
-    {}
+        : Kind(k), Modifiable(m) {}
 
   public:
     Classification() {}
@@ -382,7 +388,6 @@ class Expr : public ValueStmt {
     static Classification makeSimpleLValue() {
       return Classification(CL_LValue, CM_Modifiable);
     }
-
   };
   /// Classify - Classify this expression according to the C++11
   ///        expression taxonomy.
@@ -408,7 +413,8 @@ class Expr : public ValueStmt {
   /// expression is modifiable (C99 6.3.2.1p1).
   /// \param Loc A source location that might be filled with a relevant location
   ///            if the expression is not modifiable.
-  Classification ClassifyModifiable(ASTContext &Ctx, SourceLocation &Loc) const{
+  Classification ClassifyModifiable(ASTContext &Ctx,
+                                    SourceLocation &Loc) const {
     return ClassifyImpl(Ctx, &Loc);
   }
 
@@ -421,9 +427,9 @@ class Expr : public ValueStmt {
   static ExprValueKind getValueKindForType(QualType T) {
     if (const ReferenceType *RT = T->getAs<ReferenceType>())
       return (isa<LValueReferenceType>(RT)
-                ? VK_LValue
-                : (RT->getPointeeType()->isFunctionType()
-                     ? VK_LValue : VK_XValue));
+                  ? VK_LValue
+                  : (RT->getPointeeType()->isFunctionType() ? VK_LValue
+                                                            : VK_XValue));
     return VK_PRValue;
   }
 
@@ -454,7 +460,6 @@ class Expr : public ValueStmt {
   Classification ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const;
 
 public:
-
   /// Returns true if this expression is a gl-value that
   /// potentially refers to a bit-field.
   ///
@@ -472,12 +477,19 @@ class Expr : public ValueStmt {
   FieldDecl *getSourceBitField();
 
   const FieldDecl *getSourceBitField() const {
-    return const_cast<Expr*>(this)->getSourceBitField();
+    return const_cast<Expr *>(this)->getSourceBitField();
+  }
+
+  /// If this expression refers to an enum constant, retrieve its declaration
+  EnumConstantDecl *getEnumConstantDecl();
+
+  const EnumConstantDecl *getEnumConstantDecl() const {
+    return const_cast<Expr *>(this)->getEnumConstantDecl();
   }
 
   Decl *getReferencedDeclOfCallee();
   const Decl *getReferencedDeclOfCallee() const {
-    return const_cast<Expr*>(this)->getReferencedDeclOfCallee();
+    return const_cast<Expr *>(this)->getReferencedDeclOfCallee();
   }
 
   /// If this expression is an l-value for an Objective C
@@ -500,9 +512,7 @@ class Expr : public ValueStmt {
   bool refersToGlobalRegisterVar() const;
 
   /// Returns whether this expression has a placeholder type.
-  bool hasPlaceholderType() const {
-    return getType()->isPlaceholderType();
-  }
+  bool hasPlaceholderType() const { return getType()->isPlaceholderType(); }
 
   /// Returns whether this expression has a specific placeholder type.
   bool hasPlaceholderType(BuiltinType::Kind K) const {
@@ -562,19 +572,18 @@ class Expr : public ValueStmt {
   /// might be usable in a constant expression in C++11, if it were marked
   /// constexpr. Return false if the function can never produce a constant
   /// expression, along with diagnostics describing why not.
-  static bool isPotentialConstantExpr(const FunctionDecl *FD,
-                                      SmallVectorImpl<
-                                        PartialDiagnosticAt> &Diags);
+  static bool
+  isPotentialConstantExpr(const FunctionDecl *FD,
+                          SmallVectorImpl<PartialDiagnosticAt> &Diags);
 
   /// isPotentialConstantExprUnevaluated - Return true if this expression might
   /// be usable in a constant expression in C++11 in an unevaluated context, if
   /// it were in function FD marked constexpr. Return false if the function can
   /// never produce a constant expression, along with diagnostics describing
   /// why not.
-  static bool isPotentialConstantExprUnevaluated(Expr *E,
-                                                 const FunctionDecl *FD,
-                                                 SmallVectorImpl<
-                                                   PartialDiagnosticAt> &Diags);
+  static bool isPotentialConstantExprUnevaluated(
+      Expr *E, const FunctionDecl *FD,
+      SmallVectorImpl<PartialDiagnosticAt> &Diags);
 
   /// isConstantInitializer - Returns true if this expression can be emitted to
   /// IR as a constant, and thus can be used as a constant initializer in C.
@@ -620,9 +629,7 @@ class Expr : public ValueStmt {
 
     // hasSideEffects - Return true if the evaluated expression has
     // side effects.
-    bool hasSideEffects() const {
-      return HasSideEffects;
-    }
+    bool hasSideEffects() const { return HasSideEffects; }
   };
 
   /// EvalResult is a struct with detailed info about an evaluated expression.
@@ -729,7 +736,7 @@ class Expr : public ValueStmt {
   /// constant.
   bool EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
                                 const FunctionDecl *Callee,
-                                ArrayRef<const Expr*> Args,
+                                ArrayRef<const Expr *> Args,
                                 const Expr *This = nullptr) const;
 
   enum class ConstantExprKind {
@@ -815,9 +822,9 @@ class Expr : public ValueStmt {
   /// isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to
   /// a Null pointer constant. The return value can further distinguish the
   /// kind of NULL pointer constant that was detected.
-  NullPointerConstantKind isNullPointerConstant(
-      ASTContext &Ctx,
-      NullPointerConstantValueDependence NPC) const;
+  NullPointerConstantKind
+  isNullPointerConstant(ASTContext &Ctx,
+                        NullPointerConstantValueDependence NPC) const;
 
   /// isOBJCGCCandidate - Return true if this expression may be used in a read/
   /// write barrier.
@@ -1003,7 +1010,7 @@ class Expr : public ValueStmt {
   /// Checks that the two Expr's will refer to the same value as a comparison
   /// operand.  The caller must ensure that the values referenced by the Expr's
   /// are not modified between E1 and E2 or the result my be invalid.
-  static bool isSameComparisonOperand(const Expr* E1, const Expr* E2);
+  static bool isSameComparisonOperand(const Expr *E1, const Expr *E2);
 
   static bool classof(const Stmt *T) {
     return T->getStmtClass() >= firstExprConstant &&
@@ -1025,16 +1032,16 @@ using ConstantExprKind = Expr::ConstantExprKind;
 /// FullExpr - Represents a "full-expression" node.
 class FullExpr : public Expr {
 protected:
- Stmt *SubExpr;
-
- FullExpr(StmtClass SC, Expr *subexpr)
-     : Expr(SC, subexpr->getType(), subexpr->getValueKind(),
-            subexpr->getObjectKind()),
-       SubExpr(subexpr) {
-   setDependence(computeDependence(this));
- }
-  FullExpr(StmtClass SC, EmptyShell Empty)
-    : Expr(SC, Empty) {}
+  Stmt *SubExpr;
+
+  FullExpr(StmtClass SC, Expr *subexpr)
+      : Expr(SC, subexpr->getType(), subexpr->getValueKind(),
+             subexpr->getObjectKind()),
+        SubExpr(subexpr) {
+    setDependence(computeDependence(this));
+  }
+  FullExpr(StmtClass SC, EmptyShell Empty) : Expr(SC, Empty) {}
+
 public:
   const Expr *getSubExpr() const { return cast<Expr>(SubExpr); }
   Expr *getSubExpr() { return cast<Expr>(SubExpr); }
@@ -1137,7 +1144,7 @@ class ConstantExpr final
   APValue getAPValueResult() const;
   llvm::APSInt getResultAsAPSInt() const;
   // Iterators
-  child_range children() { return child_range(&SubExpr, &SubExpr+1); }
+  child_range children() { return child_range(&SubExpr, &SubExpr + 1); }
   const_child_range children() const {
     return const_child_range(&SubExpr, &SubExpr + 1);
   }
@@ -1171,7 +1178,7 @@ class OpaqueValueExpr : public Expr {
   static const OpaqueValueExpr *findInCopyConstruct(const Expr *expr);
 
   explicit OpaqueValueExpr(EmptyShell Empty)
-    : Expr(OpaqueValueExprClass, Empty) {}
+      : Expr(OpaqueValueExprClass, Empty) {}
 
   /// Retrieve the location of this expression.
   SourceLocation getLocation() const { return OpaqueValueExprBits.Loc; }
@@ -1483,7 +1490,7 @@ class IntegerLiteral : public Expr, public APIntStorage {
 
   /// Construct an empty integer literal.
   explicit IntegerLiteral(EmptyShell Empty)
-    : Expr(IntegerLiteralClass, Empty) { }
+      : Expr(IntegerLiteralClass, Empty) {}
 
 public:
   // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy,
@@ -1529,7 +1536,7 @@ class FixedPointLiteral : public Expr, public APIntStorage {
   explicit FixedPointLiteral(EmptyShell Empty)
       : Expr(FixedPointLiteralClass, Empty) {}
 
- public:
+public:
   FixedPointLiteral(const ASTContext &C, const llvm::APInt &V, QualType type,
                     SourceLocation l, unsigned Scale);
 
@@ -1573,6 +1580,7 @@ enum class CharacterLiteralKind { Ascii, Wide, UTF8, UTF16, UTF32 };
 class CharacterLiteral : public Expr {
   unsigned Value;
   SourceLocation Loc;
+
 public:
   // type should be IntTy
   CharacterLiteral(unsigned value, CharacterLiteralKind kind, QualType type,
@@ -1584,7 +1592,7 @@ class CharacterLiteral : public Expr {
   }
 
   /// Construct an empty character literal.
-  CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { }
+  CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) {}
 
   SourceLocation getLocation() const { return Loc; }
   CharacterLiteralKind getKind() const {
@@ -1698,6 +1706,7 @@ class FloatingLiteral : public Expr, private APFloatStorage {
 ///
 class ImaginaryLiteral : public Expr {
   Stmt *Val;
+
 public:
   ImaginaryLiteral(Expr *val, QualType Ty)
       : Expr(ImaginaryLiteralClass, Ty, VK_PRValue, OK_Ordinary), Val(val) {
@@ -1706,7 +1715,7 @@ class ImaginaryLiteral : public Expr {
 
   /// Build an empty imaginary literal.
   explicit ImaginaryLiteral(EmptyShell Empty)
-    : Expr(ImaginaryLiteralClass, Empty) { }
+      : Expr(ImaginaryLiteralClass, Empty) {}
 
   const Expr *getSubExpr() const { return cast<Expr>(Val); }
   Expr *getSubExpr() { return cast<Expr>(Val); }
@@ -1722,7 +1731,7 @@ class ImaginaryLiteral : public Expr {
   }
 
   // Iterators
-  child_range children() { return child_range(&Val, &Val+1); }
+  child_range children() { return child_range(&Val, &Val + 1); }
   const_child_range children() const {
     return const_child_range(&Val, &Val + 1);
   }
@@ -1875,7 +1884,9 @@ class StringLiteral final
   bool isUTF8() const { return getKind() == StringLiteralKind::UTF8; }
   bool isUTF16() const { return getKind() == StringLiteralKind::UTF16; }
   bool isUTF32() const { return getKind() == StringLiteralKind::UTF32; }
-  bool isUnevaluated() const { return getKind() == StringLiteralKind::Unevaluated; }
+  bool isUnevaluated() const {
+    return getKind() == StringLiteralKind::Unevaluated;
+  }
   bool isPascal() const { return StringLiteralBits.IsPascal; }
 
   bool containsNonAscii() const {
@@ -2105,6 +2116,7 @@ class SYCLUniqueStableNameExpr final : public Expr {
 class ParenExpr : public Expr {
   SourceLocation L, R;
   Stmt *Val;
+
 public:
   ParenExpr(SourceLocation l, SourceLocation r, Expr *val)
       : Expr(ParenExprClass, val->getType(), val->getValueKind(),
@@ -2114,8 +2126,7 @@ class ParenExpr : public Expr {
   }
 
   /// Construct an empty parenthesized expression.
-  explicit ParenExpr(EmptyShell Empty)
-    : Expr(ParenExprClass, Empty) { }
+  explicit ParenExpr(EmptyShell Empty) : Expr(ParenExprClass, Empty) {}
 
   const Expr *getSubExpr() const { return cast<Expr>(Val); }
   Expr *getSubExpr() { return cast<Expr>(Val); }
@@ -2137,7 +2148,7 @@ class ParenExpr : public Expr {
   }
 
   // Iterators
-  child_range children() { return child_range(&Val, &Val+1); }
+  child_range children() { return child_range(&Val, &Val + 1); }
   const_child_range children() const {
     return const_child_range(&Val, &Val + 1);
   }
@@ -2234,9 +2245,7 @@ class UnaryOperator final
   }
 
   /// isPrefix - Return true if this is a prefix operation, like --x.
-  static bool isPrefix(Opcode Op) {
-    return Op == UO_PreInc || Op == UO_PreDec;
-  }
+  static bool isPrefix(Opcode Op) { return Op == UO_PreInc || Op == UO_PreDec; }
 
   bool isPrefix() const { return isPrefix(getOpcode()); }
   bool isPostfix() const { return isPostfix(getOpcode()); }
@@ -2244,16 +2253,12 @@ class UnaryOperator final
   static bool isIncrementOp(Opcode Op) {
     return Op == UO_PreInc || Op == UO_PostInc;
   }
-  bool isIncrementOp() const {
-    return isIncrementOp(getOpcode());
-  }
+  bool isIncrementOp() const { return isIncrementOp(getOpcode()); }
 
   static bool isDecrementOp(Opcode Op) {
     return Op == UO_PreDec || Op == UO_PostDec;
   }
-  bool isDecrementOp() const {
-    return isDecrementOp(getOpcode());
-  }
+  bool isDecrementOp() const { return isDecrementOp(getOpcode()); }
 
   static bool isIncrementDecrementOp(Opcode Op) { return Op <= UO_PreDec; }
   bool isIncrementDecrementOp() const {
@@ -2290,7 +2295,7 @@ class UnaryOperator final
   }
 
   // Iterators
-  child_range children() { return child_range(&Val, &Val+1); }
+  child_range children() { return child_range(&Val, &Val + 1); }
   const_child_range children() const {
     return const_child_range(&Val, &Val + 1);
   }
@@ -2450,24 +2455,22 @@ class OffsetOfExpr final
     return NumComps;
   }
 
-  OffsetOfExpr(const ASTContext &C, QualType type,
-               SourceLocation OperatorLoc, TypeSourceInfo *tsi,
-               ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
-               SourceLocation RParenLoc);
+  OffsetOfExpr(const ASTContext &C, QualType type, SourceLocation OperatorLoc,
+               TypeSourceInfo *tsi, ArrayRef<OffsetOfNode> comps,
+               ArrayRef<Expr *> exprs, SourceLocation RParenLoc);
 
   explicit OffsetOfExpr(unsigned numComps, unsigned numExprs)
-    : Expr(OffsetOfExprClass, EmptyShell()),
-      TSInfo(nullptr), NumComps(numComps), NumExprs(numExprs) {}
+      : Expr(OffsetOfExprClass, EmptyShell()), TSInfo(nullptr),
+        NumComps(numComps), NumExprs(numExprs) {}
 
 public:
-
   static OffsetOfExpr *Create(const ASTContext &C, QualType type,
                               SourceLocation OperatorLoc, TypeSourceInfo *tsi,
                               ArrayRef<OffsetOfNode> comps,
-                              ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/81389


More information about the cfe-commits mailing list