[clang] Revert "[Clang][Sema] Earlier type checking for builtin unary operators (#90500)" (PR #92149)

via cfe-commits cfe-commits at lists.llvm.org
Tue May 14 10:18:52 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Krystian Stasiowski (sdkrystian)

<details>
<summary>Changes</summary>

This reverts commit 8019cbbbbc94658d133583f7be6cd0023d30b0f3.

---

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


15 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (-3) 
- (modified) clang/include/clang/AST/Type.h (+1-4) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+179-175) 
- (modified) clang/test/AST/ast-dump-expr-json.cpp (+2-2) 
- (modified) clang/test/AST/ast-dump-expr.cpp (+1-1) 
- (modified) clang/test/AST/ast-dump-lambda.cpp (+1-1) 
- (removed) clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp (-65) 
- (modified) clang/test/CXX/over/over.built/ast.cpp (+30-128) 
- (modified) clang/test/CXX/over/over.built/p10.cpp (+1-1) 
- (modified) clang/test/CXX/over/over.built/p11.cpp (+1-1) 
- (modified) clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp (+15-10) 
- (modified) clang/test/Frontend/noderef_templates.cpp (+2-2) 
- (modified) clang/test/SemaCXX/cxx2b-deducing-this.cpp (+4-2) 
- (modified) clang/test/SemaTemplate/class-template-spec.cpp (+6-6) 
- (modified) clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp (+3-3) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a2e44efe41347..49ab222bec405 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -55,9 +55,6 @@ C++ Specific Potentially Breaking Changes
 
 - Clang now rejects pointer to member from parenthesized expression in unevaluated context such as ``decltype(&(foo::bar))``. (#GH40906).
 
-- Clang now performs semantic analysis for unary operators with dependent operands
-  that are known to be of non-class non-enumeration type prior to instantiation.
-
 ABI Changes in This Version
 ---------------------------
 - Fixed Microsoft name mangling of implicitly defined variables used for thread
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index da3834f19ca04..e6643469e0b33 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -8044,10 +8044,7 @@ inline bool Type::isUndeducedType() const {
 /// Determines whether this is a type for which one can define
 /// an overloaded operator.
 inline bool Type::isOverloadableType() const {
-  if (!CanonicalType->isDependentType())
-    return isRecordType() || isEnumeralType();
-  return !isArrayType() && !isFunctionType() && !isAnyPointerType() &&
-         !isMemberPointerType();
+  return isDependentType() || isRecordType() || isEnumeralType();
 }
 
 /// Determines whether this type is written as a typedef-name.
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 18fd5ba700ad3..e6c3fa51d54da 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -672,12 +672,12 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
 
   // We don't want to throw lvalue-to-rvalue casts on top of
   // expressions of certain types in C++.
-  if (getLangOpts().CPlusPlus) {
-    if (T == Context.OverloadTy || T->isRecordType() ||
-        (T->isDependentType() && !T->isAnyPointerType() &&
-         !T->isMemberPointerType()))
-      return E;
-  }
+  if (getLangOpts().CPlusPlus &&
+      (E->getType() == Context.OverloadTy ||
+       // FIXME: This is a hack! We want the lvalue-to-rvalue conversion applied
+       // to pointer types even if the pointee type is dependent.
+       (T->isDependentType() && !T->isPointerType()) || T->isRecordType()))
+    return E;
 
   // The C standard is actually really unclear on this point, and
   // DR106 tells us what the result should be but not why.  It's
@@ -10827,7 +10827,7 @@ static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc,
   if (const AtomicType *ResAtomicType = ResType->getAs<AtomicType>())
     ResType = ResAtomicType->getValueType();
 
-  assert(ResType->isAnyPointerType());
+  assert(ResType->isAnyPointerType() && !ResType->isDependentType());
   QualType PointeeTy = ResType->getPointeeType();
   return S.RequireCompleteSizedType(
       Loc, PointeeTy,
@@ -13955,8 +13955,11 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
 static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
                                                ExprValueKind &VK,
                                                ExprObjectKind &OK,
-                                               SourceLocation OpLoc, bool IsInc,
-                                               bool IsPrefix) {
+                                               SourceLocation OpLoc,
+                                               bool IsInc, bool IsPrefix) {
+  if (Op->isTypeDependent())
+    return S.Context.DependentTy;
+
   QualType ResType = Op->getType();
   // Atomic types can be used for increment / decrement where the non-atomic
   // versions can, so ignore the _Atomic() specifier for the purpose of
@@ -14038,6 +14041,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op,
   }
 }
 
+
 /// getPrimaryDecl - Helper function for CheckAddressOfOperand().
 /// This routine allows us to typecheck complex/recursive expressions
 /// where the declaration is needed for type checking. We only need to
@@ -14407,6 +14411,9 @@ static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) {
 static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
                                         SourceLocation OpLoc,
                                         bool IsAfterAmp = false) {
+  if (Op->isTypeDependent())
+    return S.Context.DependentTy;
+
   ExprResult ConvResult = S.UsualUnaryConversions(Op);
   if (ConvResult.isInvalid())
     return QualType();
@@ -15460,191 +15467,188 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
       return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 1);
   }
 
-  if (InputExpr->isTypeDependent() &&
-      InputExpr->getType()->isSpecificBuiltinType(BuiltinType::Dependent)) {
-    resultType = Context.DependentTy;
-  } else {
-    switch (Opc) {
-    case UO_PreInc:
-    case UO_PreDec:
-    case UO_PostInc:
-    case UO_PostDec:
-      resultType =
-          CheckIncrementDecrementOperand(*this, Input.get(), VK, OK, OpLoc,
-                                         Opc == UO_PreInc || Opc == UO_PostInc,
-                                         Opc == UO_PreInc || Opc == UO_PreDec);
-      CanOverflow = isOverflowingIntegerType(Context, resultType);
+  switch (Opc) {
+  case UO_PreInc:
+  case UO_PreDec:
+  case UO_PostInc:
+  case UO_PostDec:
+    resultType = CheckIncrementDecrementOperand(*this, Input.get(), VK, OK,
+                                                OpLoc,
+                                                Opc == UO_PreInc ||
+                                                Opc == UO_PostInc,
+                                                Opc == UO_PreInc ||
+                                                Opc == UO_PreDec);
+    CanOverflow = isOverflowingIntegerType(Context, resultType);
+    break;
+  case UO_AddrOf:
+    resultType = CheckAddressOfOperand(Input, OpLoc);
+    CheckAddressOfNoDeref(InputExpr);
+    RecordModifiableNonNullParam(*this, InputExpr);
+    break;
+  case UO_Deref: {
+    Input = DefaultFunctionArrayLvalueConversion(Input.get());
+    if (Input.isInvalid()) return ExprError();
+    resultType =
+        CheckIndirectionOperand(*this, Input.get(), VK, OpLoc, IsAfterAmp);
+    break;
+  }
+  case UO_Plus:
+  case UO_Minus:
+    CanOverflow = Opc == UO_Minus &&
+                  isOverflowingIntegerType(Context, Input.get()->getType());
+    Input = UsualUnaryConversions(Input.get());
+    if (Input.isInvalid()) return ExprError();
+    // Unary plus and minus require promoting an operand of half vector to a
+    // float vector and truncating the result back to a half vector. For now, we
+    // do this only when HalfArgsAndReturns is set (that is, when the target is
+    // arm or arm64).
+    ConvertHalfVec = needsConversionOfHalfVec(true, Context, Input.get());
+
+    // If the operand is a half vector, promote it to a float vector.
+    if (ConvertHalfVec)
+      Input = convertVector(Input.get(), Context.FloatTy, *this);
+    resultType = Input.get()->getType();
+    if (resultType->isDependentType())
       break;
-    case UO_AddrOf:
-      resultType = CheckAddressOfOperand(Input, OpLoc);
-      CheckAddressOfNoDeref(InputExpr);
-      RecordModifiableNonNullParam(*this, InputExpr);
+    if (resultType->isArithmeticType()) // C99 6.5.3.3p1
       break;
-    case UO_Deref: {
-      Input = DefaultFunctionArrayLvalueConversion(Input.get());
-      if (Input.isInvalid())
-        return ExprError();
-      resultType =
-          CheckIndirectionOperand(*this, Input.get(), VK, OpLoc, IsAfterAmp);
+    else if (resultType->isVectorType() &&
+             // The z vector extensions don't allow + or - with bool vectors.
+             (!Context.getLangOpts().ZVector ||
+              resultType->castAs<VectorType>()->getVectorKind() !=
+                  VectorKind::AltiVecBool))
+      break;
+    else if (resultType->isSveVLSBuiltinType()) // SVE vectors allow + and -
+      break;
+    else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6
+             Opc == UO_Plus &&
+             resultType->isPointerType())
       break;
+
+    return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+      << resultType << Input.get()->getSourceRange());
+
+  case UO_Not: // bitwise complement
+    Input = UsualUnaryConversions(Input.get());
+    if (Input.isInvalid())
+      return ExprError();
+    resultType = Input.get()->getType();
+    if (resultType->isDependentType())
+      break;
+    // C99 6.5.3.3p1. We allow complex int and float as a GCC extension.
+    if (resultType->isComplexType() || resultType->isComplexIntegerType())
+      // C99 does not support '~' for complex conjugation.
+      Diag(OpLoc, diag::ext_integer_complement_complex)
+          << resultType << Input.get()->getSourceRange();
+    else if (resultType->hasIntegerRepresentation())
+      break;
+    else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
+      // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
+      // on vector float types.
+      QualType T = resultType->castAs<ExtVectorType>()->getElementType();
+      if (!T->isIntegerType())
+        return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+                          << resultType << Input.get()->getSourceRange());
+    } else {
+      return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+                       << resultType << Input.get()->getSourceRange());
     }
-    case UO_Plus:
-    case UO_Minus:
-      CanOverflow = Opc == UO_Minus &&
-                    isOverflowingIntegerType(Context, Input.get()->getType());
-      Input = UsualUnaryConversions(Input.get());
-      if (Input.isInvalid())
-        return ExprError();
-      // Unary plus and minus require promoting an operand of half vector to a
-      // float vector and truncating the result back to a half vector. For now,
-      // we do this only when HalfArgsAndReturns is set (that is, when the
-      // target is arm or arm64).
-      ConvertHalfVec = needsConversionOfHalfVec(true, Context, Input.get());
-
-      // If the operand is a half vector, promote it to a float vector.
-      if (ConvertHalfVec)
-        Input = convertVector(Input.get(), Context.FloatTy, *this);
-      resultType = Input.get()->getType();
-      if (resultType->isArithmeticType()) // C99 6.5.3.3p1
-        break;
-      else if (resultType->isVectorType() &&
-               // The z vector extensions don't allow + or - with bool vectors.
-               (!Context.getLangOpts().ZVector ||
-                resultType->castAs<VectorType>()->getVectorKind() !=
-                    VectorKind::AltiVecBool))
-        break;
-      else if (resultType->isSveVLSBuiltinType()) // SVE vectors allow + and -
-        break;
-      else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6
-               Opc == UO_Plus && resultType->isPointerType())
-        break;
+    break;
 
+  case UO_LNot: // logical negation
+    // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5).
+    Input = DefaultFunctionArrayLvalueConversion(Input.get());
+    if (Input.isInvalid()) return ExprError();
+    resultType = Input.get()->getType();
+
+    // Though we still have to promote half FP to float...
+    if (resultType->isHalfType() && !Context.getLangOpts().NativeHalfType) {
+      Input = ImpCastExprToType(Input.get(), Context.FloatTy, CK_FloatingCast).get();
+      resultType = Context.FloatTy;
+    }
+
+    // WebAsembly tables can't be used in unary expressions.
+    if (resultType->isPointerType() &&
+        resultType->getPointeeType().isWebAssemblyReferenceType()) {
       return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
                        << resultType << Input.get()->getSourceRange());
+    }
 
-    case UO_Not: // bitwise complement
-      Input = UsualUnaryConversions(Input.get());
-      if (Input.isInvalid())
-        return ExprError();
-      resultType = Input.get()->getType();
-      // C99 6.5.3.3p1. We allow complex int and float as a GCC extension.
-      if (resultType->isComplexType() || resultType->isComplexIntegerType())
-        // C99 does not support '~' for complex conjugation.
-        Diag(OpLoc, diag::ext_integer_complement_complex)
-            << resultType << Input.get()->getSourceRange();
-      else if (resultType->hasIntegerRepresentation())
-        break;
-      else if (resultType->isExtVectorType() && Context.getLangOpts().OpenCL) {
-        // OpenCL v1.1 s6.3.f: The bitwise operator not (~) does not operate
-        // on vector float types.
+    if (resultType->isDependentType())
+      break;
+    if (resultType->isScalarType() && !isScopedEnumerationType(resultType)) {
+      // C99 6.5.3.3p1: ok, fallthrough;
+      if (Context.getLangOpts().CPlusPlus) {
+        // C++03 [expr.unary.op]p8, C++0x [expr.unary.op]p9:
+        // operand contextually converted to bool.
+        Input = ImpCastExprToType(Input.get(), Context.BoolTy,
+                                  ScalarTypeToBooleanCastKind(resultType));
+      } else if (Context.getLangOpts().OpenCL &&
+                 Context.getLangOpts().OpenCLVersion < 120) {
+        // OpenCL v1.1 6.3.h: The logical operator not (!) does not
+        // operate on scalar float types.
+        if (!resultType->isIntegerType() && !resultType->isPointerType())
+          return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+                           << resultType << Input.get()->getSourceRange());
+      }
+    } else if (resultType->isExtVectorType()) {
+      if (Context.getLangOpts().OpenCL &&
+          Context.getLangOpts().getOpenCLCompatibleVersion() < 120) {
+        // OpenCL v1.1 6.3.h: The logical operator not (!) does not
+        // operate on vector float types.
         QualType T = resultType->castAs<ExtVectorType>()->getElementType();
         if (!T->isIntegerType())
           return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
                            << resultType << Input.get()->getSourceRange());
-      } else {
-        return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-                         << resultType << Input.get()->getSourceRange());
       }
+      // Vector logical not returns the signed variant of the operand type.
+      resultType = GetSignedVectorType(resultType);
       break;
-
-    case UO_LNot: // logical negation
-      // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5).
-      Input = DefaultFunctionArrayLvalueConversion(Input.get());
-      if (Input.isInvalid())
-        return ExprError();
-      resultType = Input.get()->getType();
-
-      // Though we still have to promote half FP to float...
-      if (resultType->isHalfType() && !Context.getLangOpts().NativeHalfType) {
-        Input = ImpCastExprToType(Input.get(), Context.FloatTy, CK_FloatingCast)
-                    .get();
-        resultType = Context.FloatTy;
-      }
-
-      // WebAsembly tables can't be used in unary expressions.
-      if (resultType->isPointerType() &&
-          resultType->getPointeeType().isWebAssemblyReferenceType()) {
-        return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-                         << resultType << Input.get()->getSourceRange());
-      }
-
-      if (resultType->isScalarType() && !isScopedEnumerationType(resultType)) {
-        // C99 6.5.3.3p1: ok, fallthrough;
-        if (Context.getLangOpts().CPlusPlus) {
-          // C++03 [expr.unary.op]p8, C++0x [expr.unary.op]p9:
-          // operand contextually converted to bool.
-          Input = ImpCastExprToType(Input.get(), Context.BoolTy,
-                                    ScalarTypeToBooleanCastKind(resultType));
-        } else if (Context.getLangOpts().OpenCL &&
-                   Context.getLangOpts().OpenCLVersion < 120) {
-          // OpenCL v1.1 6.3.h: The logical operator not (!) does not
-          // operate on scalar float types.
-          if (!resultType->isIntegerType() && !resultType->isPointerType())
-            return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-                             << resultType << Input.get()->getSourceRange());
-        }
-      } else if (resultType->isExtVectorType()) {
-        if (Context.getLangOpts().OpenCL &&
-            Context.getLangOpts().getOpenCLCompatibleVersion() < 120) {
-          // OpenCL v1.1 6.3.h: The logical operator not (!) does not
-          // operate on vector float types.
-          QualType T = resultType->castAs<ExtVectorType>()->getElementType();
-          if (!T->isIntegerType())
-            return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-                             << resultType << Input.get()->getSourceRange());
-        }
-        // Vector logical not returns the signed variant of the operand type.
-        resultType = GetSignedVectorType(resultType);
-        break;
-      } else if (Context.getLangOpts().CPlusPlus &&
-                 resultType->isVectorType()) {
-        const VectorType *VTy = resultType->castAs<VectorType>();
-        if (VTy->getVectorKind() != VectorKind::Generic)
-          return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
-                           << resultType << Input.get()->getSourceRange());
-
-        // Vector logical not returns the signed variant of the operand type.
-        resultType = GetSignedVectorType(resultType);
-        break;
-      } else {
+    } else if (Context.getLangOpts().CPlusPlus && resultType->isVectorType()) {
+      const VectorType *VTy = resultType->castAs<VectorType>();
+      if (VTy->getVectorKind() != VectorKind::Generic)
         return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
                          << resultType << Input.get()->getSourceRange());
-      }
 
-      // LNot always has type int. C99 6.5.3.3p5.
-      // In C++, it's bool. C++ 5.3.1p8
-      resultType = Context.getLogicalOperationType();
-      break;
-    case UO_Real:
-    case UO_Imag:
-      resultType = CheckRealImagOperand(*this, Input, OpLoc, Opc == UO_Real);
-      // _Real maps ordinary l-values into ordinary l-values. _Imag maps
-      // ordinary complex l-values to ordinary l-values and all other values to
-      // r-values.
-      if (Input.isInvalid())
-        return ExprError();
-      if (Opc == UO_Real || Input.get()->getType()->isAnyComplexType()) {
-        if (Input.get()->isGLValue() &&
-            Input.get()->getObjectKind() == OK_Ordinary)
-          VK = Input.get()->getValueKind();
-      } else if (!getLangOpts().CPlusPlus) {
-        // In C, a volatile scalar is read by __imag. In C++, it is not.
-        Input = DefaultLvalueConversion(Input.get());
-      }
-      break;
-    case UO_Extension:
-      resultType = Input.get()->getType();
-      VK = Input.get()->getValueKind();
-      OK = Input.get()->getObjectKind();
+      // Vector logical not returns the signed variant of the operand type.
+      resultType = GetSignedVectorType(resultType);
       break;
-    case UO_Coawait:
-      // It's unnecessary to represent the pass-through operator co_await in the
-      // AST; just return the input expression instead.
-      assert(!Input.get()->getType()->isDependentType() &&
-             "the co_await expression must be non-dependant before "
-             "building operator co_await");
-      return Input;
+    } else {
+      return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
+        << resultType << Input.get()->getSourceRange());
     }
+
+    // LNot always has type int. C99 6.5.3.3p5.
+    // In C++, it's bool. C++ 5.3.1p8
+    resultType = Context.getLogicalOperationType();
+    break;
+  case UO_Real:
+  case UO_Imag:
+    resultType = CheckRealImagOperand(*this, Input, OpLoc, Opc == UO_Real);
+    // _Real maps ordinary l-values into ordinary l-values. _Imag maps ordinary
+    // complex l-values to ordinary l-values and all other values to r-values.
+    if (Input.isInvalid()) return ExprError();
+    if (Opc == UO_Real || Input.get()->getType()->isAnyComplexType()) {
+      if (Input.get()->isGLValue() &&
+          Input.get()->getObjectKind() == OK_Ordinary)
+        VK = Input.get()->getValueKind();
+    } else if (!getLangOpts().CPlusPlus) {
+      // In C, a volatile scalar is read by __imag. In C++, it is not.
+      Inp...
[truncated]

``````````

</details>


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


More information about the cfe-commits mailing list