https://github.com/sdkrystian created https://github.com/llvm/llvm-project/pull/92149
This reverts commit 8019cbbbbc94658d133583f7be6cd0023d30b0f3. >From a55eb47a72fd6b5d703e7c20e2cbf5b2aa7fd78d Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Tue, 14 May 2024 13:17:29 -0400 Subject: [PATCH] Revert "[Clang][Sema] Earlier type checking for builtin unary operators (#90500)" This reverts commit 8019cbbbbc94658d133583f7be6cd0023d30b0f3. --- clang/docs/ReleaseNotes.rst | 3 - clang/include/clang/AST/Type.h | 5 +- clang/lib/Sema/SemaExpr.cpp | 354 +++++++++--------- clang/test/AST/ast-dump-expr-json.cpp | 4 +- clang/test/AST/ast-dump-expr.cpp | 2 +- clang/test/AST/ast-dump-lambda.cpp | 2 +- .../expr/expr.unary/expr.unary.general/p1.cpp | 65 ---- clang/test/CXX/over/over.built/ast.cpp | 158 ++------ clang/test/CXX/over/over.built/p10.cpp | 2 +- clang/test/CXX/over/over.built/p11.cpp | 2 +- .../temp.res/temp.dep/temp.dep.type/p4.cpp | 25 +- clang/test/Frontend/noderef_templates.cpp | 4 +- clang/test/SemaCXX/cxx2b-deducing-this.cpp | 6 +- .../test/SemaTemplate/class-template-spec.cpp | 12 +- .../ASTMatchers/ASTMatchersNarrowingTest.cpp | 6 +- 15 files changed, 246 insertions(+), 404 deletions(-) delete mode 100644 clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp 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. + Input = DefaultLvalueConversion(Input.get()); + } + break; + case UO_Extension: + resultType = Input.get()->getType(); + VK = Input.get()->getValueKind(); + OK = Input.get()->getObjectKind(); + 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; } if (resultType.isNull() || Input.isInvalid()) return ExprError(); diff --git a/clang/test/AST/ast-dump-expr-json.cpp b/clang/test/AST/ast-dump-expr-json.cpp index 4b7365e554cb7..0fb07b0b434cc 100644 --- a/clang/test/AST/ast-dump-expr-json.cpp +++ b/clang/test/AST/ast-dump-expr-json.cpp @@ -4261,9 +4261,9 @@ void TestNonADLCall3() { // CHECK-NEXT: } // CHECK-NEXT: }, // CHECK-NEXT: "type": { -// CHECK-NEXT: "qualType": "V" +// CHECK-NEXT: "qualType": "<dependent type>" // CHECK-NEXT: }, -// CHECK-NEXT: "valueCategory": "lvalue", +// CHECK-NEXT: "valueCategory": "prvalue", // CHECK-NEXT: "isPostfix": false, // CHECK-NEXT: "opcode": "*", // CHECK-NEXT: "canOverflow": false, diff --git a/clang/test/AST/ast-dump-expr.cpp b/clang/test/AST/ast-dump-expr.cpp index 4df5ba4276abd..69e65e22d61d0 100644 --- a/clang/test/AST/ast-dump-expr.cpp +++ b/clang/test/AST/ast-dump-expr.cpp @@ -282,7 +282,7 @@ void PrimaryExpressions(Ts... a) { // CHECK-NEXT: CompoundStmt // CHECK-NEXT: FieldDecl 0x{{[^ ]*}} <col:8> col:8 implicit 'V' // CHECK-NEXT: ParenListExpr 0x{{[^ ]*}} <col:8> 'NULL TYPE' - // CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} <col:8> 'V' lvalue prefix '*' cannot overflow + // CHECK-NEXT: UnaryOperator 0x{{[^ ]*}} <col:8> '<dependent type>' prefix '*' cannot overflow // CHECK-NEXT: CXXThisExpr 0x{{[^ ]*}} <col:8> 'V *' this } }; diff --git a/clang/test/AST/ast-dump-lambda.cpp b/clang/test/AST/ast-dump-lambda.cpp index a4d3fe4fbda57..ef8789cd97d3e 100644 --- a/clang/test/AST/ast-dump-lambda.cpp +++ b/clang/test/AST/ast-dump-lambda.cpp @@ -81,7 +81,7 @@ template <typename... Ts> void test(Ts... a) { // CHECK-NEXT: | | | `-CompoundStmt {{.*}} <col:15, col:16> // CHECK-NEXT: | | `-FieldDecl {{.*}} <col:8> col:8{{( imported)?}} implicit 'V' // CHECK-NEXT: | |-ParenListExpr {{.*}} <col:8> 'NULL TYPE' -// CHECK-NEXT: | | `-UnaryOperator {{.*}} <col:8> 'V' lvalue prefix '*' cannot overflow +// CHECK-NEXT: | | `-UnaryOperator {{.*}} <col:8> '<dependent type>' prefix '*' cannot overflow // CHECK-NEXT: | | `-CXXThisExpr {{.*}} <col:8> 'V *' this // CHECK-NEXT: | `-CompoundStmt {{.*}} <col:15, col:16> // CHECK-NEXT: |-DeclStmt {{.*}} <line:22:3, col:11> diff --git a/clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp b/clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp deleted file mode 100644 index 6744ce1cad174..0000000000000 --- a/clang/test/CXX/expr/expr.unary/expr.unary.general/p1.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// RUN: %clang_cc1 -Wno-unused -fsyntax-only %s -verify - -struct A { - void operator*(); - void operator+(); - void operator-(); - void operator!(); - void operator~(); - void operator&(); - void operator++(); - void operator--(); -}; - -struct B { }; - -template<typename T, typename U> -void dependent(T t, T* pt, T U::* mpt, T(&ft)(), T(&at)[4]) { - *t; - +t; - -t; - !t; - ~t; - &t; - ++t; - --t; - - *pt; - +pt; - -pt; // expected-error {{invalid argument type 'T *' to unary expression}} - !pt; - ~pt; // expected-error {{invalid argument type 'T *' to unary expression}} - &pt; - ++pt; - --pt; - - *mpt; // expected-error {{indirection requires pointer operand ('T U::*' invalid)}} - +mpt; // expected-error {{invalid argument type 'T U::*' to unary expression}} - -mpt; // expected-error {{invalid argument type 'T U::*' to unary expression}} - !mpt; - ~mpt; // expected-error {{invalid argument type 'T U::*' to unary expression}} - &mpt; - ++mpt; // expected-error {{cannot increment value of type 'T U::*'}} - --mpt; // expected-error {{cannot decrement value of type 'T U::*'}} - - *ft; - +ft; - -ft; // expected-error {{invalid argument type 'T (*)()' to unary expression}} - !ft; - ~ft; // expected-error {{invalid argument type 'T (*)()' to unary expression}} - &ft; - ++ft; // expected-error {{cannot increment value of type 'T ()'}} - --ft; // expected-error {{cannot decrement value of type 'T ()'}} - - *at; - +at; - -at; // expected-error {{invalid argument type 'T *' to unary expression}} - !at; - ~at; // expected-error {{invalid argument type 'T *' to unary expression}} - &at; - ++at; // expected-error {{cannot increment value of type 'T[4]'}} - --at; // expected-error {{cannot decrement value of type 'T[4]'}} -} - -// Make sure we only emit diagnostics once. -template void dependent(A t, A* pt, A B::* mpt, A(&ft)(), A(&at)[4]); diff --git a/clang/test/CXX/over/over.built/ast.cpp b/clang/test/CXX/over/over.built/ast.cpp index 78f86edb1e961..56a63431269f3 100644 --- a/clang/test/CXX/over/over.built/ast.cpp +++ b/clang/test/CXX/over/over.built/ast.cpp @@ -1,139 +1,41 @@ -// RUN: %clang_cc1 -std=c++17 -Wno-unused -ast-dump %s -ast-dump-filter Test | FileCheck %s +// RUN: %clang_cc1 -std=c++17 -ast-dump %s -ast-dump-filter Test | FileCheck %s -namespace Test { - template<typename T, typename U> - void Unary(T t, T* pt, T U::* mpt, T(&ft)(), T(&at)[4]) { - // CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '*' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T' - *t; +struct A{}; - // CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '+' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T' - +t; +template <typename T, typename U> +auto Test(T* pt, U* pu) { + // CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '*' + // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + (void)*pt; - // CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '-' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T' - -t; + // CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '++' + // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + (void)(++pt); - // CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '!' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T' - !t; + // CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '+' + // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + (void)(+pt); - // CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '~' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T' - ~t; + // CHECK: BinaryOperator {{.*}} '<dependent type>' '+' + // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + // CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3 + (void)(pt + 3); - // CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T' - &t; + // CHECK: BinaryOperator {{.*}} '<dependent type>' '-' + // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + (void)(pt - pt); - // CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '++' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T' - ++t; + // CHECK: BinaryOperator {{.*}} '<dependent type>' '-' + // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + // CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *' + (void)(pt - pu); - // CHECK: UnaryOperator {{.*}} '<dependent type>' lvalue prefix '--' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T' lvalue ParmVar {{.*}} 't' 'T' - --t; + // CHECK: BinaryOperator {{.*}} '<dependent type>' '==' + // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' + // CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *' + (void)(pt == pu); - // CHECK: UnaryOperator {{.*}} 'T' lvalue prefix '*' cannot overflow - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue> - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - *pt; +} - // CHECK: UnaryOperator {{.*}} 'T *' prefix '+' cannot overflow - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue> - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - +pt; - // CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <PointerToBoolean> - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <LValueToRValue> - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - !pt; - - // CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - &pt; - - // CHECK: UnaryOperator {{.*}} 'T *' lvalue prefix '++' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - ++pt; - - // CHECK: UnaryOperator {{.*}} 'T *' lvalue prefix '--' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - --pt; - - // CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <MemberPointerToBoolean> - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T U::*' <LValueToRValue> - // CHECK-NEXT: DeclRefExpr {{.*}} 'T U::*' lvalue ParmVar {{.*}} 'mpt' 'T U::*' - !mpt; - - // CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T U::*' lvalue ParmVar {{.*}} 'mpt' 'T U::*' - &mpt; - - // CHECK: UnaryOperator {{.*}} 'T ()' lvalue prefix '*' cannot overflow - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T (*)()' <FunctionToPointerDecay> - // CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()' - *ft; - - // CHECK: UnaryOperator {{.*}} 'T (*)()' prefix '+' cannot overflow - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T (*)()' <FunctionToPointerDecay> - // CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()' - +ft; - - // CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <PointerToBoolean> - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T (*)()' <FunctionToPointerDecay> - // CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()' - !ft; - - // CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T ()' lvalue ParmVar {{.*}} 'ft' 'T (&)()' - &ft; - - // CHECK: UnaryOperator {{.*}} 'T' lvalue prefix '*' cannot overflow - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <ArrayToPointerDecay> - // CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]' - *at; - - // CHECK: UnaryOperator {{.*}} 'T *' prefix '+' cannot overflow - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <ArrayToPointerDecay> - // CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]' - +at; - - // CHECK: UnaryOperator {{.*}} 'bool' prefix '!' cannot overflow - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'bool' <PointerToBoolean> - // CHECK-NEXT: ImplicitCastExpr {{.*}} 'T *' <ArrayToPointerDecay> - // CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]' - !at; - - // CHECK: UnaryOperator {{.*}} '<dependent type>' prefix '&' cannot overflow - // CHECK-NEXT: DeclRefExpr {{.*}} 'T[4]' lvalue ParmVar {{.*}} 'at' 'T (&)[4]' - &at; - } - - template<typename T, typename U> - void Binary(T* pt, U* pu) { - // CHECK: BinaryOperator {{.*}} '<dependent type>' '+' - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - // CHECK-NEXT: IntegerLiteral {{.*}} 'int' 3 - pt + 3; - - // CHECK: BinaryOperator {{.*}} '<dependent type>' '-' - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - pt - pt; - - // CHECK: BinaryOperator {{.*}} '<dependent type>' '-' - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - // CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *' - pt - pu; - - // CHECK: BinaryOperator {{.*}} '<dependent type>' '==' - // CHECK-NEXT: DeclRefExpr {{.*}} 'T *' lvalue ParmVar {{.*}} 'pt' 'T *' - // CHECK-NEXT: DeclRefExpr {{.*}} 'U *' lvalue ParmVar {{.*}} 'pu' 'U *' - pt == pu; - } -} // namespace Test diff --git a/clang/test/CXX/over/over.built/p10.cpp b/clang/test/CXX/over/over.built/p10.cpp index 8ff2396d0b6f9..678056da58205 100644 --- a/clang/test/CXX/over/over.built/p10.cpp +++ b/clang/test/CXX/over/over.built/p10.cpp @@ -15,6 +15,6 @@ void f(int i, float f, bool b, char c, int* pi, A* pa, T* pt) { (void)-pi; // expected-error {{invalid argument type}} (void)-pa; // expected-error {{invalid argument type}} - (void)-pt; // expected-error {{invalid argument type}} + (void)-pt; // FIXME: we should be able to give an error here. } diff --git a/clang/test/CXX/over/over.built/p11.cpp b/clang/test/CXX/over/over.built/p11.cpp index f7a741db726de..7ebf16b95439f 100644 --- a/clang/test/CXX/over/over.built/p11.cpp +++ b/clang/test/CXX/over/over.built/p11.cpp @@ -7,6 +7,6 @@ void f(int i, float f, bool b, char c, int* pi, T* pt) { (void)~b; (void)~c; (void)~pi; // expected-error {{invalid argument type}} - (void)~pt; // expected-error {{invalid argument type}} + (void)~pt; // FIXME: we should be able to give an error here. } diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp index 982e5372f5b0c..3ca7c6c7eb8ee 100644 --- a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp +++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p4.cpp @@ -357,14 +357,17 @@ namespace N0 { a->A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}} a->B::A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}} - (*this).x4; // expected-error{{no member named 'x4' in 'B<T>'}} - (*this).B::x4; // expected-error{{no member named 'x4' in 'B<T>'}} - (*this).A::x4; // expected-error{{no member named 'x4' in 'N0::A'}} - (*this).B::A::x4; // expected-error{{no member named 'x4' in 'N0::A'}} - (*this).f4(); // expected-error{{no member named 'f4' in 'B<T>'}} - (*this).B::f4(); // expected-error{{no member named 'f4' in 'B<T>'}} - (*this).A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}} - (*this).B::A::f4(); // expected-error{{no member named 'f4' in 'N0::A'}} + // FIXME: An overloaded unary 'operator*' is built for these + // even though the operand is a pointer (to a dependent type). + // Type::isOverloadableType should return false for such cases. + (*this).x4; + (*this).B::x4; + (*this).A::x4; + (*this).B::A::x4; + (*this).f4(); + (*this).B::f4(); + (*this).A::f4(); + (*this).B::A::f4(); b.x4; // expected-error{{no member named 'x4' in 'B<T>'}} b.B::x4; // expected-error{{no member named 'x4' in 'B<T>'}} @@ -396,13 +399,15 @@ namespace N1 { f<0>(); this->f<0>(); a->f<0>(); - (*this).f<0>(); + // FIXME: This should not require 'template'! + (*this).f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}} b.f<0>(); x.f<0>(); this->x.f<0>(); a->x.f<0>(); - (*this).x.f<0>(); + // FIXME: This should not require 'template'! + (*this).x.f<0>(); // expected-error{{missing 'template' keyword prior to dependent template name 'f'}} b.x.f<0>(); // FIXME: None of these should require 'template'! diff --git a/clang/test/Frontend/noderef_templates.cpp b/clang/test/Frontend/noderef_templates.cpp index 9e54cd5d78899..5fde6efd87c7f 100644 --- a/clang/test/Frontend/noderef_templates.cpp +++ b/clang/test/Frontend/noderef_templates.cpp @@ -3,8 +3,8 @@ #define NODEREF __attribute__((noderef)) template <typename T> -int func(T NODEREF *a) { // expected-note 3 {{a declared here}} - return *a + 1; // expected-warning 3 {{dereferencing a; was declared with a 'noderef' type}} +int func(T NODEREF *a) { // expected-note 2 {{a declared here}} + return *a + 1; // expected-warning 2 {{dereferencing a; was declared with a 'noderef' type}} } void func() { diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index aa64530bd5be3..5f29a955e053c 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -19,7 +19,7 @@ struct S { // new and delete are implicitly static void *operator new(this unsigned long); // expected-error{{an explicit object parameter cannot appear in a static function}} void operator delete(this void*); // expected-error{{an explicit object parameter cannot appear in a static function}} - + void g(this auto) const; // expected-error{{explicit object member function cannot have 'const' qualifier}} void h(this auto) &; // expected-error{{explicit object member function cannot have '&' qualifier}} void i(this auto) &&; // expected-error{{explicit object member function cannot have '&&' qualifier}} @@ -198,7 +198,9 @@ void func(int i) { void TestMutationInLambda() { [i = 0](this auto &&){ i++; }(); [i = 0](this auto){ i++; }(); - [i = 0](this const auto&){ i++; }(); // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}} + [i = 0](this const auto&){ i++; }(); + // expected-error@-1 {{cannot assign to a variable captured by copy in a non-mutable lambda}} + // expected-note@-2 {{in instantiation of}} int x; const auto l1 = [x](this auto&) { x = 42; }; // expected-error {{cannot assign to a variable captured by copy in a non-mutable lambda}} diff --git a/clang/test/SemaTemplate/class-template-spec.cpp b/clang/test/SemaTemplate/class-template-spec.cpp index faa54c3675383..56b8207bd9a43 100644 --- a/clang/test/SemaTemplate/class-template-spec.cpp +++ b/clang/test/SemaTemplate/class-template-spec.cpp @@ -18,7 +18,7 @@ int test_specs(A<float, float> *a1, A<float, int> *a2) { return a1->x + a2->y; } -int test_incomplete_specs(A<double, double> *a1, +int test_incomplete_specs(A<double, double> *a1, A<double> *a2) { (void)a1->x; // expected-error{{member access into incomplete type}} @@ -39,7 +39,7 @@ template <> struct X<int, int> { int foo(); }; // #1 template <> struct X<float> { int bar(); }; // #2 typedef int int_type; -void testme(X<int_type> *x1, X<float, int> *x2) { +void testme(X<int_type> *x1, X<float, int> *x2) { (void)x1->foo(); // okay: refers to #1 (void)x2->bar(); // okay: refers to #2 } @@ -53,7 +53,7 @@ struct A<char> { A<char>::A() { } // Make sure we can see specializations defined before the primary template. -namespace N{ +namespace N{ template<typename T> struct A0; } @@ -97,7 +97,7 @@ namespace M { template<> struct ::A<long double>; // expected-error{{must occur at global scope}} } -template<> struct N::B<char> { +template<> struct N::B<char> { int testf(int x) { return f(x); } }; @@ -138,9 +138,9 @@ namespace PR18009 { template <typename T> struct C { template <int N, int M> struct S; - template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // ok + template <int N> struct S<N, N ? **(T(*)[N])0 : 0> {}; // expected-error {{depends on a template parameter of the partial specialization}} }; - C<int> c; + C<int> c; // expected-note {{in instantiation of}} template<int A> struct outer { template<int B, int C> struct inner {}; diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index f26140675fd46..c08deb903f129 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1572,9 +1572,9 @@ TEST_P(ASTMatchersTest, IsArrow_MatchesMemberVariablesViaArrow) { EXPECT_TRUE( matches("template <class T> class Y { void x() { this->m; } int m; };", memberExpr(isArrow()))); - EXPECT_TRUE(notMatches( - "template <class T> class Y { void x() { (*this).m; } int m; };", - memberExpr(isArrow()))); + EXPECT_TRUE( + notMatches("template <class T> class Y { void x() { (*this).m; } };", + cxxDependentScopeMemberExpr(isArrow()))); } TEST_P(ASTMatchersTest, IsArrow_MatchesStaticMemberVariablesViaArrow) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits