From e190dee7a5488f6314f74accd266c4abf36c2c4b Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 11 Mar 2011 19:24:49 +0000 Subject: [PATCH] Add support for the OpenCL vec_step operator, by generalising and extending the existing support for sizeof and alignof. Original patch by Guy Benyei. llvm-svn: 127475 --- .../include/clang/AST/EvaluatedExprVisitor.h | 2 +- clang/include/clang/AST/Expr.h | 46 ++++---- clang/include/clang/AST/RecursiveASTVisitor.h | 4 +- .../clang/Basic/DiagnosticSemaKinds.td | 12 +- clang/include/clang/Basic/StmtNodes.td | 2 +- clang/include/clang/Basic/TokenKinds.def | 3 +- clang/include/clang/Basic/TypeTraits.h | 7 ++ clang/include/clang/Parse/Parser.h | 4 +- clang/include/clang/Sema/Sema.h | 24 ++-- .../Core/PathSensitive/ExprEngine.h | 6 +- clang/lib/AST/ASTImporter.cpp | 13 ++- clang/lib/AST/Expr.cpp | 4 +- clang/lib/AST/ExprClassification.cpp | 2 +- clang/lib/AST/ExprConstant.cpp | 77 ++++++++----- clang/lib/AST/ItaniumMangle.cpp | 20 +++- clang/lib/AST/StmtDumper.cpp | 16 ++- clang/lib/AST/StmtPrinter.cpp | 14 ++- clang/lib/AST/StmtProfile.cpp | 4 +- clang/lib/Analysis/CFG.cpp | 12 +- clang/lib/Analysis/UninitializedValuesV2.cpp | 7 +- clang/lib/CodeGen/CGExprScalar.cpp | 9 +- clang/lib/Parse/ParseDecl.cpp | 6 +- clang/lib/Parse/ParseDeclCXX.cpp | 4 +- clang/lib/Parse/ParseExpr.cpp | 69 +++++++----- clang/lib/Rewrite/RewriteObjC.cpp | 9 +- clang/lib/Sema/SemaChecking.cpp | 2 +- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- clang/lib/Sema/SemaExpr.cpp | 103 ++++++++++++------ clang/lib/Sema/TreeTransform.h | 39 ++++--- clang/lib/Serialization/ASTReaderStmt.cpp | 8 +- clang/lib/Serialization/ASTWriterStmt.cpp | 6 +- .../Checkers/CheckSizeofPointer.cpp | 6 +- .../Checkers/IdempotentOperationChecker.cpp | 7 +- .../Checkers/UnreachableCodeChecker.cpp | 2 +- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 29 ++--- clang/test/PCH/exprs.c | 2 +- clang/test/PCH/exprs.h | 2 +- clang/test/SemaOpenCL/vec_step.cl | 32 ++++++ clang/tools/libclang/CIndex.cpp | 5 +- clang/tools/libclang/CXCursor.cpp | 2 +- 40 files changed, 395 insertions(+), 228 deletions(-) create mode 100644 clang/test/SemaOpenCL/vec_step.cl diff --git a/clang/include/clang/AST/EvaluatedExprVisitor.h b/clang/include/clang/AST/EvaluatedExprVisitor.h index 035f57c12ea7..3bc62eda2d06 100644 --- a/clang/include/clang/AST/EvaluatedExprVisitor.h +++ b/clang/include/clang/AST/EvaluatedExprVisitor.h @@ -37,7 +37,7 @@ public: // other sub-expressions). void VisitDeclRefExpr(DeclRefExpr *E) { } void VisitOffsetOfExpr(OffsetOfExpr *E) { } - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { } + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { } void VisitBlockExpr(BlockExpr *E) { } void VisitCXXUuidofExpr(CXXUuidofExpr *E) { } void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { } diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 548568127ab3..4a68e43e0632 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -21,6 +21,7 @@ #include "clang/AST/OperationKinds.h" #include "clang/AST/ASTVector.h" #include "clang/AST/UsuallyTinyPtrVector.h" +#include "clang/Basic/TypeTraits.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallVector.h" @@ -1554,10 +1555,11 @@ public: } }; -/// SizeOfAlignOfExpr - [C99 6.5.3.4] - This is for sizeof/alignof, both of -/// types and expressions. -class SizeOfAlignOfExpr : public Expr { - bool isSizeof : 1; // true if sizeof, false if alignof. +/// UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) +/// expression operand. Used for sizeof/alignof (C99 6.5.3.4) and +/// vec_step (OpenCL 1.1 6.11.12). +class UnaryExprOrTypeTraitExpr : public Expr { + unsigned Kind : 2; bool isType : 1; // true if operand is a type, false if an expression union { TypeSourceInfo *Ty; @@ -1566,36 +1568,38 @@ class SizeOfAlignOfExpr : public Expr { SourceLocation OpLoc, RParenLoc; public: - SizeOfAlignOfExpr(bool issizeof, TypeSourceInfo *TInfo, - QualType resultType, SourceLocation op, - SourceLocation rp) : - Expr(SizeOfAlignOfExprClass, resultType, VK_RValue, OK_Ordinary, + UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, TypeSourceInfo *TInfo, + QualType resultType, SourceLocation op, + SourceLocation rp) : + Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary, false, // Never type-dependent (C++ [temp.dep.expr]p3). // Value-dependent if the argument is type-dependent. TInfo->getType()->isDependentType(), TInfo->getType()->containsUnexpandedParameterPack()), - isSizeof(issizeof), isType(true), OpLoc(op), RParenLoc(rp) { + Kind(ExprKind), isType(true), OpLoc(op), RParenLoc(rp) { Argument.Ty = TInfo; } - SizeOfAlignOfExpr(bool issizeof, Expr *E, - QualType resultType, SourceLocation op, - SourceLocation rp) : - Expr(SizeOfAlignOfExprClass, resultType, VK_RValue, OK_Ordinary, + UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, Expr *E, + QualType resultType, SourceLocation op, + SourceLocation rp) : + Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary, false, // Never type-dependent (C++ [temp.dep.expr]p3). // Value-dependent if the argument is type-dependent. E->isTypeDependent(), E->containsUnexpandedParameterPack()), - isSizeof(issizeof), isType(false), OpLoc(op), RParenLoc(rp) { + Kind(ExprKind), isType(false), OpLoc(op), RParenLoc(rp) { Argument.Ex = E; } /// \brief Construct an empty sizeof/alignof expression. - explicit SizeOfAlignOfExpr(EmptyShell Empty) - : Expr(SizeOfAlignOfExprClass, Empty) { } + explicit UnaryExprOrTypeTraitExpr(EmptyShell Empty) + : Expr(UnaryExprOrTypeTraitExprClass, Empty) { } - bool isSizeOf() const { return isSizeof; } - void setSizeof(bool S) { isSizeof = S; } + UnaryExprOrTypeTrait getKind() const { + return static_cast(Kind); + } + void setKind(UnaryExprOrTypeTrait K) { Kind = K; } bool isArgumentType() const { return isType; } QualType getArgumentType() const { @@ -1610,7 +1614,7 @@ public: return static_cast(Argument.Ex); } const Expr *getArgumentExpr() const { - return const_cast(this)->getArgumentExpr(); + return const_cast(this)->getArgumentExpr(); } void setArgument(Expr *E) { Argument.Ex = E; isType = false; } @@ -1636,9 +1640,9 @@ public: } static bool classof(const Stmt *T) { - return T->getStmtClass() == SizeOfAlignOfExprClass; + return T->getStmtClass() == UnaryExprOrTypeTraitExprClass; } - static bool classof(const SizeOfAlignOfExpr *) { return true; } + static bool classof(const UnaryExprOrTypeTraitExpr *) { return true; } // Iterators child_range children(); diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index e5f5a9c056a9..ba8f6b52afe6 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1787,7 +1787,7 @@ DEF_TRAVERSE_STMT(OffsetOfExpr, { TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); }) -DEF_TRAVERSE_STMT(SizeOfAlignOfExpr, { +DEF_TRAVERSE_STMT(UnaryExprOrTypeTraitExpr, { // The child-iterator will pick up the arg if it's an expression, // but not if it's a type. if (S->isArgumentType()) @@ -1930,7 +1930,7 @@ DEF_TRAVERSE_STMT(ObjCStringLiteral, { }) // Candidates: // // http://clang.llvm.org/doxygen/classclang_1_1CXXTypeidExpr.html -// http://clang.llvm.org/doxygen/classclang_1_1SizeOfAlignOfExpr.html +// http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html // http://clang.llvm.org/doxygen/classclang_1_1TypesCompatibleExpr.html // Every class that has getQualifier. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 982ed25103e2..233113250731 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2343,14 +2343,18 @@ def err_func_def_incomplete_result : Error< def ext_sizeof_function_type : Extension< "invalid application of 'sizeof' to a function type">, InGroup; def err_sizeof_alignof_overloaded_function_type : Error< - "invalid application of '%select{sizeof|__alignof}0' to an overloaded " - "function">; + "invalid application of '%select{sizeof|__alignof|vec_step}0' to an " + "overloaded function">; def ext_sizeof_void_type : Extension< - "invalid application of '%0' to a void type">, InGroup; + "invalid application of '%select{sizeof|__alignof|vec_step}0' to a void " + "type">, InGroup; def err_sizeof_alignof_incomplete_type : Error< - "invalid application of '%select{sizeof|__alignof}0' to an incomplete type %1">; + "invalid application of '%select{sizeof|__alignof|vec_step}0' to an " + "incomplete type %1">; def err_sizeof_alignof_bitfield : Error< "invalid application of '%select{sizeof|__alignof}0' to bit-field">; +def err_vecstep_non_scalar_vector_type : Error< + "'vec_step' requires built-in scalar or vector type, %0 invalid">; def err_offsetof_incomplete_type : Error< "offsetof of incomplete type %0">; def err_offsetof_record_type : Error< diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index be0d8ff091e8..44f6f5393986 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -54,7 +54,7 @@ def CharacterLiteral : DStmt; def ParenExpr : DStmt; def UnaryOperator : DStmt; def OffsetOfExpr : DStmt; -def SizeOfAlignOfExpr : DStmt; +def UnaryExprOrTypeTraitExpr : DStmt; def ArraySubscriptExpr : DStmt; def CallExpr : DStmt; def MemberExpr : DStmt; diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 96a817bdaee6..c7d9524b4146 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -346,9 +346,10 @@ KEYWORD(__fastcall , KEYALL) KEYWORD(__thiscall , KEYALL) KEYWORD(__forceinline , KEYALL) -// OpenCL-specific keywords (see OpenCL 1.1 [6.1.9]) +// OpenCL-specific keywords KEYWORD(__kernel , KEYOPENCL) ALIAS("kernel", __kernel , KEYOPENCL) +KEYWORD(vec_step , KEYOPENCL) // Borland Extensions. KEYWORD(__pascal , KEYALL) diff --git a/clang/include/clang/Basic/TypeTraits.h b/clang/include/clang/Basic/TypeTraits.h index 00c6e9ed5000..16a57a54851f 100644 --- a/clang/include/clang/Basic/TypeTraits.h +++ b/clang/include/clang/Basic/TypeTraits.h @@ -42,6 +42,13 @@ namespace clang { BTT_TypeCompatible, BTT_IsConvertibleTo }; + + /// UnaryExprOrTypeTrait - Names for the "expression or type" traits. + enum UnaryExprOrTypeTrait { + UETT_SizeOf, + UETT_AlignOf, + UETT_VecStep + }; } #endif diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 5d667d9b8ee3..1afc3c94df89 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1041,10 +1041,10 @@ private: } ExprResult ParsePostfixExpressionSuffix(ExprResult LHS); - ExprResult ParseSizeofAlignofExpression(); + ExprResult ParseUnaryExprOrTypeTraitExpression(); ExprResult ParseBuiltinPrimaryExpression(); - ExprResult ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, + ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, bool &isCastExpr, ParsedType &CastTy, SourceRange &CastRange); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5935864f387a..17e9d3d6969b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1990,19 +1990,25 @@ public: ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, Expr *Input); - ExprResult CreateSizeOfAlignOfExpr(TypeSourceInfo *T, - SourceLocation OpLoc, - bool isSizeOf, SourceRange R); - ExprResult CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, - bool isSizeOf, SourceRange R); + ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *T, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R); + ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R); ExprResult - ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, - void *TyOrEx, const SourceRange &ArgRange); + ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + bool isType, void *TyOrEx, + const SourceRange &ArgRange); ExprResult CheckPlaceholderExpr(Expr *E, SourceLocation Loc); + bool CheckVecStepExpr(Expr *E, SourceLocation OpLoc, SourceRange R); - bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc, - SourceRange R, bool isSizeof); + bool CheckUnaryExprOrTypeTraitOperand(QualType type, SourceLocation OpLoc, + SourceRange R, + UnaryExprOrTypeTrait ExprKind); ExprResult ActOnSizeofParameterPackExpr(Scope *S, SourceLocation OpLoc, IdentifierInfo &Name, diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index e5b76d29f6f0..7a562482c266 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -339,9 +339,9 @@ public: void VisitOffsetOfExpr(const OffsetOfExpr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst); - /// VisitSizeOfAlignOfExpr - Transfer function for sizeof. - void VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, ExplodedNode* Pred, - ExplodedNodeSet& Dst); + /// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof. + void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr* Ex, + ExplodedNode* Pred, ExplodedNodeSet& Dst); /// VisitUnaryOperator - Transfer function logic for unary operators. void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode* Pred, diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 357819a6842d..b00c78827f30 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -139,7 +139,7 @@ namespace { Expr *VisitCharacterLiteral(CharacterLiteral *E); Expr *VisitParenExpr(ParenExpr *E); Expr *VisitUnaryOperator(UnaryOperator *E); - Expr *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + Expr *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); Expr *VisitBinaryOperator(BinaryOperator *E); Expr *VisitCompoundAssignOperator(CompoundAssignOperator *E); Expr *VisitImplicitCastExpr(ImplicitCastExpr *E); @@ -3799,7 +3799,8 @@ Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) { Importer.Import(E->getOperatorLoc())); } -Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *E) { QualType ResultType = Importer.Import(E->getType()); if (E->isArgumentType()) { @@ -3807,8 +3808,8 @@ Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (!TInfo) return 0; - return new (Importer.getToContext()) SizeOfAlignOfExpr(E->isSizeOf(), - TInfo, ResultType, + return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(), + TInfo, ResultType, Importer.Import(E->getOperatorLoc()), Importer.Import(E->getRParenLoc())); } @@ -3817,8 +3818,8 @@ Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (!SubExpr) return 0; - return new (Importer.getToContext()) SizeOfAlignOfExpr(E->isSizeOf(), - SubExpr, ResultType, + return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(), + SubExpr, ResultType, Importer.Import(E->getOperatorLoc()), Importer.Import(E->getRParenLoc())); } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 99ce6113945c..4793b114ef47 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2854,8 +2854,8 @@ const Expr* ConstExprIterator::operator->() const { return cast(*I); } // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// -// SizeOfAlignOfExpr -Stmt::child_range SizeOfAlignOfExpr::children() { +// UnaryExprOrTypeTraitExpr +Stmt::child_range UnaryExprOrTypeTraitExpr::children() { // If this is of a type and the type is a VLA type (and not a typedef), the // size expression of the VLA needs to be treated as an executable expression. // Why isn't this weirdness documented better in StmtIterator? diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp index 890898a985e8..376792223ad7 100644 --- a/clang/lib/AST/ExprClassification.cpp +++ b/clang/lib/AST/ExprClassification.cpp @@ -128,7 +128,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // Expressions that are prvalues. case Expr::CXXBoolLiteralExprClass: case Expr::CXXPseudoDestructorExprClass: - case Expr::SizeOfAlignOfExprClass: + case Expr::UnaryExprOrTypeTraitExprClass: case Expr::CXXNewExprClass: case Expr::CXXThisExprClass: case Expr::CXXNullPtrLiteralExprClass: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index f421671f7fea..b6ab33258d83 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -290,7 +290,8 @@ public: bool VisitFloatingLiteral(FloatingLiteral *E) { return false; } bool VisitStringLiteral(StringLiteral *E) { return false; } bool VisitCharacterLiteral(CharacterLiteral *E) { return false; } - bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return false; } + bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) + { return false; } bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) { return Visit(E->getLHS()) || Visit(E->getRHS()); } bool VisitChooseExpr(ChooseExpr *E) @@ -1020,7 +1021,7 @@ public: bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E); bool VisitCastExpr(CastExpr* E); - bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); + bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return Success(E->getValue(), E); @@ -1601,36 +1602,59 @@ CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) { } -/// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the -/// expression's type. -bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { - // Handle alignof separately. - if (!E->isSizeOf()) { +/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with +/// a result as the expression's type. +bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( + const UnaryExprOrTypeTraitExpr *E) { + switch(E->getKind()) { + case UETT_AlignOf: { if (E->isArgumentType()) return Success(GetAlignOfType(E->getArgumentType()), E); else return Success(GetAlignOfExpr(E->getArgumentExpr()), E); } - QualType SrcTy = E->getTypeOfArgument(); - // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, - // the result is the size of the referenced type." - // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the - // result shall be the alignment of the referenced type." - if (const ReferenceType *Ref = SrcTy->getAs()) - SrcTy = Ref->getPointeeType(); + case UETT_VecStep: { + QualType Ty = E->getTypeOfArgument(); - // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc - // extension. - if (SrcTy->isVoidType() || SrcTy->isFunctionType()) - return Success(1, E); + if (Ty->isVectorType()) { + unsigned n = Ty->getAs()->getNumElements(); - // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. - if (!SrcTy->isConstantSizeType()) - return false; + // The vec_step built-in functions that take a 3-component + // vector return 4. (OpenCL 1.1 spec 6.11.12) + if (n == 3) + n = 4; - // Get information about the size. - return Success(Info.Ctx.getTypeSizeInChars(SrcTy), E); + return Success(n, E); + } else + return Success(1, E); + } + + case UETT_SizeOf: { + QualType SrcTy = E->getTypeOfArgument(); + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = SrcTy->getAs()) + SrcTy = Ref->getPointeeType(); + + // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc + // extension. + if (SrcTy->isVoidType() || SrcTy->isFunctionType()) + return Success(1, E); + + // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. + if (!SrcTy->isConstantSizeType()) + return false; + + // Get information about the size. + return Success(Info.Ctx.getTypeSizeInChars(SrcTy), E); + } + } + + llvm_unreachable("unknown expr/type trait"); + return false; } bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { @@ -2884,9 +2908,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // are ICEs, the value of the offsetof must be an integer constant. return CheckEvalInICE(E, Ctx); } - case Expr::SizeOfAlignOfExprClass: { - const SizeOfAlignOfExpr *Exp = cast(E); - if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType()) + case Expr::UnaryExprOrTypeTraitExprClass: { + const UnaryExprOrTypeTraitExpr *Exp = cast(E); + if ((Exp->getKind() == UETT_SizeOf) && + Exp->getTypeOfArgument()->isVariableArrayType()) return ICEDiag(2, E->getLocStart()); return NoDiag(); } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 45653e6e7d60..bceed0813789 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1888,10 +1888,22 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { break; } - case Expr::SizeOfAlignOfExprClass: { - const SizeOfAlignOfExpr *SAE = cast(E); - if (SAE->isSizeOf()) Out << 's'; - else Out << 'a'; + case Expr::UnaryExprOrTypeTraitExprClass: { + const UnaryExprOrTypeTraitExpr *SAE = cast(E); + switch(SAE->getKind()) { + case UETT_SizeOf: + Out << 's'; + break; + case UETT_AlignOf: + Out << 'a'; + break; + case UETT_VecStep: + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot yet mangle vec_step expression"); + Diags.Report(DiagID); + return; + } if (SAE->isArgumentType()) { Out << 't'; mangleType(SAE->getArgumentType()); diff --git a/clang/lib/AST/StmtDumper.cpp b/clang/lib/AST/StmtDumper.cpp index 5c7dbb3ed990..21ed8489677b 100644 --- a/clang/lib/AST/StmtDumper.cpp +++ b/clang/lib/AST/StmtDumper.cpp @@ -141,7 +141,7 @@ namespace { void VisitFloatingLiteral(FloatingLiteral *Node); void VisitStringLiteral(StringLiteral *Str); void VisitUnaryOperator(UnaryOperator *Node); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node); void VisitMemberExpr(MemberExpr *Node); void VisitExtVectorElementExpr(ExtVectorElementExpr *Node); void VisitBinaryOperator(BinaryOperator *Node); @@ -441,9 +441,19 @@ void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) { OS << " " << (Node->isPostfix() ? "postfix" : "prefix") << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; } -void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { +void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) { DumpExpr(Node); - OS << " " << (Node->isSizeOf() ? "sizeof" : "alignof") << " "; + switch(Node->getKind()) { + case UETT_SizeOf: + OS << " sizeof "; + break; + case UETT_AlignOf: + OS << " __alignof "; + break; + case UETT_VecStep: + OS << " vec_step "; + break; + } if (Node->isArgumentType()) DumpType(Node->getArgumentType()); } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 1cdd22088141..4f500441166d 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -706,8 +706,18 @@ void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) { OS << ")"; } -void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { - OS << (Node->isSizeOf() ? "sizeof" : "__alignof"); +void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){ + switch(Node->getKind()) { + case UETT_SizeOf: + OS << "sizeof"; + break; + case UETT_AlignOf: + OS << "__alignof"; + break; + case UETT_VecStep: + OS << "vec_step"; + break; + } if (Node->isArgumentType()) OS << "(" << Node->getArgumentType().getAsString(Policy) << ")"; else { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index b54001167b42..a506d055b305 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -290,9 +290,9 @@ void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) { VisitExpr(S); } -void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) { +void StmtProfiler::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *S) { VisitExpr(S); - ID.AddBoolean(S->isSizeOf()); + ID.AddInteger(S->getKind()); if (S->isArgumentType()) VisitType(S->getArgumentType()); } diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index fa054f66e2e8..ca7469f67744 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -343,7 +343,8 @@ private: CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S); CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); CFGBlock *VisitReturnStmt(ReturnStmt* R); - CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, AddStmtChoice asc); + CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, + AddStmtChoice asc); CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc); CFGBlock *VisitSwitchStmt(SwitchStmt *S); CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc); @@ -951,8 +952,9 @@ tryAgain: case Stmt::ReturnStmtClass: return VisitReturnStmt(cast(S)); - case Stmt::SizeOfAlignOfExprClass: - return VisitSizeOfAlignOfExpr(cast(S), asc); + case Stmt::UnaryExprOrTypeTraitExprClass: + return VisitUnaryExprOrTypeTraitExpr(cast(S), + asc); case Stmt::StmtExprClass: return VisitStmtExpr(cast(S), asc); @@ -2148,8 +2150,8 @@ CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) { return Block; } -CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, - AddStmtChoice asc) { +CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, + AddStmtChoice asc) { if (asc.alwaysAdd(*this, E)) { autoCreateBlock(); diff --git a/clang/lib/Analysis/UninitializedValuesV2.cpp b/clang/lib/Analysis/UninitializedValuesV2.cpp index 0d0bc36db364..966ec9ce06d5 100644 --- a/clang/lib/Analysis/UninitializedValuesV2.cpp +++ b/clang/lib/Analysis/UninitializedValuesV2.cpp @@ -324,7 +324,7 @@ public: void VisitUnaryOperator(UnaryOperator *uo); void VisitBinaryOperator(BinaryOperator *bo); void VisitCastExpr(CastExpr *ce); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *se); void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs); bool isTrackedVar(const VarDecl *vd) { @@ -516,8 +516,9 @@ void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) { Visit(ce->getSubExpr()); } -void TransferFunctions::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se) { - if (se->isSizeOf()) { +void TransferFunctions::VisitUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *se) { + if (se->getKind() == UETT_SizeOf) { if (se->getType()->isConstantSizeType()) return; // Handle VLAs. diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index c442f10b866f..8326dcc7a8d1 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -184,7 +184,7 @@ public: return EmitNullValue(E->getType()); } Value *VisitOffsetOfExpr(OffsetOfExpr *E); - Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); + Value *VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel()); return Builder.CreateBitCast(V, ConvertType(E->getType())); @@ -1516,12 +1516,13 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { return Result; } -/// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of +/// VisitUnaryExprOrTypeTraitExpr - Return the size or alignment of the type of /// argument of the sizeof expression as an integer. Value * -ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { +ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr( + const UnaryExprOrTypeTraitExpr *E) { QualType TypeToSize = E->getTypeOfArgument(); - if (E->isSizeOf()) { + if (E->getKind() == UETT_SizeOf) { if (const VariableArrayType *VAT = CGF.getContext().getAsVariableArrayType(TypeToSize)) { if (E->isArgumentType()) { diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7fd49838c859..fc5fb33e8413 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3660,10 +3660,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { bool isCastExpr; ParsedType CastTy; SourceRange CastRange; - ExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, - isCastExpr, - CastTy, - CastRange); + ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, + CastTy, CastRange); if (hasParens) DS.setTypeofParensRange(CastRange); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index c214610f6442..7b11e92d97d0 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2371,8 +2371,8 @@ ExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { SourceLocation TypeLoc = Tok.getLocation(); ParsedType Ty = ParseTypeName().get(); SourceRange TypeRange(Start, Tok.getLocation()); - return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, - Ty.getAsOpaquePtr(), TypeRange); + return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, + Ty.getAsOpaquePtr(), TypeRange); } else return ParseConstantExpression(); } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index ab74d5160d95..7cb955134a4f 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -788,7 +788,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___alignof: // unary-expression: '__alignof' unary-expression // unary-expression: '__alignof' '(' type-name ')' // unary-expression: 'alignof' '(' type-id ')' - return ParseSizeofAlignofExpression(); + case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression + return ParseUnaryExprOrTypeTraitExpression(); case tok::ampamp: { // unary-expression: '&&' identifier SourceLocation AmpAmpLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) @@ -1256,10 +1257,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } } -/// ParseExprAfterTypeofSizeofAlignof - We parsed a typeof/sizeof/alignof and -/// we are at the start of an expression or a parenthesized type-id. -/// OpTok is the operand token (typeof/sizeof/alignof). Returns the expression -/// (isCastExpr == false) or the type (isCastExpr == true). +/// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/ +/// vec_step and we are at the start of an expression or a parenthesized +/// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the +/// expression (isCastExpr == false) or the type (isCastExpr == true). /// /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression @@ -1273,15 +1274,20 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression /// +/// [OpenCL 1.1 6.11.12] vec_step built-in function: +/// vec_step ( expressions ) +/// vec_step ( type-name ) +/// ExprResult -Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, - bool &isCastExpr, - ParsedType &CastTy, - SourceRange &CastRange) { +Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, + bool &isCastExpr, + ParsedType &CastTy, + SourceRange &CastRange) { assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) || - OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof)) && - "Not a typeof/sizeof/alignof expression!"); + OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof) || + OpTok.is(tok::kw_vec_step)) && + "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; @@ -1345,7 +1351,7 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, } -/// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression. +/// ParseUnaryExprOrTypeTraitExpression - Parse a sizeof or alignof expression. /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' @@ -1353,10 +1359,10 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' -ExprResult Parser::ParseSizeofAlignofExpression() { +ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) - || Tok.is(tok::kw_alignof)) && - "Not a sizeof/alignof expression!"); + || Tok.is(tok::kw_alignof) || Tok.is(tok::kw_vec_step)) && + "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); @@ -1403,24 +1409,31 @@ ExprResult Parser::ParseSizeofAlignofExpression() { bool isCastExpr; ParsedType CastTy; SourceRange CastRange; - ExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, - isCastExpr, - CastTy, - CastRange); + ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, + isCastExpr, + CastTy, + CastRange); + + UnaryExprOrTypeTrait ExprKind = UETT_SizeOf; + if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw___alignof)) + ExprKind = UETT_AlignOf; + else if (OpTok.is(tok::kw_vec_step)) + ExprKind = UETT_VecStep; if (isCastExpr) - return Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(), - OpTok.is(tok::kw_sizeof), - /*isType=*/true, - CastTy.getAsOpaquePtr(), - CastRange); + return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), + ExprKind, + /*isType=*/true, + CastTy.getAsOpaquePtr(), + CastRange); // If we get here, the operand to the sizeof/alignof was an expresion. if (!Operand.isInvalid()) - Operand = Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(), - OpTok.is(tok::kw_sizeof), - /*isType=*/false, - Operand.release(), CastRange); + Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), + ExprKind, + /*isType=*/false, + Operand.release(), + CastRange); return move(Operand); } diff --git a/clang/lib/Rewrite/RewriteObjC.cpp b/clang/lib/Rewrite/RewriteObjC.cpp index bd91b9be4d4f..36ae3953f356 100644 --- a/clang/lib/Rewrite/RewriteObjC.cpp +++ b/clang/lib/Rewrite/RewriteObjC.cpp @@ -3116,10 +3116,11 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, SourceLocation()); // Build sizeof(returnType) - SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, - Context->getTrivialTypeSourceInfo(returnType), - Context->getSizeType(), - SourceLocation(), SourceLocation()); + UnaryExprOrTypeTraitExpr *sizeofExpr = + new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf, + Context->getTrivialTypeSourceInfo(returnType), + Context->getSizeType(), SourceLocation(), + SourceLocation()); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases. // For X86 it is more complicated and some kind of target specific routine diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 10773309a3bf..4cdbf5375e6f 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3038,7 +3038,7 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { if (isa(E)) return; // Don't descend into unevaluated contexts. - if (isa(E)) return; + if (isa(E)) return; // Now just recurse over the expression's children. CC = E->getExprLoc(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 186f23d73fe8..a72c75b337ff 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -1362,7 +1362,7 @@ static bool InitExprContainsUninitializedFields(const Stmt *S, *L = ME->getMemberLoc(); return true; } - } else if (isa(S)) { + } else if (isa(S)) { // sizeof/alignof doesn't reference contents, do not warn. return false; } else if (const UnaryOperator *UOE = dyn_cast(S)) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 9cff0f58f476..7dee50257d5a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2711,10 +2711,10 @@ ExprResult Sema::ActOnParenExpr(SourceLocation L, /// The UsualUnaryConversions() function is *not* called by this routine. /// See C99 6.3.2.1p[2-4] for more details. -bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, - SourceLocation OpLoc, - SourceRange ExprRange, - bool isSizeof) { +bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType, + SourceLocation OpLoc, + SourceRange ExprRange, + UnaryExprOrTypeTrait ExprKind) { if (exprType->isDependentType()) return false; @@ -2725,30 +2725,47 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, if (const ReferenceType *Ref = exprType->getAs()) exprType = Ref->getPointeeType(); + // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in + // scalar or vector data type argument..." + // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic + // type (C99 6.2.5p18) or void. + if (ExprKind == UETT_VecStep) { + if (!(exprType->isArithmeticType() || exprType->isVoidType() || + exprType->isVectorType())) { + Diag(OpLoc, diag::err_vecstep_non_scalar_vector_type) + << exprType << ExprRange; + return true; + } + } + // C99 6.5.3.4p1: if (exprType->isFunctionType()) { // alignof(function) is allowed as an extension. - if (isSizeof) - Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange; + if (ExprKind == UETT_SizeOf) + Diag(OpLoc, diag::ext_sizeof_function_type) + << ExprRange; return false; } - // Allow sizeof(void)/alignof(void) as an extension. + // Allow sizeof(void)/alignof(void) as an extension. vec_step(void) is not + // an extension, as void is a built-in scalar type (OpenCL 1.1 6.1.1). if (exprType->isVoidType()) { - Diag(OpLoc, diag::ext_sizeof_void_type) - << (isSizeof ? "sizeof" : "__alignof") << ExprRange; + if (ExprKind != UETT_VecStep) + Diag(OpLoc, diag::ext_sizeof_void_type) + << ExprKind << ExprRange; return false; } if (RequireCompleteType(OpLoc, exprType, PDiag(diag::err_sizeof_alignof_incomplete_type) - << int(!isSizeof) << ExprRange)) + << ExprKind << ExprRange)) return true; // Reject sizeof(interface) and sizeof(interface) in 64-bit mode. if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) { Diag(OpLoc, diag::err_sizeof_nonfragile_interface) - << exprType << isSizeof << ExprRange; + << exprType << (ExprKind == UETT_SizeOf) + << ExprRange; return true; } @@ -2778,78 +2795,98 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc, if (isa(ME->getMemberDecl())) return false; - return S.CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false); + return S.CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange, + UETT_AlignOf); +} + +bool Sema::CheckVecStepExpr(Expr *E, SourceLocation OpLoc, + SourceRange ExprRange) { + E = E->IgnoreParens(); + + // Cannot know anything else if the expression is dependent. + if (E->isTypeDependent()) + return false; + + return CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange, + UETT_VecStep); } /// \brief Build a sizeof or alignof expression given a type operand. ExprResult -Sema::CreateSizeOfAlignOfExpr(TypeSourceInfo *TInfo, - SourceLocation OpLoc, - bool isSizeOf, SourceRange R) { +Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R) { if (!TInfo) return ExprError(); QualType T = TInfo->getType(); if (!T->isDependentType() && - CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf)) + CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind)) return ExprError(); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, TInfo, - Context.getSizeType(), OpLoc, - R.getEnd())); + return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, TInfo, + Context.getSizeType(), + OpLoc, R.getEnd())); } /// \brief Build a sizeof or alignof expression given an expression /// operand. ExprResult -Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, - bool isSizeOf, SourceRange R) { +Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R) { // Verify that the operand is valid. bool isInvalid = false; if (E->isTypeDependent()) { // Delay type-checking for type-dependent expressions. - } else if (!isSizeOf) { + } else if (ExprKind == UETT_AlignOf) { isInvalid = CheckAlignOfExpr(*this, E, OpLoc, R); + } else if (ExprKind == UETT_VecStep) { + isInvalid = CheckVecStepExpr(E, OpLoc, R); } else if (E->getBitField()) { // C99 6.5.3.4p1. Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; } else if (E->getType()->isPlaceholderType()) { ExprResult PE = CheckPlaceholderExpr(E, OpLoc); if (PE.isInvalid()) return ExprError(); - return CreateSizeOfAlignOfExpr(PE.take(), OpLoc, isSizeOf, R); + return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind, R); } else { - isInvalid = CheckSizeOfAlignOfOperand(E->getType(), OpLoc, R, true); + isInvalid = CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, R, + UETT_SizeOf); } if (isInvalid) return ExprError(); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, E, - Context.getSizeType(), OpLoc, - R.getEnd())); + return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, E, + Context.getSizeType(), + OpLoc, R.getEnd())); } -/// ActOnSizeOfAlignOfExpr - Handle @c sizeof(type) and @c sizeof @c expr and -/// the same for @c alignof and @c __alignof +/// ActOnUnaryExprOrTypeTraitExpr - Handle @c sizeof(type) and @c sizeof @c +/// expr and the same for @c alignof and @c __alignof /// Note that the ArgRange is invalid if isType is false. ExprResult -Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, - void *TyOrEx, const SourceRange &ArgRange) { +Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, bool isType, + void *TyOrEx, const SourceRange &ArgRange) { // If error parsing type, ignore. if (TyOrEx == 0) return ExprError(); if (isType) { TypeSourceInfo *TInfo; (void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo); - return CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeof, ArgRange); + return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, ArgRange); } Expr *ArgEx = (Expr *)TyOrEx; ExprResult Result - = CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange()); + = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind, + ArgEx->getSourceRange()); return move(Result); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 835b2f875ed0..d2688a1ba8da 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1300,25 +1300,28 @@ public: NumComponents, RParenLoc); } - /// \brief Build a new sizeof or alignof expression with a type argument. + /// \brief Build a new sizeof, alignof or vec_step expression with a + /// type argument. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildSizeOfAlignOf(TypeSourceInfo *TInfo, - SourceLocation OpLoc, - bool isSizeOf, SourceRange R) { - return getSema().CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeOf, R); + ExprResult RebuildUnaryExprOrTypeTrait(TypeSourceInfo *TInfo, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R) { + return getSema().CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, R); } - /// \brief Build a new sizeof or alignof expression with an expression - /// argument. + /// \brief Build a new sizeof, alignof or vec step expression with an + /// expression argument. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildSizeOfAlignOf(Expr *SubExpr, SourceLocation OpLoc, - bool isSizeOf, SourceRange R) { + ExprResult RebuildUnaryExprOrTypeTrait(Expr *SubExpr, SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R) { ExprResult Result - = getSema().CreateSizeOfAlignOfExpr(SubExpr, OpLoc, isSizeOf, R); + = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind, R); if (Result.isInvalid()) return ExprError(); @@ -5541,7 +5544,8 @@ TreeTransform::TransformOpaqueValueExpr(OpaqueValueExpr *E) { template ExprResult -TreeTransform::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +TreeTransform::TransformUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *E) { if (E->isArgumentType()) { TypeSourceInfo *OldT = E->getArgumentTypeInfo(); @@ -5552,9 +5556,9 @@ TreeTransform::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (!getDerived().AlwaysRebuild() && OldT == NewT) return SemaRef.Owned(E); - return getDerived().RebuildSizeOfAlignOf(NewT, E->getOperatorLoc(), - E->isSizeOf(), - E->getSourceRange()); + return getDerived().RebuildUnaryExprOrTypeTrait(NewT, E->getOperatorLoc(), + E->getKind(), + E->getSourceRange()); } ExprResult SubExpr; @@ -5572,9 +5576,10 @@ TreeTransform::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return SemaRef.Owned(E); } - return getDerived().RebuildSizeOfAlignOf(SubExpr.get(), E->getOperatorLoc(), - E->isSizeOf(), - E->getSourceRange()); + return getDerived().RebuildUnaryExprOrTypeTrait(SubExpr.get(), + E->getOperatorLoc(), + E->getKind(), + E->getSourceRange()); } template diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index e39fe3ba739e..70104cb18bc9 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -97,7 +97,7 @@ namespace clang { void VisitParenListExpr(ParenListExpr *E); void VisitUnaryOperator(UnaryOperator *E); void VisitOffsetOfExpr(OffsetOfExpr *E); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); void VisitArraySubscriptExpr(ArraySubscriptExpr *E); void VisitCallExpr(CallExpr *E); void VisitMemberExpr(MemberExpr *E); @@ -555,9 +555,9 @@ void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { E->setIndexExpr(I, Reader.ReadSubExpr()); } -void ASTStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { VisitExpr(E); - E->setSizeof(Record[Idx++]); + E->setKind(static_cast(Record[Idx++])); if (Record[Idx] == 0) { E->setArgument(Reader.ReadSubExpr()); ++Idx; @@ -1546,7 +1546,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_SIZEOF_ALIGN_OF: - S = new (Context) SizeOfAlignOfExpr(Empty); + S = new (Context) UnaryExprOrTypeTraitExpr(Empty); break; case EXPR_ARRAY_SUBSCRIPT: diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index a0ecf2792124..81942b6483ea 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -68,7 +68,7 @@ namespace clang { void VisitParenListExpr(ParenListExpr *E); void VisitUnaryOperator(UnaryOperator *E); void VisitOffsetOfExpr(OffsetOfExpr *E); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); void VisitArraySubscriptExpr(ArraySubscriptExpr *E); void VisitCallExpr(CallExpr *E); void VisitMemberExpr(MemberExpr *E); @@ -504,9 +504,9 @@ void ASTStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) { Code = serialization::EXPR_OFFSETOF; } -void ASTStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +void ASTStmtWriter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { VisitExpr(E); - Record.push_back(E->isSizeOf()); + Record.push_back(E->getKind()); if (E->isArgumentType()) Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record); else { diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp index ffcfce31a807..abf53fd3db28 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp @@ -26,7 +26,7 @@ class WalkAST : public StmtVisitor { public: WalkAST(BugReporter &br) : BR(br) {} - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); void VisitStmt(Stmt *S) { VisitChildren(S); } void VisitChildren(Stmt *S); }; @@ -39,8 +39,8 @@ void WalkAST::VisitChildren(Stmt *S) { } // CWE-467: Use of sizeof() on a Pointer Type -void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { - if (!E->isSizeOf()) +void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { + if (E->getKind() != UETT_SizeOf) return; // If an explicit type is used in the code, usually the coder knows what he is diff --git a/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp index bc9a29dd3ade..495c594bea31 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp @@ -641,9 +641,10 @@ bool IdempotentOperationChecker::CanVary(const Expr *Ex, return false; // Cases requiring custom logic - case Stmt::SizeOfAlignOfExprClass: { - const SizeOfAlignOfExpr *SE = cast(Ex); - if (!SE->isSizeOf()) + case Stmt::UnaryExprOrTypeTraitExprClass: { + const UnaryExprOrTypeTraitExpr *SE = + cast(Ex); + if (SE->getKind() != UETT_SizeOf) return false; return SE->getTypeOfArgument()->isVariableArrayType(); } diff --git a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index 905a99e161ee..b540bce98170 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp @@ -204,7 +204,7 @@ bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB, // Run each of the checks on the conditions if (containsMacro(cond) || containsEnum(cond) || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond) - || containsStmt(cond)) + || containsStmt(cond)) return true; return false; diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 95d339ff8273..9178a6184fbb 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -690,8 +690,9 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, VisitOffsetOfExpr(cast(S), Pred, Dst); break; - case Stmt::SizeOfAlignOfExprClass: - VisitSizeOfAlignOfExpr(cast(S), Pred, Dst); + case Stmt::UnaryExprOrTypeTraitExprClass: + VisitUnaryExprOrTypeTraitExpr(cast(S), + Pred, Dst); break; case Stmt::StmtExprClass: { @@ -2410,19 +2411,15 @@ void ExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred, assert(0 && "unprocessed InitListExpr type"); } -/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type). -void ExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, +/// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof(type). +void ExprEngine::VisitUnaryExprOrTypeTraitExpr( + const UnaryExprOrTypeTraitExpr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst) { QualType T = Ex->getTypeOfArgument(); - CharUnits amt; - if (Ex->isSizeOf()) { - if (T == getContext().VoidTy) { - // sizeof(void) == 1 byte. - amt = CharUnits::One(); - } - else if (!T->isConstantSizeType()) { + if (Ex->getKind() == UETT_SizeOf) { + if (!T->isIncompleteType() && !T->isConstantSizeType()) { assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); // FIXME: Add support for VLA type arguments, not just VLA expressions. @@ -2463,13 +2460,11 @@ void ExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, Dst.Add(Pred); return; } - else { - // All other cases. - amt = getContext().getTypeSizeInChars(T); - } } - else // Get alignment of the type. - amt = getContext().getTypeAlignInChars(T); + + Expr::EvalResult Result; + Ex->Evaluate(Result, getContext()); + CharUnits amt = CharUnits::fromQuantity(Result.Val.getInt().getZExtValue()); MakeNode(Dst, Ex, Pred, GetState(Pred)->BindExpr(Ex, diff --git a/clang/test/PCH/exprs.c b/clang/test/PCH/exprs.c index d855defe7eed..ffeab732f84d 100644 --- a/clang/test/PCH/exprs.c +++ b/clang/test/PCH/exprs.c @@ -39,7 +39,7 @@ negate_enum *int_ptr4 = &integer; // OffsetOfExpr offsetof_type *offsetof_ptr = &size_type_value; -// SizeOfAlignOfExpr +// UnaryExprOrTypeTraitExpr typeof(sizeof(float)) size_t_value; typeof_sizeof *size_t_ptr = &size_t_value; typeof_sizeof2 *size_t_ptr2 = &size_t_value; diff --git a/clang/test/PCH/exprs.h b/clang/test/PCH/exprs.h index 80768f8df24e..c9adbe8aad76 100644 --- a/clang/test/PCH/exprs.h +++ b/clang/test/PCH/exprs.h @@ -38,7 +38,7 @@ struct Z { typedef typeof(__builtin_offsetof(struct Z, y.array[1 + 2].member)) offsetof_type; -// SizeOfAlignOfExpr +// UnaryExprOrTypeTraitExpr typedef typeof(sizeof(int)) typeof_sizeof; typedef typeof(sizeof(Enumerator)) typeof_sizeof2; diff --git a/clang/test/SemaOpenCL/vec_step.cl b/clang/test/SemaOpenCL/vec_step.cl new file mode 100644 index 000000000000..d83ebf11fe03 --- /dev/null +++ b/clang/test/SemaOpenCL/vec_step.cl @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s + +typedef int int2 __attribute__((ext_vector_type(2))); +typedef int int3 __attribute__((ext_vector_type(3))); +typedef int int4 __attribute__((ext_vector_type(4))); +typedef int int8 __attribute__((ext_vector_type(8))); +typedef int int16 __attribute__((ext_vector_type(16))); + +void foo(int3 arg1, int8 arg2) { + int4 auto1; + int16 *auto2; + int auto3; + int2 auto4; + struct S *incomplete1; + + int res1[vec_step(arg1) == 4 ? 1 : -1]; + int res2[vec_step(arg2) == 8 ? 1 : -1]; + int res3[vec_step(auto1) == 4 ? 1 : -1]; + int res4[vec_step(*auto2) == 16 ? 1 : -1]; + int res5[vec_step(auto3) == 1 ? 1 : -1]; + int res6[vec_step(auto4) == 2 ? 1 : -1]; + int res7[vec_step(int2) == 2 ? 1 : -1]; + int res8[vec_step(int3) == 4 ? 1 : -1]; + int res9[vec_step(int4) == 4 ? 1 : -1]; + int res10[vec_step(int8) == 8 ? 1 : -1]; + int res11[vec_step(int16) == 16 ? 1 : -1]; + int res12[vec_step(void) == 1 ? 1 : -1]; + + int res13 = vec_step(*incomplete1); // expected-error {{'vec_step' requires built-in scalar or vector type, 'struct S' invalid}} + int res14 = vec_step(int16*); // expected-error {{'vec_step' requires built-in scalar or vector type, 'int16 *' invalid}} + int res15 = vec_step(void(void)); // expected-error {{'vec_step' requires built-in scalar or vector type, 'void (void)' invalid}} +} diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 16672ca70401..7853c3dda88d 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1749,7 +1749,7 @@ public: void VisitObjCEncodeExpr(ObjCEncodeExpr *E); void VisitObjCMessageExpr(ObjCMessageExpr *M); void VisitOverloadExpr(OverloadExpr *E); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); void VisitStmt(Stmt *S); void VisitSwitchStmt(SwitchStmt *S); void VisitWhileStmt(WhileStmt *W); @@ -2014,7 +2014,8 @@ void EnqueueVisitor::VisitOverloadExpr(OverloadExpr *E) { AddExplicitTemplateArgs(E->getOptionalExplicitTemplateArgs()); WL.push_back(OverloadExprParts(E, Parent)); } -void EnqueueVisitor::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +void EnqueueVisitor::VisitUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *E) { EnqueueChildren(E); if (E->isArgumentType()) AddTypeLoc(E->getArgumentTypeInfo()); diff --git a/clang/tools/libclang/CXCursor.cpp b/clang/tools/libclang/CXCursor.cpp index dd22a97ab19b..7ed5d2051cfc 100644 --- a/clang/tools/libclang/CXCursor.cpp +++ b/clang/tools/libclang/CXCursor.cpp @@ -111,7 +111,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::ParenExprClass: case Stmt::UnaryOperatorClass: case Stmt::OffsetOfExprClass: - case Stmt::SizeOfAlignOfExprClass: + case Stmt::UnaryExprOrTypeTraitExprClass: case Stmt::ArraySubscriptExprClass: case Stmt::BinaryOperatorClass: case Stmt::CompoundAssignOperatorClass: