diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:04 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2023-02-11 12:38:11 +0000 |
| commit | e3b557809604d036af6e00c60f012c2025b59a5e (patch) | |
| tree | 8a11ba2269a3b669601e2fd41145b174008f4da8 /clang/lib/Sema/SemaType.cpp | |
| parent | 08e8dd7b9db7bb4a9de26d44c1cbfd24e869c014 (diff) | |
Diffstat (limited to 'clang/lib/Sema/SemaType.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 701 |
1 files changed, 512 insertions, 189 deletions
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 3ab5d26a9a75..89d819a77dcb 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -19,9 +19,11 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -33,12 +35,13 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/Support/ErrorHandling.h" #include <bitset> +#include <optional> using namespace clang; @@ -430,7 +433,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator, if (onlyBlockPointers) continue; - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorChunk::BlockPointer: result = &ptrChunk; @@ -759,7 +762,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, - /*DeclsInPrototype=*/None, loc, loc, declarator)); + /*DeclsInPrototype=*/std::nullopt, loc, loc, declarator)); // For consistency, make sure the state still has us as processing // the decl spec. @@ -827,8 +830,8 @@ static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator, /// Apply Objective-C type arguments to the given type. static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, ArrayRef<TypeSourceInfo *> typeArgs, - SourceRange typeArgsRange, - bool failOnError = false) { + SourceRange typeArgsRange, bool failOnError, + bool rebuilding) { // We can only apply type arguments to an Objective-C class type. const auto *objcObjectType = type->getAs<ObjCObjectType>(); if (!objcObjectType || !objcObjectType->getInterface()) { @@ -892,7 +895,9 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, } } - if (!diagnosed) { + // When rebuilding, qualifiers might have gotten here through a + // final substitution. + if (!rebuilding && !diagnosed) { S.Diag(qual.getBeginLoc(), diag::err_objc_type_arg_qualified) << typeArg << typeArg.getQualifiers().getAsString() << FixItHint::CreateRemoval(rangeToRemove); @@ -1054,22 +1059,18 @@ QualType Sema::BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl, return Result; } -QualType Sema::BuildObjCObjectType(QualType BaseType, - SourceLocation Loc, - SourceLocation TypeArgsLAngleLoc, - ArrayRef<TypeSourceInfo *> TypeArgs, - SourceLocation TypeArgsRAngleLoc, - SourceLocation ProtocolLAngleLoc, - ArrayRef<ObjCProtocolDecl *> Protocols, - ArrayRef<SourceLocation> ProtocolLocs, - SourceLocation ProtocolRAngleLoc, - bool FailOnError) { +QualType Sema::BuildObjCObjectType( + QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, SourceLocation ProtocolRAngleLoc, + bool FailOnError, bool Rebuilding) { QualType Result = BaseType; if (!TypeArgs.empty()) { - Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs, - SourceRange(TypeArgsLAngleLoc, - TypeArgsRAngleLoc), - FailOnError); + Result = + applyObjCTypeArgs(*this, Loc, Result, TypeArgs, + SourceRange(TypeArgsLAngleLoc, TypeArgsRAngleLoc), + FailOnError, Rebuilding); if (FailOnError && Result.isNull()) return QualType(); } @@ -1097,11 +1098,10 @@ TypeResult Sema::actOnObjCProtocolQualifierType( SourceLocation rAngleLoc) { // Form id<protocol-list>. QualType Result = Context.getObjCObjectType( - Context.ObjCBuiltinIdTy, { }, - llvm::makeArrayRef( - (ObjCProtocolDecl * const *)protocols.data(), - protocols.size()), - false); + Context.ObjCBuiltinIdTy, {}, + llvm::ArrayRef((ObjCProtocolDecl *const *)protocols.data(), + protocols.size()), + false); Result = Context.getObjCObjectPointerType(Result); TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result); @@ -1168,10 +1168,11 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( T, BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(), TypeArgsLAngleLoc, ActualTypeArgInfos, TypeArgsRAngleLoc, ProtocolLAngleLoc, - llvm::makeArrayRef((ObjCProtocolDecl * const *)Protocols.data(), - Protocols.size()), + llvm::ArrayRef((ObjCProtocolDecl *const *)Protocols.data(), + Protocols.size()), ProtocolLocs, ProtocolRAngleLoc, - /*FailOnError=*/false); + /*FailOnError=*/false, + /*Rebuilding=*/false); if (Result == T) return BaseType; @@ -1247,6 +1248,18 @@ getImageAccess(const ParsedAttributesView &Attrs) { return OpenCLAccessAttr::Keyword_read_only; } +static UnaryTransformType::UTTKind +TSTToUnaryTransformType(DeclSpec::TST SwitchTST) { + switch (SwitchTST) { +#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \ + case TST_##Trait: \ + return UnaryTransformType::Enum; +#include "clang/Basic/TransformTypeTraits.def" + default: + llvm_unreachable("attempted to parse a non-unary transform builtin"); + } +} + /// Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -1369,7 +1382,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } } - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclSpec::TST_int: { if (DS.getTypeSpecSign() != TypeSpecifierSign::Unsigned) { switch (DS.getTypeSpecWidth()) { @@ -1575,6 +1588,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // TypeQuals handled by caller. Result = Context.getTypeDeclType(D); + if (const auto *Using = + dyn_cast_or_null<UsingShadowDecl>(DS.getRepAsFoundDecl())) + Result = Context.getUsingType(Using, Result); // In both C and C++, make an ElaboratedType. ElaboratedTypeKeyword Keyword @@ -1596,6 +1612,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // TypeQuals handled by caller. break; } + case DeclSpec::TST_typeof_unqualType: case DeclSpec::TST_typeofType: // FIXME: Preserve type source info. Result = S.GetTypeFromParser(DS.getRepAsType()); @@ -1604,13 +1621,20 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { if (const TagType *TT = Result->getAs<TagType>()) S.DiagnoseUseOfDecl(TT->getDecl(), DS.getTypeSpecTypeLoc()); // TypeQuals handled by caller. - Result = Context.getTypeOfType(Result); + Result = Context.getTypeOfType( + Result, DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualType + ? TypeOfKind::Unqualified + : TypeOfKind::Qualified); break; + case DeclSpec::TST_typeof_unqualExpr: case DeclSpec::TST_typeofExpr: { Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. - Result = S.BuildTypeofExprType(E); + Result = S.BuildTypeofExprType(E, DS.getTypeSpecType() == + DeclSpec::TST_typeof_unqualExpr + ? TypeOfKind::Unqualified + : TypeOfKind::Qualified); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -1628,12 +1652,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; } - case DeclSpec::TST_underlyingType: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait: +#include "clang/Basic/TransformTypeTraits.def" Result = S.GetTypeFromParser(DS.getRepAsType()); - assert(!Result.isNull() && "Didn't get a type for __underlying_type?"); - Result = S.BuildUnaryTransformType(Result, - UnaryTransformType::EnumUnderlyingType, - DS.getTypeSpecTypeLoc()); + assert(!Result.isNull() && "Didn't get a type for the transformation?"); + Result = S.BuildUnaryTransformType( + Result, TSTToUnaryTransformType(DS.getTypeSpecType()), + DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -2158,7 +2183,7 @@ QualType Sema::BuildPointerType(QualType T, return QualType(); } - if (getLangOpts().HLSL) { + if (getLangOpts().HLSL && Loc.isValid()) { Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0; return QualType(); } @@ -2228,7 +2253,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return QualType(); } - if (getLangOpts().HLSL) { + if (getLangOpts().HLSL && Loc.isValid()) { Diag(Loc, diag::err_hlsl_pointers_unsupported) << 1; return QualType(); } @@ -2379,6 +2404,23 @@ static ExprResult checkArraySize(Sema &S, Expr *&ArraySize, return R; } +bool Sema::checkArrayElementAlignment(QualType EltTy, SourceLocation Loc) { + EltTy = Context.getBaseElementType(EltTy); + if (EltTy->isIncompleteType() || EltTy->isDependentType() || + EltTy->isUndeducedType()) + return true; + + CharUnits Size = Context.getTypeSizeInChars(EltTy); + CharUnits Alignment = Context.getTypeAlignInChars(EltTy); + + if (Size.isMultipleOf(Alignment)) + return true; + + Diag(Loc, diag::err_array_element_alignment) + << EltTy << Size.getQuantity() << Alignment.getQuantity(); + return false; +} + /// Build an array type. /// /// \param T The type of each element in the array. @@ -2462,6 +2504,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } + if (!checkArrayElementAlignment(T, Loc)) + return QualType(); + // Do placeholder conversions on the array size expression. if (ArraySize && ArraySize->hasPlaceholderType()) { ExprResult Result = CheckPlaceholderExpr(ArraySize); @@ -2584,12 +2629,10 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, if (T->isVariableArrayType() && !Context.getTargetInfo().isVLASupported()) { // CUDA device code and some other targets don't support VLAs. - targetDiag(Loc, (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) - ? diag::err_cuda_vla - : diag::err_vla_unsupported) - << ((getLangOpts().CUDA && getLangOpts().CUDAIsDevice) - ? CurrentCUDATarget() - : CFT_InvalidTarget); + bool IsCUDADevice = (getLangOpts().CUDA && getLangOpts().CUDAIsDevice); + targetDiag(Loc, + IsCUDADevice ? diag::err_cuda_vla : diag::err_vla_unsupported) + << (IsCUDADevice ? CurrentCUDATarget() : 0); } // If this is not C99, diagnose array size modifiers on non-VLAs. @@ -2621,17 +2664,28 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, // can't already be a vector. if ((!CurType->isDependentType() && (!CurType->isBuiltinType() || CurType->isBooleanType() || - (!CurType->isIntegerType() && !CurType->isRealFloatingType()))) || + (!CurType->isIntegerType() && !CurType->isRealFloatingType())) && + !CurType->isBitIntType()) || CurType->isArrayType()) { Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << CurType; return QualType(); } + // Only support _BitInt elements with byte-sized power of 2 NumBits. + if (CurType->isBitIntType()) { + unsigned NumBits = CurType->getAs<BitIntType>()->getNumBits(); + if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) { + Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type) + << (NumBits < 8); + return QualType(); + } + } if (SizeExpr->isTypeDependent() || SizeExpr->isValueDependent()) return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc, VectorType::GenericVector); - Optional<llvm::APSInt> VecSize = SizeExpr->getIntegerConstantExpr(Context); + std::optional<llvm::APSInt> VecSize = + SizeExpr->getIntegerConstantExpr(Context); if (!VecSize) { Diag(AttrLoc, diag::err_attribute_argument_type) << "vector_size" << AANT_ArgumentIntegerConstant @@ -2697,8 +2751,19 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return QualType(); } + // Only support _BitInt elements with byte-sized power of 2 NumBits. + if (T->isBitIntType()) { + unsigned NumBits = T->getAs<BitIntType>()->getNumBits(); + if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) { + Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type) + << (NumBits < 8); + return QualType(); + } + } + if (!ArraySize->isTypeDependent() && !ArraySize->isValueDependent()) { - Optional<llvm::APSInt> vecSize = ArraySize->getIntegerConstantExpr(Context); + std::optional<llvm::APSInt> vecSize = + ArraySize->getIntegerConstantExpr(Context); if (!vecSize) { Diag(AttrLoc, diag::err_attribute_argument_type) << "ext_vector_type" << AANT_ArgumentIntegerConstant @@ -2744,8 +2809,9 @@ QualType Sema::BuildMatrixType(QualType ElementTy, Expr *NumRows, Expr *NumCols, return Context.getDependentSizedMatrixType(ElementTy, NumRows, NumCols, AttrLoc); - Optional<llvm::APSInt> ValueRows = NumRows->getIntegerConstantExpr(Context); - Optional<llvm::APSInt> ValueColumns = + std::optional<llvm::APSInt> ValueRows = + NumRows->getIntegerConstantExpr(Context); + std::optional<llvm::APSInt> ValueColumns = NumCols->getIntegerConstantExpr(Context); auto const RowRange = NumRows->getSourceRange(); @@ -2810,7 +2876,8 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { } // Functions cannot return half FP. - if (T->isHalfType() && !getLangOpts().HalfArgsAndReturns) { + if (T->isHalfType() && !getLangOpts().NativeHalfArgsAndReturns && + !Context.getTargetInfo().allowHalfArgsAndReturns()) { Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 << FixItHint::CreateInsertion(Loc, "*"); return true; @@ -2834,6 +2901,8 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { if (T.isVolatileQualified() && getLangOpts().CPlusPlus20) Diag(Loc, diag::warn_deprecated_volatile_return) << T; + if (T.getAddressSpace() != LangAS::Default && getLangOpts().HLSL) + return true; return false; } @@ -2916,7 +2985,8 @@ QualType Sema::BuildFunctionType(QualType T, if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; - } else if (ParamType->isHalfType() && !getLangOpts().HalfArgsAndReturns) { + } else if (ParamType->isHalfType() && !getLangOpts().NativeHalfArgsAndReturns && + !Context.getTargetInfo().allowHalfArgsAndReturns()) { // Disallow half FP arguments. Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 << FixItHint::CreateInsertion(Loc, "*"); @@ -2992,7 +3062,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, return QualType(); } - if (getLangOpts().HLSL) { + if (getLangOpts().HLSL && Loc.isValid()) { Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0; return QualType(); } @@ -3540,7 +3610,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, !D.getNumTypeObjects() && D.getDeclSpec().getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorContext::TemplateTypeArg: Error = 10; // Template type argument break; @@ -3565,7 +3635,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType && !Auto->isDecltypeAuto()) break; // auto(x) - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorContext::TypeName: case DeclaratorContext::Association: Error = 15; // Generic @@ -3834,7 +3904,7 @@ static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) { case DeclaratorChunk::Paren: if (&C == &Paren) continue; - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorChunk::Pointer: StartsWithDeclaratorId = false; continue; @@ -4604,7 +4674,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } // Determine whether we should infer _Nonnull on pointer types. - Optional<NullabilityKind> inferNullability; + std::optional<NullabilityKind> inferNullability; bool inferNullabilityCS = false; bool inferNullabilityInnerOnly = false; bool inferNullabilityInnerOnlyComplete = false; @@ -4637,8 +4707,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // inner pointers. complainAboutMissingNullability = CAMN_InnerPointers; - if (T->canHaveNullability(/*ResultIfUnknown*/false) && - !T->getNullability(S.Context)) { + if (T->canHaveNullability(/*ResultIfUnknown*/ false) && + !T->getNullability()) { // Note that we allow but don't require nullability on dependent types. ++NumPointersRemaining; } @@ -4674,7 +4744,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::TrailingReturn: case DeclaratorContext::TrailingReturnVar: isFunctionOrMethod = true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorContext::Member: if (state.getDeclarator().isObjCIvar() && !isFunctionOrMethod) { @@ -4683,12 +4753,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } // Weak properties are inferred to be nullable. - if (state.getDeclarator().isObjCWeakProperty() && inAssumeNonNullRegion) { - inferNullability = NullabilityKind::Nullable; + if (state.getDeclarator().isObjCWeakProperty()) { + // Weak properties cannot be nonnull, and should not complain about + // missing nullable attributes during completeness checks. + complainAboutMissingNullability = CAMN_No; + if (inAssumeNonNullRegion) { + inferNullability = NullabilityKind::Nullable; + } break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorContext::File: case DeclaratorContext::KNRTypeList: { @@ -4843,7 +4918,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case CAMN_InnerPointers: if (NumPointersRemaining == 0) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case CAMN_Yes: checkNullabilityConsistency(S, pointerKind, pointerLoc, pointerEndLoc); @@ -4854,8 +4929,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // If the type itself could have nullability but does not, infer pointer // nullability and perform consistency checking. if (S.CodeSynthesisContexts.empty()) { - if (T->canHaveNullability(/*ResultIfUnknown*/false) && - !T->getNullability(S.Context)) { + if (T->canHaveNullability(/*ResultIfUnknown*/ false) && + !T->getNullability()) { if (isVaList(T)) { // Record that we've seen a pointer, but do nothing else. if (NumPointersRemaining > 0) @@ -4878,9 +4953,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } - if (complainAboutMissingNullability == CAMN_Yes && - T->isArrayType() && !T->getNullability(S.Context) && !isVaList(T) && - D.isPrototypeContext() && + if (complainAboutMissingNullability == CAMN_Yes && T->isArrayType() && + !T->getNullability() && !isVaList(T) && D.isPrototypeContext() && !hasOuterPointerLikeChunk(D, D.getNumTypeObjects())) { checkNullabilityConsistency(S, SimplePointerKind::Array, D.getDeclSpec().getTypeSpecTypeLoc()); @@ -5152,7 +5226,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, << T << 0 /*pointer hint*/; D.setInvalidType(true); } - } else if (!S.getLangOpts().HalfArgsAndReturns) { + } else if (!S.getLangOpts().NativeHalfArgsAndReturns && + !S.Context.getTargetInfo().allowHalfArgsAndReturns()) { S.Diag(D.getIdentifierLoc(), diag::err_parameters_retval_cannot_have_fp16_type) << 1; D.setInvalidType(true); @@ -5301,14 +5376,19 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } else { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" attribute. Scan - // for this attribute now. - if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) - if (!D.getDeclarationAttributes().hasAttribute( - ParsedAttr::AT_Overloadable) && - !D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) && - !D.getDeclSpec().getAttributes().hasAttribute( - ParsedAttr::AT_Overloadable)) + // for this attribute now. We also allow it in C2x per WG14 N2975. + if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) { + if (LangOpts.C2x) + S.Diag(FTI.getEllipsisLoc(), + diag::warn_c17_compat_ellipsis_only_parameter); + else if (!D.getDeclarationAttributes().hasAttribute( + ParsedAttr::AT_Overloadable) && + !D.getAttributes().hasAttribute( + ParsedAttr::AT_Overloadable) && + !D.getDeclSpec().getAttributes().hasAttribute( + ParsedAttr::AT_Overloadable)) S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_param); + } if (FTI.NumParams && FTI.Params[0].Param == nullptr) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function @@ -5384,16 +5464,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(); Param->setInvalidDecl(); } - } else if (!S.getLangOpts().HalfArgsAndReturns) { + } else if (!S.getLangOpts().NativeHalfArgsAndReturns && + !S.Context.getTargetInfo().allowHalfArgsAndReturns()) { S.Diag(Param->getLocation(), diag::err_parameters_retval_cannot_have_fp16_type) << 0; D.setInvalidType(); } } else if (!FTI.hasPrototype) { - if (ParamTy->isPromotableIntegerType()) { + if (Context.isPromotableIntegerType(ParamTy)) { ParamTy = Context.getPromotedIntegerType(ParamTy); Param->setKNRPromoted(true); - } else if (const BuiltinType* BTy = ParamTy->getAs<BuiltinType>()) { + } else if (const BuiltinType *BTy = ParamTy->getAs<BuiltinType>()) { if (BTy->getKind() == BuiltinType::Float) { ParamTy = Context.DoubleTy; Param->setKNRPromoted(true); @@ -5538,7 +5619,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // in ClsType; hence we wrap ClsType into an ElaboratedType. // NOTE: in particular, no wrap occurs if ClsType already is an // Elaborated, DependentName, or DependentTemplateSpecialization. - if (NNSPrefix && isa<TemplateSpecializationType>(NNS->getAsType())) + if (isa<TemplateSpecializationType>(NNS->getAsType())) ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType); break; } @@ -5775,7 +5856,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, << T << D.getSourceRange(); D.setEllipsisLoc(SourceLocation()); } else { - T = Context.getPackExpansionType(T, None, /*ExpectPackInType=*/false); + T = Context.getPackExpansionType(T, std::nullopt, + /*ExpectPackInType=*/false); } break; case DeclaratorContext::TemplateParam: @@ -5788,7 +5870,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // parameter packs in the type of the non-type template parameter, then // it expands those parameter packs. if (T->containsUnexpandedParameterPack()) - T = Context.getPackExpansionType(T, None); + T = Context.getPackExpansionType(T, std::nullopt); else S.Diag(D.getEllipsisLoc(), LangOpts.CPlusPlus11 @@ -5974,6 +6056,21 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL, TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr())); } +static void fillMatrixTypeLoc(MatrixTypeLoc MTL, + const ParsedAttributesView &Attrs) { + for (const ParsedAttr &AL : Attrs) { + if (AL.getKind() == ParsedAttr::AT_MatrixType) { + MTL.setAttrNameLoc(AL.getLoc()); + MTL.setAttrRowOperand(AL.getArgAsExpr(0)); + MTL.setAttrColumnOperand(AL.getArgAsExpr(1)); + MTL.setAttrOperandParensRange(SourceRange()); + return; + } + } + + llvm_unreachable("no matrix_type attribute found at the expected location!"); +} + namespace { class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> { Sema &SemaRef; @@ -6048,18 +6145,20 @@ namespace { } void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { - assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr); + assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr || + DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualExpr); TL.setTypeofLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); } void VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { - assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType); + assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType || + DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualType); TL.setTypeofLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); assert(DS.getRepAsType()); TypeSourceInfo *TInfo = nullptr; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); - TL.setUnderlyingTInfo(TInfo); + TL.setUnmodifiedTInfo(TInfo); } void VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { assert(DS.getTypeSpecType() == DeclSpec::TST_decltype); @@ -6067,8 +6166,7 @@ namespace { TL.setRParenLoc(DS.getTypeofParensRange().getEnd()); } void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { - // FIXME: This holds only because we only have one unary transform. - assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType); + assert(DS.isTransformTypeTrait(DS.getTypeSpecType())); TL.setKWLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); assert(DS.getRepAsType()); @@ -6090,19 +6188,19 @@ namespace { } } void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { - ElaboratedTypeKeyword Keyword - = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType()); if (DS.getTypeSpecType() == TST_typename) { TypeSourceInfo *TInfo = nullptr; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); - if (TInfo) { - TL.copy(TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>()); - return; - } + if (TInfo) + if (auto ETL = TInfo->getTypeLoc().getAs<ElaboratedTypeLoc>()) { + TL.copy(ETL); + return; + } } - TL.setElaboratedKeywordLoc(Keyword != ETK_None - ? DS.getTypeSpecTypeLoc() - : SourceLocation()); + const ElaboratedType *T = TL.getTypePtr(); + TL.setElaboratedKeywordLoc(T->getKeyword() != ETK_None + ? DS.getTypeSpecTypeLoc() + : SourceLocation()); const CXXScopeSpec& SS = DS.getTypeSpecScope(); TL.setQualifierLoc(SS.getWithLocInContext(Context)); Visit(TL.getNextTypeLoc().getUnqualifiedLoc()); @@ -6158,6 +6256,9 @@ namespace { void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } + void VisitUsingTypeLoc(UsingTypeLoc TL) { + TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); + } void VisitAtomicTypeLoc(AtomicTypeLoc TL) { // An AtomicTypeLoc can come from either an _Atomic(...) type specifier // or an _Atomic qualifier. @@ -6339,6 +6440,9 @@ namespace { VisitDependentSizedExtVectorTypeLoc(DependentSizedExtVectorTypeLoc TL) { TL.setNameLoc(Chunk.Loc); } + void VisitMatrixTypeLoc(MatrixTypeLoc TL) { + fillMatrixTypeLoc(TL, Chunk.getAttrs()); + } void VisitTypeLoc(TypeLoc TL) { llvm_unreachable("unsupported TypeLoc kind in declarator!"); @@ -6386,21 +6490,6 @@ fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL, "no address_space attribute found at the expected location!"); } -static void fillMatrixTypeLoc(MatrixTypeLoc MTL, - const ParsedAttributesView &Attrs) { - for (const ParsedAttr &AL : Attrs) { - if (AL.getKind() == ParsedAttr::AT_MatrixType) { - MTL.setAttrNameLoc(AL.getLoc()); - MTL.setAttrRowOperand(AL.getArgAsExpr(0)); - MTL.setAttrColumnOperand(AL.getArgAsExpr(1)); - MTL.setAttrOperandParensRange(SourceRange()); - return; - } - } - - llvm_unreachable("no matrix_type attribute found at the expected location!"); -} - /// Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. @@ -6432,29 +6521,42 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, CurrTL = ATL.getValueLoc().getUnqualifiedLoc(); } - while (MacroQualifiedTypeLoc TL = CurrTL.getAs<MacroQualifiedTypeLoc>()) { - TL.setExpansionLoc( - State.getExpansionLocForMacroQualifiedType(TL.getTypePtr())); - CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); - } + bool HasDesugaredTypeLoc = true; + while (HasDesugaredTypeLoc) { + switch (CurrTL.getTypeLocClass()) { + case TypeLoc::MacroQualified: { + auto TL = CurrTL.castAs<MacroQualifiedTypeLoc>(); + TL.setExpansionLoc( + State.getExpansionLocForMacroQualifiedType(TL.getTypePtr())); + CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); + break; + } - while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) { - fillAttributedTypeLoc(TL, State); - CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); - } + case TypeLoc::Attributed: { + auto TL = CurrTL.castAs<AttributedTypeLoc>(); + fillAttributedTypeLoc(TL, State); + CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); + break; + } - while (DependentAddressSpaceTypeLoc TL = - CurrTL.getAs<DependentAddressSpaceTypeLoc>()) { - fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs()); - CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc(); - } + case TypeLoc::Adjusted: + case TypeLoc::BTFTagAttributed: { + CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); + break; + } - if (MatrixTypeLoc TL = CurrTL.getAs<MatrixTypeLoc>()) - fillMatrixTypeLoc(TL, D.getTypeObject(i).getAttrs()); + case TypeLoc::DependentAddressSpace: { + auto TL = CurrTL.castAs<DependentAddressSpaceTypeLoc>(); + fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs()); + CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc(); + break; + } - // FIXME: Ordering here? - while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>()) - CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); + default: + HasDesugaredTypeLoc = false; + break; + } + } DeclaratorLocFiller(S.Context, State, D.getTypeObject(i)).Visit(CurrTL); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); @@ -6539,7 +6641,7 @@ static bool BuildAddressSpaceIndex(Sema &S, LangAS &ASIdx, const Expr *AddrSpace, SourceLocation AttrLoc) { if (!AddrSpace->isValueDependent()) { - Optional<llvm::APSInt> OptAddrSpace = + std::optional<llvm::APSInt> OptAddrSpace = AddrSpace->getIntegerConstantExpr(S.Context); if (!OptAddrSpace) { S.Diag(AttrLoc, diag::err_attribute_argument_type) @@ -6707,6 +6809,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, // The keyword-based type attributes imply which address space to use. ASIdx = S.getLangOpts().SYCLIsDevice ? Attr.asSYCLLangAS() : Attr.asOpenCLLangAS(); + if (S.getLangOpts().HLSL) + ASIdx = Attr.asHLSLLangAS(); if (ASIdx == LangAS::Default) llvm_unreachable("Invalid address space"); @@ -7158,17 +7262,25 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, } std::bitset<attr::LastAttr> Attrs; - attr::Kind NewAttrKind = A->getKind(); QualType Desugared = Type; - const AttributedType *AT = dyn_cast<AttributedType>(Type); - while (AT) { + for (;;) { + if (const TypedefType *TT = dyn_cast<TypedefType>(Desugared)) { + Desugared = TT->desugar(); + continue; + } else if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Desugared)) { + Desugared = ET->desugar(); + continue; + } + const AttributedType *AT = dyn_cast<AttributedType>(Desugared); + if (!AT) + break; Attrs[AT->getAttrKind()] = true; Desugared = AT->getModifiedType(); - AT = dyn_cast<AttributedType>(Desugared); } // You cannot specify duplicate type attributes, so if the attribute has // already been applied, flag it. + attr::Kind NewAttrKind = A->getKind(); if (Attrs[NewAttrKind]) { S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr; return true; @@ -7189,14 +7301,11 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, return true; } - // Pointer type qualifiers can only operate on pointer types, but not - // pointer-to-member types. - // - // FIXME: Should we really be disallowing this attribute if there is any - // type sugar between it and the pointer (other than attributes)? Eg, this - // disallows the attribute on a parenthesized pointer. - // And if so, should we really allow *any* type attribute? + // Check the raw (i.e., desugared) Canonical type to see if it + // is a pointer type. if (!isa<PointerType>(Desugared)) { + // Pointer type qualifiers can only operate on pointer types, but not + // pointer-to-member types. if (Type->isMemberPointerType()) S.Diag(PAttr.getLoc(), diag::err_attribute_no_member_pointers) << PAttr; else @@ -7206,7 +7315,8 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, // Add address space to type based on its attributes. LangAS ASIdx = LangAS::Default; - uint64_t PtrWidth = S.Context.getTargetInfo().getPointerWidth(0); + uint64_t PtrWidth = + S.Context.getTargetInfo().getPointerWidth(LangAS::Default); if (PtrWidth == 32) { if (Attrs[attr::Ptr64]) ASIdx = LangAS::ptr64; @@ -7300,7 +7410,7 @@ static bool checkNullabilityTypeSpecifier(TypeProcessingState &state, // This (unlike the code above) looks through typedefs that might // have nullability specifiers on them, which means we cannot // provide a useful Fix-It. - if (auto existingNullability = desugared->getNullability(S.Context)) { + if (auto existingNullability = desugared->getNullability()) { if (nullability != *existingNullability) { S.Diag(nullabilityLoc, diag::err_nullability_conflicting) << DiagNullabilityKind(nullability, isContextSensitive) @@ -7399,7 +7509,7 @@ static bool checkObjCKindOfType(TypeProcessingState &state, QualType &type, // If we started with an object pointer type, rebuild it. if (ptrType) { equivType = S.Context.getObjCObjectPointerType(equivType); - if (auto nullability = type->getNullability(S.Context)) { + if (auto nullability = type->getNullability()) { // We create a nullability attribute from the __kindof attribute. // Make sure that will make sense. assert(attr.getAttributeSpellingListIndex() == 0 && @@ -7714,7 +7824,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, case EST_NoexceptTrue: case EST_NoThrow: // Exception spec doesn't conflict with nothrow, so don't warn. - LLVM_FALLTHROUGH; + [[fallthrough]]; case EST_Unparsed: case EST_Uninstantiated: case EST_DependentNoexcept: @@ -7853,7 +7963,7 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, CallingConv DefaultCC = Context.getDefaultCallingConvention(IsVariadic, IsStatic); - if (CurCC != DefaultCC || DefaultCC == ToCC) + if (CurCC != DefaultCC) return; if (hasExplicitCallingConv(T)) @@ -7960,7 +8070,7 @@ static bool verifyValidIntegerConstantExpr(Sema &S, const ParsedAttr &Attr, llvm::APSInt &Result) { const auto *AttrExpr = Attr.getArgAsExpr(0); if (!AttrExpr->isTypeDependent()) { - if (Optional<llvm::APSInt> Res = + if (std::optional<llvm::APSInt> Res = AttrExpr->getIntegerConstantExpr(S.Context)) { Result = *Res; return true; @@ -8315,6 +8425,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case ParsedAttr::AT_OpenCLLocalAddressSpace: case ParsedAttr::AT_OpenCLConstantAddressSpace: case ParsedAttr::AT_OpenCLGenericAddressSpace: + case ParsedAttr::AT_HLSLGroupSharedAddressSpace: case ParsedAttr::AT_AddressSpace: HandleAddressSpaceTypeAttribute(type, attr, state); attr.setUsedAsTypeAttr(); @@ -8443,7 +8554,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // clang, so revert to attribute-based handling for C. if (!state.getSema().getLangOpts().CPlusPlus) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; FUNCTION_TYPE_ATTRS_CASELIST: attr.setUsedAsTypeAttr(); @@ -9100,29 +9211,23 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, TagDecl *OwnedTagDecl) { if (T.isNull()) return T; - NestedNameSpecifier *NNS; - if (SS.isValid()) - NNS = SS.getScopeRep(); - else { - if (Keyword == ETK_None) - return T; - NNS = nullptr; - } - return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl); + return Context.getElaboratedType( + Keyword, SS.isValid() ? SS.getScopeRep() : nullptr, T, OwnedTagDecl); } -QualType Sema::BuildTypeofExprType(Expr *E) { +QualType Sema::BuildTypeofExprType(Expr *E, TypeOfKind Kind) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (!getLangOpts().CPlusPlus && E->refersToBitField()) - Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 2; + Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) + << (Kind == TypeOfKind::Unqualified ? 3 : 2); if (!E->isTypeDependent()) { QualType T = E->getType(); if (const TagType *TT = T->getAs<TagType>()) DiagnoseUseOfDecl(TT->getDecl(), E->getExprLoc()); } - return Context.getTypeOfExprType(E); + return Context.getTypeOfExprType(E, Kind); } /// getDecltypeForExpr - Given an expr, will return the decltype for @@ -9207,39 +9312,257 @@ QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) { return Context.getDecltypeType(E, getDecltypeForExpr(E)); } -QualType Sema::BuildUnaryTransformType(QualType BaseType, - UnaryTransformType::UTTKind UKind, - SourceLocation Loc) { - switch (UKind) { - case UnaryTransformType::EnumUnderlyingType: - if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) { - Diag(Loc, diag::err_only_enums_have_underlying_types); - return QualType(); - } else { - QualType Underlying = BaseType; - if (!BaseType->isDependentType()) { - // The enum could be incomplete if we're parsing its definition or - // recovering from an error. - NamedDecl *FwdDecl = nullptr; - if (BaseType->isIncompleteType(&FwdDecl)) { - Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType; - Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl; - return QualType(); - } +static QualType GetEnumUnderlyingType(Sema &S, QualType BaseType, + SourceLocation Loc) { + assert(BaseType->isEnumeralType()); + EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl(); + assert(ED && "EnumType has no EnumDecl"); - EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl(); - assert(ED && "EnumType has no EnumDecl"); + S.DiagnoseUseOfDecl(ED, Loc); - DiagnoseUseOfDecl(ED, Loc); + QualType Underlying = ED->getIntegerType(); + assert(!Underlying.isNull()); - Underlying = ED->getIntegerType(); - assert(!Underlying.isNull()); - } - return Context.getUnaryTransformType(BaseType, Underlying, - UnaryTransformType::EnumUnderlyingType); + return Underlying; +} + +QualType Sema::BuiltinEnumUnderlyingType(QualType BaseType, + SourceLocation Loc) { + if (!BaseType->isEnumeralType()) { + Diag(Loc, diag::err_only_enums_have_underlying_types); + return QualType(); + } + + // The enum could be incomplete if we're parsing its definition or + // recovering from an error. + NamedDecl *FwdDecl = nullptr; + if (BaseType->isIncompleteType(&FwdDecl)) { + Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType; + Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl; + return QualType(); + } + + return GetEnumUnderlyingType(*this, BaseType, Loc); +} + +QualType Sema::BuiltinAddPointer(QualType BaseType, SourceLocation Loc) { + QualType Pointer = BaseType.isReferenceable() || BaseType->isVoidType() + ? BuildPointerType(BaseType.getNonReferenceType(), Loc, + DeclarationName()) + : BaseType; + + return Pointer.isNull() ? QualType() : Pointer; +} + +QualType Sema::BuiltinRemovePointer(QualType BaseType, SourceLocation Loc) { + // We don't want block pointers or ObjectiveC's id type. + if (!BaseType->isAnyPointerType() || BaseType->isObjCIdType()) + return BaseType; + + return BaseType->getPointeeType(); +} + +QualType Sema::BuiltinDecay(QualType BaseType, SourceLocation Loc) { + QualType Underlying = BaseType.getNonReferenceType(); + if (Underlying->isArrayType()) + return Context.getDecayedType(Underlying); + + if (Underlying->isFunctionType()) + return BuiltinAddPointer(BaseType, Loc); + + SplitQualType Split = Underlying.getSplitUnqualifiedType(); + // std::decay is supposed to produce 'std::remove_cv', but since 'restrict' is + // in the same group of qualifiers as 'const' and 'volatile', we're extending + // '__decay(T)' so that it removes all qualifiers. + Split.Quals.removeCVRQualifiers(); + return Context.getQualifiedType(Split); +} + +QualType Sema::BuiltinAddReference(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + assert(LangOpts.CPlusPlus); + QualType Reference = + BaseType.isReferenceable() + ? BuildReferenceType(BaseType, + UKind == UnaryTransformType::AddLvalueReference, + Loc, DeclarationName()) + : BaseType; + return Reference.isNull() ? QualType() : Reference; +} + +QualType Sema::BuiltinRemoveExtent(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + if (UKind == UnaryTransformType::RemoveAllExtents) + return Context.getBaseElementType(BaseType); + + if (const auto *AT = Context.getAsArrayType(BaseType)) + return AT->getElementType(); + + return BaseType; +} + +QualType Sema::BuiltinRemoveReference(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + assert(LangOpts.CPlusPlus); + QualType T = BaseType.getNonReferenceType(); + if (UKind == UTTKind::RemoveCVRef && + (T.isConstQualified() || T.isVolatileQualified())) { + Qualifiers Quals; + QualType Unqual = Context.getUnqualifiedArrayType(T, Quals); + Quals.removeConst(); + Quals.removeVolatile(); + T = Context.getQualifiedType(Unqual, Quals); + } + return T; +} + +QualType Sema::BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + if ((BaseType->isReferenceType() && UKind != UTTKind::RemoveRestrict) || + BaseType->isFunctionType()) + return BaseType; + + Qualifiers Quals; + QualType Unqual = Context.getUnqualifiedArrayType(BaseType, Quals); + + if (UKind == UTTKind::RemoveConst || UKind == UTTKind::RemoveCV) + Quals.removeConst(); + if (UKind == UTTKind::RemoveVolatile || UKind == UTTKind::RemoveCV) + Quals.removeVolatile(); + if (UKind == UTTKind::RemoveRestrict) + Quals.removeRestrict(); + + return Context.getQualifiedType(Unqual, Quals); +} + +static QualType ChangeIntegralSignedness(Sema &S, QualType BaseType, + bool IsMakeSigned, + SourceLocation Loc) { + if (BaseType->isEnumeralType()) { + QualType Underlying = GetEnumUnderlyingType(S, BaseType, Loc); + if (auto *BitInt = dyn_cast<BitIntType>(Underlying)) { + unsigned int Bits = BitInt->getNumBits(); + if (Bits > 1) + return S.Context.getBitIntType(!IsMakeSigned, Bits); + + S.Diag(Loc, diag::err_make_signed_integral_only) + << IsMakeSigned << /*_BitInt(1)*/ true << BaseType << 1 << Underlying; + return QualType(); + } + if (Underlying->isBooleanType()) { + S.Diag(Loc, diag::err_make_signed_integral_only) + << IsMakeSigned << /*_BitInt(1)*/ false << BaseType << 1 + << Underlying; + return QualType(); } } - llvm_unreachable("unknown unary transform type"); + + bool Int128Unsupported = !S.Context.getTargetInfo().hasInt128Type(); + std::array<CanQualType *, 6> AllSignedIntegers = { + &S.Context.SignedCharTy, &S.Context.ShortTy, &S.Context.IntTy, + &S.Context.LongTy, &S.Context.LongLongTy, &S.Context.Int128Ty}; + ArrayRef<CanQualType *> AvailableSignedIntegers( + AllSignedIntegers.data(), AllSignedIntegers.size() - Int128Unsupported); + std::array<CanQualType *, 6> AllUnsignedIntegers = { + &S.Context.UnsignedCharTy, &S.Context.UnsignedShortTy, + &S.Context.UnsignedIntTy, &S.Context.UnsignedLongTy, + &S.Context.UnsignedLongLongTy, &S.Context.UnsignedInt128Ty}; + ArrayRef<CanQualType *> AvailableUnsignedIntegers(AllUnsignedIntegers.data(), + AllUnsignedIntegers.size() - + Int128Unsupported); + ArrayRef<CanQualType *> *Consider = + IsMakeSigned ? &AvailableSignedIntegers : &AvailableUnsignedIntegers; + + uint64_t BaseSize = S.Context.getTypeSize(BaseType); + auto *Result = + llvm::find_if(*Consider, [&S, BaseSize](const CanQual<Type> *T) { + return BaseSize == S.Context.getTypeSize(T->getTypePtr()); + }); + + assert(Result != Consider->end()); + return QualType((*Result)->getTypePtr(), 0); +} + +QualType Sema::BuiltinChangeSignedness(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + bool IsMakeSigned = UKind == UnaryTransformType::MakeSigned; + if ((!BaseType->isIntegerType() && !BaseType->isEnumeralType()) || + BaseType->isBooleanType() || + (BaseType->isBitIntType() && + BaseType->getAs<BitIntType>()->getNumBits() < 2)) { + Diag(Loc, diag::err_make_signed_integral_only) + << IsMakeSigned << BaseType->isBitIntType() << BaseType << 0; + return QualType(); + } + + bool IsNonIntIntegral = + BaseType->isChar16Type() || BaseType->isChar32Type() || + BaseType->isWideCharType() || BaseType->isEnumeralType(); + + QualType Underlying = + IsNonIntIntegral + ? ChangeIntegralSignedness(*this, BaseType, IsMakeSigned, Loc) + : IsMakeSigned ? Context.getCorrespondingSignedType(BaseType) + : Context.getCorrespondingUnsignedType(BaseType); + if (Underlying.isNull()) + return Underlying; + return Context.getQualifiedType(Underlying, BaseType.getQualifiers()); +} + +QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + if (BaseType->isDependentType()) + return Context.getUnaryTransformType(BaseType, BaseType, UKind); + QualType Result; + switch (UKind) { + case UnaryTransformType::EnumUnderlyingType: { + Result = BuiltinEnumUnderlyingType(BaseType, Loc); + break; + } + case UnaryTransformType::AddPointer: { + Result = BuiltinAddPointer(BaseType, Loc); + break; + } + case UnaryTransformType::RemovePointer: { + Result = BuiltinRemovePointer(BaseType, Loc); + break; + } + case UnaryTransformType::Decay: { + Result = BuiltinDecay(BaseType, Loc); + break; + } + case UnaryTransformType::AddLvalueReference: + case UnaryTransformType::AddRvalueReference: { + Result = BuiltinAddReference(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::RemoveAllExtents: + case UnaryTransformType::RemoveExtent: { + Result = BuiltinRemoveExtent(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::RemoveCVRef: + case UnaryTransformType::RemoveReference: { + Result = BuiltinRemoveReference(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::RemoveConst: + case UnaryTransformType::RemoveCV: + case UnaryTransformType::RemoveRestrict: + case UnaryTransformType::RemoveVolatile: { + Result = BuiltinChangeCVRQualifiers(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::MakeSigned: + case UnaryTransformType::MakeUnsigned: { + Result = BuiltinChangeSignedness(BaseType, UKind, Loc); + break; + } + } + + return !Result.isNull() + ? Context.getUnaryTransformType(BaseType, Result, UKind) + : Result; } QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { |
