diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6009,24 +6009,16 @@ "1 byte of precision|with a non power of 2 precision}0">; // Expressions. -def select_unary_expr_or_type_trait_kind : TextSubstitution< - "%select{sizeof|alignof|vec_step|__builtin_omp_required_simd_align|" - "__alignof}0">; def ext_sizeof_alignof_function_type : Extension< - "invalid application of '%sub{select_unary_expr_or_type_trait_kind}0' " - "to a function type">, InGroup; + "invalid application of '%0' to a function type">, InGroup; def ext_sizeof_alignof_void_type : Extension< - "invalid application of '%sub{select_unary_expr_or_type_trait_kind}0' " - "to a void type">, InGroup; + "invalid application of '%0' to a void type">, InGroup; def err_opencl_sizeof_alignof_type : Error< - "invalid application of '%sub{select_unary_expr_or_type_trait_kind}0' " - "to a void type">; + "invalid application of '%0' to a void type">; def err_sizeof_alignof_incomplete_or_sizeless_type : Error< - "invalid application of '%sub{select_unary_expr_or_type_trait_kind}0' " - "to %select{an incomplete|sizeless}1 type %2">; + "invalid application of '%0' to %select{an incomplete|sizeless}1 type %2">; def err_sizeof_alignof_function_type : Error< - "invalid application of '%sub{select_unary_expr_or_type_trait_kind}0' " - "to a function type">; + "invalid application of '%0' to a function type">; def err_openmp_default_simd_align_expr : Error< "invalid application of '__builtin_omp_required_simd_align' to an expression, only type is allowed">; def err_sizeof_alignof_typeof_bitfield : Error< diff --git a/clang/include/clang/Basic/ExpressionTraits.h b/clang/include/clang/Basic/ExpressionTraits.h --- a/clang/include/clang/Basic/ExpressionTraits.h +++ b/clang/include/clang/Basic/ExpressionTraits.h @@ -14,12 +14,24 @@ #ifndef LLVM_CLANG_BASIC_EXPRESSIONTRAITS_H #define LLVM_CLANG_BASIC_EXPRESSIONTRAITS_H +#include "llvm/Support/Compiler.h" + namespace clang { - enum ExpressionTrait { - ET_IsLValueExpr, - ET_IsRValueExpr - }; -} +enum ExpressionTrait { +#define EXPRESSION_TRAIT(Spelling, Name, Key) ET_##Name, +#include "clang/Basic/TokenKinds.def" + ET_Last = -1 // ET_Last == last ET_XX in the enum. +#define EXPRESSION_TRAIT(Spelling, Name, Key) +1 +#include "clang/Basic/TokenKinds.def" +}; + +/// Return the internal name of type trait \p T. Never null. +const char *getTraitName(ExpressionTrait T) LLVM_READONLY; + +/// Return the spelling of the type trait \p TT. Never null. +const char *getTraitSpelling(ExpressionTrait T) LLVM_READONLY; + +} // namespace clang #endif diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -50,6 +50,18 @@ #ifndef TYPE_TRAIT_N #define TYPE_TRAIT_N(I,E,K) TYPE_TRAIT(0,I,K) #endif +#ifndef ARRAY_TYPE_TRAIT +#define ARRAY_TYPE_TRAIT(I,E,K) KEYWORD(I,K) +#endif +#ifndef UNARY_EXPR_OR_TYPE_TRAIT +#define UNARY_EXPR_OR_TYPE_TRAIT(I,E,K) KEYWORD(I,K) +#endif +#ifndef CXX11_UNARY_EXPR_OR_TYPE_TRAIT +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(I,E,K) CXX11_KEYWORD(I,K) +#endif +#ifndef EXPRESSION_TRAIT +#define EXPRESSION_TRAIT(I,E,K) KEYWORD(I,K) +#endif #ifndef ALIAS #define ALIAS(X,Y,Z) #endif @@ -292,7 +304,7 @@ KEYWORD(return , KEYALL) KEYWORD(short , KEYALL) KEYWORD(signed , KEYALL) -KEYWORD(sizeof , KEYALL) +UNARY_EXPR_OR_TYPE_TRAIT(sizeof, SizeOf, KEYALL) KEYWORD(static , KEYALL) KEYWORD(struct , KEYALL) KEYWORD(switch , KEYALL) @@ -364,7 +376,8 @@ // C++11 keywords CXX11_KEYWORD(alignas , 0) -CXX11_KEYWORD(alignof , 0) +// alignof and _Alignof return the required ABI alignment +CXX11_UNARY_EXPR_OR_TYPE_TRAIT(alignof, AlignOf, 0) CXX11_KEYWORD(char16_t , KEYNOMS18) CXX11_KEYWORD(char32_t , KEYNOMS18) CXX11_KEYWORD(constexpr , 0) @@ -406,7 +419,9 @@ KEYWORD(_Decimal64 , KEYALL) KEYWORD(_Decimal128 , KEYALL) KEYWORD(__null , KEYCXX) -KEYWORD(__alignof , KEYALL) +// __alignof returns the preferred alignment of a type, the alignment +// clang will attempt to give an object of the type if allowed by ABI. +UNARY_EXPR_OR_TYPE_TRAIT(__alignof, PreferredAlignOf, KEYALL) KEYWORD(__attribute , KEYALL) KEYWORD(__builtin_choose_expr , KEYALL) KEYWORD(__builtin_offsetof , KEYALL) @@ -494,8 +509,8 @@ TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX) // Embarcadero Expression Traits -KEYWORD(__is_lvalue_expr , KEYCXX) -KEYWORD(__is_rvalue_expr , KEYCXX) +EXPRESSION_TRAIT(__is_lvalue_expr, IsLValueExpr, KEYCXX) +EXPRESSION_TRAIT(__is_rvalue_expr, IsRValueExpr, KEYCXX) // Embarcadero Unary Type Traits TYPE_TRAIT_1(__is_arithmetic, IsArithmetic, KEYCXX) @@ -524,8 +539,8 @@ // Embarcadero Binary Type Traits TYPE_TRAIT_2(__is_same, IsSame, KEYCXX) TYPE_TRAIT_2(__is_convertible, IsConvertible, KEYCXX) -KEYWORD(__array_rank , KEYCXX) -KEYWORD(__array_extent , KEYCXX) +ARRAY_TYPE_TRAIT(__array_rank, ArrayRank, KEYCXX) +ARRAY_TYPE_TRAIT(__array_extent, ArrayExtent, KEYCXX) // Name for GCC 6 compatibility. ALIAS("__is_same_as", __is_same, KEYCXX) @@ -571,7 +586,7 @@ ALIAS("read_write", __read_write , KEYOPENCLC | KEYOPENCLCXX) // OpenCL builtins KEYWORD(__builtin_astype , KEYOPENCLC | KEYOPENCLCXX) -KEYWORD(vec_step , KEYOPENCLC | KEYALTIVEC | KEYZVECTOR) +UNARY_EXPR_OR_TYPE_TRAIT(vec_step, VecStep, KEYOPENCLC | KEYALTIVEC | KEYZVECTOR) #define GENERIC_IMAGE_TYPE(ImgType, Id) KEYWORD(ImgType##_t, KEYOPENCLC | KEYOPENCLCXX) #include "clang/Basic/OpenCLImageTypes.def" KEYWORD(pipe , KEYOPENCLC | KEYOPENCLCXX) @@ -579,7 +594,7 @@ KEYWORD(addrspace_cast , KEYOPENCLCXX) // OpenMP Type Traits -KEYWORD(__builtin_omp_required_simd_align, KEYALL) +UNARY_EXPR_OR_TYPE_TRAIT(__builtin_omp_required_simd_align, OpenMPRequiredSimdAlign, KEYALL) // Borland Extensions. KEYWORD(__pascal , KEYALL) @@ -871,6 +886,10 @@ #undef CXX_KEYWORD_OPERATOR #undef PPKEYWORD #undef ALIAS +#undef EXPRESSION_TRAIT +#undef CXX11_UNARY_EXPR_OR_TYPE_TRAIT +#undef UNARY_EXPR_OR_TYPE_TRAIT +#undef ARRAY_TYPE_TRAIT #undef TYPE_TRAIT_N #undef TYPE_TRAIT_2 #undef TYPE_TRAIT_1 diff --git a/clang/include/clang/Basic/TypeTraits.h b/clang/include/clang/Basic/TypeTraits.h --- a/clang/include/clang/Basic/TypeTraits.h +++ b/clang/include/clang/Basic/TypeTraits.h @@ -14,97 +14,59 @@ #ifndef LLVM_CLANG_BASIC_TYPETRAITS_H #define LLVM_CLANG_BASIC_TYPETRAITS_H +#include "llvm/Support/Compiler.h" + namespace clang { +/// Names for traits that operate specifically on types. +enum TypeTrait { +#define TYPE_TRAIT_1(Spelling, Name, Key) UTT_##Name, +#include "clang/Basic/TokenKinds.def" + UTT_Last = -1 // UTT_Last == last UTT_XX in the enum. +#define TYPE_TRAIT_1(Spelling, Name, Key) +1 +#include "clang/Basic/TokenKinds.def" + , +#define TYPE_TRAIT_2(Spelling, Name, Key) BTT_##Name, +#include "clang/Basic/TokenKinds.def" + BTT_Last = UTT_Last // BTT_Last == last BTT_XX in the enum. +#define TYPE_TRAIT_2(Spelling, Name, Key) +1 +#include "clang/Basic/TokenKinds.def" + , +#define TYPE_TRAIT_N(Spelling, Name, Key) TT_##Name, +#include "clang/Basic/TokenKinds.def" + TT_Last = BTT_Last // TT_Last == last TT_XX in the enum. +#define TYPE_TRAIT_N(Spelling, Name, Key) +1 +#include "clang/Basic/TokenKinds.def" +}; + +/// Names for the array type traits. +enum ArrayTypeTrait { +#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) ATT_##Name, +#include "clang/Basic/TokenKinds.def" + ATT_Last = -1 // ATT_Last == last ATT_XX in the enum. +#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) +1 +#include "clang/Basic/TokenKinds.def" +}; - /// Names for traits that operate specifically on types. - enum TypeTrait { - UTT_HasNothrowAssign, - UTT_HasNothrowMoveAssign, - UTT_HasNothrowCopy, - UTT_HasNothrowConstructor, - UTT_HasTrivialAssign, - UTT_HasTrivialMoveAssign, - UTT_HasTrivialCopy, - UTT_HasTrivialDefaultConstructor, - UTT_HasTrivialMoveConstructor, - UTT_HasTrivialDestructor, - UTT_HasVirtualDestructor, - UTT_IsAbstract, - UTT_IsAggregate, - UTT_IsArithmetic, - UTT_IsArray, - UTT_IsClass, - UTT_IsCompleteType, - UTT_IsCompound, - UTT_IsConst, - UTT_IsDestructible, - UTT_IsEmpty, - UTT_IsEnum, - UTT_IsFinal, - UTT_IsFloatingPoint, - UTT_IsFunction, - UTT_IsFundamental, - UTT_IsIntegral, - UTT_IsInterfaceClass, - UTT_IsLiteral, - UTT_IsLvalueReference, - UTT_IsMemberFunctionPointer, - UTT_IsMemberObjectPointer, - UTT_IsMemberPointer, - UTT_IsNothrowDestructible, - UTT_IsObject, - UTT_IsPOD, - UTT_IsPointer, - UTT_IsPolymorphic, - UTT_IsReference, - UTT_IsRvalueReference, - UTT_IsScalar, - UTT_IsSealed, - UTT_IsSigned, - UTT_IsStandardLayout, - UTT_IsTrivial, - UTT_IsTriviallyCopyable, - UTT_IsTriviallyDestructible, - UTT_IsUnion, - UTT_IsUnsigned, - UTT_IsVoid, - UTT_IsVolatile, - UTT_HasUniqueObjectRepresentations, - UTT_Last = UTT_HasUniqueObjectRepresentations, - BTT_IsBaseOf, - BTT_IsConvertible, - BTT_IsConvertibleTo, - BTT_IsSame, - BTT_TypeCompatible, - BTT_IsAssignable, - BTT_IsNothrowAssignable, - BTT_IsTriviallyAssignable, - BTT_ReferenceBindsToTemporary, - BTT_Last = BTT_ReferenceBindsToTemporary, - TT_IsConstructible, - TT_IsNothrowConstructible, - TT_IsTriviallyConstructible - }; +/// Names for the "expression or type" traits. +enum UnaryExprOrTypeTrait { +#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) UETT_##Name, +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) UETT_##Name, +#include "clang/Basic/TokenKinds.def" + UETT_Last = -1 // UETT_Last == last UETT_XX in the enum. +#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) +1 +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) +1 +#include "clang/Basic/TokenKinds.def" +}; - /// Names for the array type traits. - enum ArrayTypeTrait { - ATT_ArrayRank, - ATT_ArrayExtent - }; +/// Return the internal name of type trait \p T. Never null. +const char *getTraitName(TypeTrait T) LLVM_READONLY; +const char *getTraitName(ArrayTypeTrait T) LLVM_READONLY; +const char *getTraitName(UnaryExprOrTypeTrait T) LLVM_READONLY; - /// Names for the "expression or type" traits. - enum UnaryExprOrTypeTrait { - UETT_SizeOf, - /// Used for C's _Alignof and C++'s alignof. - /// _Alignof and alignof return the required ABI alignment. - UETT_AlignOf, - UETT_VecStep, - UETT_OpenMPRequiredSimdAlign, - /// Used for GCC's __alignof. - /// __alignof returns the preferred alignment of a type, the alignment - /// clang will attempt to give an object of the type if allowed by ABI. - UETT_PreferredAlignOf, - }; -} +/// Return the spelling of the type trait \p TT. Never null. +const char *getTraitSpelling(TypeTrait T) LLVM_READONLY; +const char *getTraitSpelling(ArrayTypeTrait T) LLVM_READONLY; +const char *getTraitSpelling(UnaryExprOrTypeTrait T) LLVM_READONLY; +} // namespace clang #endif diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1235,14 +1235,7 @@ void JSONNodeDumper::VisitUnaryExprOrTypeTraitExpr( const UnaryExprOrTypeTraitExpr *TTE) { - switch (TTE->getKind()) { - case UETT_SizeOf: JOS.attribute("name", "sizeof"); break; - case UETT_AlignOf: JOS.attribute("name", "alignof"); break; - case UETT_VecStep: JOS.attribute("name", "vec_step"); break; - case UETT_PreferredAlignOf: JOS.attribute("name", "__alignof"); break; - case UETT_OpenMPRequiredSimdAlign: - JOS.attribute("name", "__builtin_omp_required_simd_align"); break; - } + JOS.attribute("name", getTraitSpelling(TTE->getKind())); if (TTE->isArgumentType()) JOS.attribute("argType", createQualType(TTE->getArgumentType())); } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1281,29 +1281,20 @@ OS << ")"; } -void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){ - switch(Node->getKind()) { - case UETT_SizeOf: - OS << "sizeof"; - break; - case UETT_AlignOf: +void StmtPrinter::VisitUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *Node) { + const char *Spelling = getTraitSpelling(Node->getKind()); + if (Node->getKind() == UETT_AlignOf) { if (Policy.Alignof) - OS << "alignof"; + Spelling = "alignof"; else if (Policy.UnderscoreAlignof) - OS << "_Alignof"; + Spelling = "_Alignof"; else - OS << "__alignof"; - break; - case UETT_PreferredAlignOf: - OS << "__alignof"; - break; - case UETT_VecStep: - OS << "vec_step"; - break; - case UETT_OpenMPRequiredSimdAlign: - OS << "__builtin_omp_required_simd_align"; - break; + Spelling = "__alignof"; } + + OS << Spelling; + if (Node->isArgumentType()) { OS << '('; Node->getArgumentType().print(OS, Policy); @@ -2212,37 +2203,8 @@ printTemplateArgumentList(OS, Node->template_arguments(), Policy); } -static const char *getTypeTraitName(TypeTrait TT) { - switch (TT) { -#define TYPE_TRAIT_1(Spelling, Name, Key) \ -case clang::UTT_##Name: return #Spelling; -#define TYPE_TRAIT_2(Spelling, Name, Key) \ -case clang::BTT_##Name: return #Spelling; -#define TYPE_TRAIT_N(Spelling, Name, Key) \ - case clang::TT_##Name: return #Spelling; -#include "clang/Basic/TokenKinds.def" - } - llvm_unreachable("Type trait not covered by switch"); -} - -static const char *getTypeTraitName(ArrayTypeTrait ATT) { - switch (ATT) { - case ATT_ArrayRank: return "__array_rank"; - case ATT_ArrayExtent: return "__array_extent"; - } - llvm_unreachable("Array type trait not covered by switch"); -} - -static const char *getExpressionTraitName(ExpressionTrait ET) { - switch (ET) { - case ET_IsLValueExpr: return "__is_lvalue_expr"; - case ET_IsRValueExpr: return "__is_rvalue_expr"; - } - llvm_unreachable("Expression type trait not covered by switch"); -} - void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) { - OS << getTypeTraitName(E->getTrait()) << "("; + OS << getTraitSpelling(E->getTrait()) << "("; for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) { if (I > 0) OS << ", "; @@ -2252,13 +2214,13 @@ } void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { - OS << getTypeTraitName(E->getTrait()) << '('; + OS << getTraitSpelling(E->getTrait()) << '('; E->getQueriedType().print(OS, Policy); OS << ')'; } void StmtPrinter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { - OS << getExpressionTraitName(E->getTrait()) << '('; + OS << getTraitSpelling(E->getTrait()) << '('; PrintExpr(E->getQueriedExpression()); OS << ')'; } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -18,6 +18,7 @@ #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TypeTraits.h" using namespace clang; @@ -833,23 +834,8 @@ void TextNodeDumper::VisitUnaryExprOrTypeTraitExpr( const UnaryExprOrTypeTraitExpr *Node) { - switch (Node->getKind()) { - case UETT_SizeOf: - OS << " sizeof"; - break; - case UETT_AlignOf: - OS << " alignof"; - break; - case UETT_VecStep: - OS << " vec_step"; - break; - case UETT_OpenMPRequiredSimdAlign: - OS << " __builtin_omp_required_simd_align"; - break; - case UETT_PreferredAlignOf: - OS << " __alignof"; - break; - } + OS << " " << getTraitSpelling(Node->getKind()); + if (Node->isArgumentType()) dumpType(Node->getArgumentType()); } diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h --- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -219,14 +219,12 @@ private: static Optional getUnaryOrTypeTraitKind(llvm::StringRef ClauseKind) { - // FIXME: Type traits should probably be in a `.def` to make less error - // prone. return llvm::StringSwitch>(ClauseKind) - .Case("UETT_SizeOf", UETT_SizeOf) - .Case("UETT_AlignOf", UETT_AlignOf) - .Case("UETT_VecStep", UETT_VecStep) - .Case("UETT_OpenMPRequiredSimdAlign", UETT_OpenMPRequiredSimdAlign) - .Case("UETT_PreferredAlignOf", UETT_PreferredAlignOf) +#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) \ + .Case("UETT_" #Name, UETT_##Name) +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) \ + .Case("UETT_" #Name, UETT_##Name) +#include "clang/Basic/TokenKinds.def" .Default(llvm::None); } diff --git a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp --- a/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.cpp @@ -101,9 +101,9 @@ clang::ast_matchers::dynamic::internal::ArgTypeTraits< clang::UnaryExprOrTypeTrait>::getBestGuess(const VariantValue &Value) { static constexpr llvm::StringRef Allowed[] = { - "UETT_SizeOf", "UETT_AlignOf", - "UETT_VecStep", "UETT_OpenMPRequiredSimdAlign", - "UETT_PreferredAlignOf", +#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name, +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) "UETT_" #Name, +#include "clang/Basic/TokenKinds.def" }; if (Value.isString()) return ::getBestGuess(Value.getString(), llvm::makeArrayRef(Allowed), diff --git a/clang/lib/Basic/CMakeLists.txt b/clang/lib/Basic/CMakeLists.txt --- a/clang/lib/Basic/CMakeLists.txt +++ b/clang/lib/Basic/CMakeLists.txt @@ -45,6 +45,7 @@ Diagnostic.cpp DiagnosticIDs.cpp DiagnosticOptions.cpp + ExpressionTraits.cpp FileManager.cpp FileSystemStatCache.cpp FixedPoint.cpp @@ -87,6 +88,7 @@ Targets/X86.cpp Targets/XCore.cpp TokenKinds.cpp + TypeTraits.cpp Version.cpp Warnings.cpp XRayInstr.cpp diff --git a/clang/lib/Basic/ExpressionTraits.cpp b/clang/lib/Basic/ExpressionTraits.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Basic/ExpressionTraits.cpp @@ -0,0 +1,36 @@ +//===--- ExpressionTraits.cpp - Expression Traits Support -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the expression traits support functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/ExpressionTraits.h" +#include "llvm/Support/ErrorHandling.h" +#include +using namespace clang; + +static constexpr const char *ExpressionTraitNames[] = { +#define EXPRESSION_TRAIT(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *ExpressionTraitSpellings[] = { +#define EXPRESSION_TRAIT(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +}; + +const char *clang::getTraitName(ExpressionTrait T) { + assert(T <= ET_Last && "invalid enum value!"); + return ExpressionTraitNames[T]; +} + +const char *clang::getTraitSpelling(ExpressionTrait T) { + assert(T <= ET_Last && "invalid enum value!"); + return ExpressionTraitSpellings[T]; +} diff --git a/clang/lib/Basic/TypeTraits.cpp b/clang/lib/Basic/TypeTraits.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Basic/TypeTraits.cpp @@ -0,0 +1,86 @@ +//===--- TypeTraits.cpp - Type Traits Support -----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the type traits support functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/TypeTraits.h" +#include "llvm/Support/ErrorHandling.h" +#include +using namespace clang; + +static constexpr const char *TypeTraitNames[] = { +#define TYPE_TRAIT_1(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +#define TYPE_TRAIT_2(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +#define TYPE_TRAIT_N(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *TypeTraitSpellings[] = { +#define TYPE_TRAIT_1(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +#define TYPE_TRAIT_2(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +#define TYPE_TRAIT_N(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *ArrayTypeTraitNames[] = { +#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *ArrayTypeTraitSpellings[] = { +#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *UnaryExprOrTypeTraitNames[] = { +#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Name, +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Name, +#include "clang/Basic/TokenKinds.def" +}; + +static constexpr const char *UnaryExprOrTypeTraitSpellings[] = { +#define UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Spelling, +#define CXX11_UNARY_EXPR_OR_TYPE_TRAIT(Spelling, Name, Key) #Spelling, +#include "clang/Basic/TokenKinds.def" +}; + +const char *clang::getTraitName(TypeTrait T) { + assert(T <= TT_Last && "invalid enum value!"); + return TypeTraitNames[T]; +} + +const char *clang::getTraitName(ArrayTypeTrait T) { + assert(T <= ATT_Last && "invalid enum value!"); + return ArrayTypeTraitNames[T]; +} + +const char *clang::getTraitName(UnaryExprOrTypeTrait T) { + assert(T <= UETT_Last && "invalid enum value!"); + return UnaryExprOrTypeTraitNames[T]; +} + +const char *clang::getTraitSpelling(TypeTrait T) { + assert(T <= TT_Last && "invalid enum value!"); + return TypeTraitSpellings[T]; +} + +const char *clang::getTraitSpelling(ArrayTypeTrait T) { + assert(T <= ATT_Last && "invalid enum value!"); + return ArrayTypeTraitSpellings[T]; +} + +const char *clang::getTraitSpelling(UnaryExprOrTypeTrait T) { + assert(T <= UETT_Last && "invalid enum value!"); + return UnaryExprOrTypeTraitSpellings[T]; +} diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -3971,7 +3971,7 @@ TraitKind == UETT_PreferredAlignOf)) { // sizeof(function)/alignof(function) is allowed as an extension. S.Diag(Loc, diag::ext_sizeof_alignof_function_type) - << TraitKind << ArgRange; + << getTraitSpelling(TraitKind) << ArgRange; return false; } @@ -3980,7 +3980,7 @@ if (T->isVoidType()) { unsigned DiagID = S.LangOpts.OpenCL ? diag::err_opencl_sizeof_alignof_type : diag::ext_sizeof_alignof_void_type; - S.Diag(Loc, DiagID) << TraitKind << ArgRange; + S.Diag(Loc, DiagID) << getTraitSpelling(TraitKind) << ArgRange; return false; } @@ -4059,13 +4059,13 @@ if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) { if (RequireCompleteSizedType( E->getExprLoc(), Context.getBaseElementType(E->getType()), - diag::err_sizeof_alignof_incomplete_or_sizeless_type, ExprKind, - E->getSourceRange())) + diag::err_sizeof_alignof_incomplete_or_sizeless_type, + getTraitSpelling(ExprKind), E->getSourceRange())) return true; } else { if (RequireCompleteSizedExprType( - E, diag::err_sizeof_alignof_incomplete_or_sizeless_type, ExprKind, - E->getSourceRange())) + E, diag::err_sizeof_alignof_incomplete_or_sizeless_type, + getTraitSpelling(ExprKind), E->getSourceRange())) return true; } @@ -4075,7 +4075,7 @@ if (ExprTy->isFunctionType()) { Diag(E->getExprLoc(), diag::err_sizeof_alignof_function_type) - << ExprKind << E->getSourceRange(); + << getTraitSpelling(ExprKind) << E->getSourceRange(); return true; } @@ -4164,12 +4164,12 @@ if (RequireCompleteSizedType( OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type, - ExprKind, ExprRange)) + getTraitSpelling(ExprKind), ExprRange)) return true; if (ExprType->isFunctionType()) { Diag(OpLoc, diag::err_sizeof_alignof_function_type) - << ExprKind << ExprRange; + << getTraitSpelling(ExprKind) << ExprRange; return true; }