diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaType.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Sema/SemaType.cpp | 2459 |
1 files changed, 1778 insertions, 681 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaType.cpp b/contrib/llvm-project/clang/lib/Sema/SemaType.cpp index 4178024d1264..92086d7277fd 100644 --- a/contrib/llvm-project/clang/lib/Sema/SemaType.cpp +++ b/contrib/llvm-project/clang/lib/Sema/SemaType.cpp @@ -16,12 +16,16 @@ #include "clang/AST/ASTMutationListener.h" #include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" #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" #include "clang/Sema/DeclSpec.h" @@ -32,12 +36,15 @@ #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/ADT/StringExtras.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include <bitset> +#include <optional> using namespace clang; @@ -98,8 +105,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, } } - S.Diag(loc, diag::warn_type_attribute_wrong_type) << name << WhichType - << type; + S.Diag(loc, attr.isRegularKeywordAttribute() + ? diag::err_type_attribute_wrong_type + : diag::warn_type_attribute_wrong_type) + << name << WhichType << type; } // objc_gc applies to Objective-C pointers or, otherwise, to the @@ -117,14 +126,18 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, case ParsedAttr::AT_RegCall: \ case ParsedAttr::AT_Pascal: \ case ParsedAttr::AT_SwiftCall: \ + case ParsedAttr::AT_SwiftAsyncCall: \ case ParsedAttr::AT_VectorCall: \ case ParsedAttr::AT_AArch64VectorPcs: \ + case ParsedAttr::AT_AArch64SVEPcs: \ + case ParsedAttr::AT_AMDGPUKernelCall: \ case ParsedAttr::AT_MSABI: \ case ParsedAttr::AT_SysVABI: \ case ParsedAttr::AT_Pcs: \ case ParsedAttr::AT_IntelOclBicc: \ case ParsedAttr::AT_PreserveMost: \ - case ParsedAttr::AT_PreserveAll + case ParsedAttr::AT_PreserveAll: \ + case ParsedAttr::AT_M68kRTD // Function type attributes. #define FUNCTION_TYPE_ATTRS_CASELIST \ @@ -132,6 +145,12 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, case ParsedAttr::AT_NoReturn: \ case ParsedAttr::AT_Regparm: \ case ParsedAttr::AT_CmseNSCall: \ + case ParsedAttr::AT_ArmStreaming: \ + case ParsedAttr::AT_ArmStreamingCompatible: \ + case ParsedAttr::AT_ArmPreserves: \ + case ParsedAttr::AT_ArmIn: \ + case ParsedAttr::AT_ArmOut: \ + case ParsedAttr::AT_ArmInOut: \ case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: \ case ParsedAttr::AT_AnyX86NoCfCheck: \ CALLING_CONV_ATTRS_CASELIST @@ -164,12 +183,6 @@ namespace { /// DeclSpec. unsigned chunkIndex; - /// Whether there are non-trivial modifications to the decl spec. - bool trivial; - - /// Whether we saved the attributes in the decl spec. - bool hasSavedAttrs; - /// The original set of attributes on the DeclSpec. SmallVector<ParsedAttr *, 2> savedAttrs; @@ -198,8 +211,7 @@ namespace { public: TypeProcessingState(Sema &sema, Declarator &declarator) : sema(sema), declarator(declarator), - chunkIndex(declarator.getNumTypeObjects()), trivial(true), - hasSavedAttrs(false), parsedNoDeref(false) {} + chunkIndex(declarator.getNumTypeObjects()), parsedNoDeref(false) {} Sema &getSema() const { return sema; @@ -231,13 +243,12 @@ namespace { /// Save the current set of attributes on the DeclSpec. void saveDeclSpecAttrs() { // Don't try to save them multiple times. - if (hasSavedAttrs) return; + if (!savedAttrs.empty()) + return; DeclSpec &spec = getMutableDeclSpec(); - for (ParsedAttr &AL : spec.getAttributes()) - savedAttrs.push_back(&AL); - trivial &= savedAttrs.empty(); - hasSavedAttrs = true; + llvm::append_range(savedAttrs, + llvm::make_pointer_range(spec.getAttributes())); } /// Record that we had nowhere to put the given type attribute. @@ -264,6 +275,12 @@ namespace { return T; } + /// Get a BTFTagAttributed type for the btf_type_tag attribute. + QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr, + QualType WrappedType) { + return sema.Context.getBTFTagAttributedType(BTFAttr, WrappedType); + } + /// Completely replace the \c auto in \p TypeWithAuto by /// \p Replacement. Also replace \p TypeWithAuto in \c TypeAttrPair if /// necessary. @@ -322,23 +339,18 @@ namespace { bool didParseNoDeref() const { return parsedNoDeref; } ~TypeProcessingState() { - if (trivial) return; + if (savedAttrs.empty()) + return; - restoreDeclSpecAttrs(); + getMutableDeclSpec().getAttributes().clearListOnly(); + for (ParsedAttr *AL : savedAttrs) + getMutableDeclSpec().getAttributes().addAtEnd(AL); } private: DeclSpec &getMutableDeclSpec() const { return const_cast<DeclSpec&>(declarator.getDeclSpec()); } - - void restoreDeclSpecAttrs() { - assert(hasSavedAttrs); - - getMutableDeclSpec().getAttributes().clearListOnly(); - for (ParsedAttr *AL : savedAttrs) - getMutableDeclSpec().getAttributes().addAtEnd(AL); - } }; } // end anonymous namespace @@ -359,11 +371,14 @@ enum TypeAttrLocation { TAL_DeclName }; -static void processTypeAttrs(TypeProcessingState &state, QualType &type, - TypeAttrLocation TAL, ParsedAttributesView &attrs); +static void +processTypeAttrs(TypeProcessingState &state, QualType &type, + TypeAttrLocation TAL, const ParsedAttributesView &attrs, + Sema::CUDAFunctionTarget CFT = Sema::CFT_HostDevice); static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, - QualType &type); + QualType &type, + Sema::CUDAFunctionTarget CFT); static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &state, ParsedAttr &attr, QualType &type); @@ -432,7 +447,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator, if (onlyBlockPointers) continue; - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorChunk::BlockPointer: result = &ptrChunk; @@ -609,7 +624,8 @@ static void distributeFunctionTypeAttr(TypeProcessingState &state, /// distributed, false if no location was found. static bool distributeFunctionTypeAttrToInnermost( TypeProcessingState &state, ParsedAttr &attr, - ParsedAttributesView &attrList, QualType &declSpecType) { + ParsedAttributesView &attrList, QualType &declSpecType, + Sema::CUDAFunctionTarget CFT) { Declarator &declarator = state.getDeclarator(); // Put it on the innermost function chunk, if there is one. @@ -621,28 +637,20 @@ static bool distributeFunctionTypeAttrToInnermost( return true; } - return handleFunctionTypeAttr(state, attr, declSpecType); + return handleFunctionTypeAttr(state, attr, declSpecType, CFT); } /// A function type attribute was written in the decl spec. Try to /// apply it somewhere. -static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state, - ParsedAttr &attr, - QualType &declSpecType) { +static void +distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state, + ParsedAttr &attr, QualType &declSpecType, + Sema::CUDAFunctionTarget CFT) { state.saveDeclSpecAttrs(); - // C++11 attributes before the decl specifiers actually appertain to - // the declarators. Move them straight there. We don't support the - // 'put them wherever you like' semantics we allow for GNU attributes. - if (attr.isCXX11Attribute()) { - moveAttrFromListToList(attr, state.getCurrentAttributes(), - state.getDeclarator().getAttributes()); - return; - } - // Try to distribute to the innermost. if (distributeFunctionTypeAttrToInnermost( - state, attr, state.getCurrentAttributes(), declSpecType)) + state, attr, state.getCurrentAttributes(), declSpecType, CFT)) return; // If that failed, diagnose the bad attribute when the declarator is @@ -650,16 +658,18 @@ static void distributeFunctionTypeAttrFromDeclSpec(TypeProcessingState &state, state.addIgnoredTypeAttr(attr); } -/// A function type attribute was written on the declarator. Try to -/// apply it somewhere. -static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, - ParsedAttr &attr, - QualType &declSpecType) { +/// A function type attribute was written on the declarator or declaration. +/// Try to apply it somewhere. +/// `Attrs` is the attribute list containing the declaration (either of the +/// declarator or the declaration). +static void distributeFunctionTypeAttrFromDeclarator( + TypeProcessingState &state, ParsedAttr &attr, QualType &declSpecType, + Sema::CUDAFunctionTarget CFT) { Declarator &declarator = state.getDeclarator(); // Try to distribute to the innermost. if (distributeFunctionTypeAttrToInnermost( - state, attr, declarator.getAttributes(), declSpecType)) + state, attr, declarator.getAttributes(), declSpecType, CFT)) return; // If that failed, diagnose the bad attribute when the declarator is @@ -668,7 +678,7 @@ static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, state.addIgnoredTypeAttr(attr); } -/// Given that there are attributes written on the declarator +/// Given that there are attributes written on the declarator or declaration /// itself, try to distribute any type attributes to the appropriate /// declarator chunk. /// @@ -677,19 +687,20 @@ static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, /// int (f ATTR)(); /// but not necessarily this: /// int f() ATTR; +/// +/// `Attrs` is the attribute list containing the declaration (either of the +/// declarator or the declaration). static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, - QualType &declSpecType) { - // Collect all the type attributes from the declarator itself. - assert(!state.getDeclarator().getAttributes().empty() && - "declarator has no attrs!"); + QualType &declSpecType, + Sema::CUDAFunctionTarget CFT) { // The called functions in this loop actually remove things from the current // list, so iterating over the existing list isn't possible. Instead, make a // non-owning copy and iterate over that. ParsedAttributesView AttrsCopy{state.getDeclarator().getAttributes()}; for (ParsedAttr &attr : AttrsCopy) { - // Do not distribute C++11 attributes. They have strict rules for what + // Do not distribute [[]] attributes. They have strict rules for what // they appertain to. - if (attr.isCXX11Attribute()) + if (attr.isStandardAttributeSyntax() || attr.isRegularKeywordAttribute()) continue; switch (attr.getKind()) { @@ -698,7 +709,7 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, break; FUNCTION_TYPE_ATTRS_CASELIST: - distributeFunctionTypeAttrFromDeclarator(state, attr, declSpecType); + distributeFunctionTypeAttrFromDeclarator(state, attr, declSpecType, CFT); break; MS_TYPE_ATTRS_CASELIST: @@ -768,7 +779,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. @@ -836,8 +847,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()) { @@ -901,7 +912,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); @@ -950,7 +963,7 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, // Retrieve the bound. QualType bound = typeParam->getUnderlyingType(); - const auto *boundObjC = bound->getAs<ObjCObjectPointerType>(); + const auto *boundObjC = bound->castAs<ObjCObjectPointerType>(); // Determine whether the type argument is substitutable for the bound. if (typeArgObjC->isObjCIdType()) { @@ -1063,22 +1076,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(); } @@ -1106,11 +1115,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); @@ -1177,10 +1185,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; @@ -1256,24 +1265,16 @@ getImageAccess(const ParsedAttributesView &Attrs) { return OpenCLAccessAttr::Keyword_read_only; } -static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS, - AutoTypeKeyword AutoKW) { - assert(DS.isConstrainedAuto()); - TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId(); - TemplateArgumentListInfo TemplateArgsInfo; - TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc); - TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); - llvm::SmallVector<TemplateArgument, 8> TemplateArgs; - for (auto &ArgLoc : TemplateArgsInfo.arguments()) - TemplateArgs.push_back(ArgLoc.getArgument()); - return S.Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false, - /*IsPack=*/false, - cast<ConceptDecl>(TemplateId->Template.get() - .getAsTemplateDecl()), - TemplateArgs); +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 @@ -1367,40 +1368,38 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // allowed to be completely missing a declspec. This is handled in the // parser already though by it pretending to have seen an 'int' in this // case. - if (S.getLangOpts().ImplicitInt) { - // In C89 mode, we only warn if there is a completely missing declspec - // when one is not allowed. - if (DS.isEmpty()) { - S.Diag(DeclLoc, diag::ext_missing_declspec) - << DS.getSourceRange() - << FixItHint::CreateInsertion(DS.getBeginLoc(), "int"); - } + if (S.getLangOpts().isImplicitIntRequired()) { + S.Diag(DeclLoc, diag::warn_missing_type_specifier) + << DS.getSourceRange() + << FixItHint::CreateInsertion(DS.getBeginLoc(), "int"); } else if (!DS.hasTypeSpecifier()) { // C99 and C++ require a type specifier. For example, C99 6.7.2p2 says: // "At least one type specifier shall be given in the declaration // specifiers in each declaration, and in the specifier-qualifier list in // each struct declaration and type name." - if (S.getLangOpts().CPlusPlus && !DS.isTypeSpecPipe()) { + if (!S.getLangOpts().isImplicitIntAllowed() && !DS.isTypeSpecPipe()) { S.Diag(DeclLoc, diag::err_missing_type_specifier) - << DS.getSourceRange(); + << DS.getSourceRange(); - // When this occurs in C++ code, often something is very broken with the - // value being declared, poison it as invalid so we don't get chains of + // When this occurs, often something is very broken with the value + // being declared, poison it as invalid so we don't get chains of // errors. declarator.setInvalidType(true); - } else if ((S.getLangOpts().OpenCLVersion >= 200 || - S.getLangOpts().OpenCLCPlusPlus) && + } else if (S.getLangOpts().getOpenCLCompatibleVersion() >= 200 && DS.isTypeSpecPipe()) { S.Diag(DeclLoc, diag::err_missing_actual_pipe_type) - << DS.getSourceRange(); + << DS.getSourceRange(); declarator.setInvalidType(true); } else { + assert(S.getLangOpts().isImplicitIntAllowed() && + "implicit int is disabled?"); S.Diag(DeclLoc, diag::ext_missing_type_specifier) - << DS.getSourceRange(); + << DS.getSourceRange() + << FixItHint::CreateInsertion(DS.getBeginLoc(), "int"); } } - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclSpec::TST_int: { if (DS.getTypeSpecSign() != TypeSpecifierSign::Unsigned) { switch (DS.getTypeSpecWidth()) { @@ -1455,12 +1454,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; } - case DeclSpec::TST_extint: { - if (!S.Context.getTargetInfo().hasExtIntType()) - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) - << "_ExtInt"; + case DeclSpec::TST_bitint: { + if (!S.Context.getTargetInfo().hasBitIntType()) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "_BitInt"; Result = - S.BuildExtIntType(DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned, + S.BuildBitIntType(DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned, DS.getRepAsExpr(), DS.getBeginLoc()); if (Result.isNull()) { Result = Context.IntTy; @@ -1516,8 +1514,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } case DeclSpec::TST_int128: if (!S.Context.getTargetInfo().hasInt128Type() && - !S.getLangOpts().SYCLIsDevice && - !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) + !(S.getLangOpts().SYCLIsDevice || S.getLangOpts().CUDAIsDevice || + (S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice))) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__int128"; if (DS.getTypeSpecSign() == TypeSpecifierSign::Unsigned) @@ -1530,16 +1528,17 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // do not diagnose _Float16 usage to avoid false alarm. // ToDo: more precise diagnostics for CUDA. if (!S.Context.getTargetInfo().hasFloat16Type() && !S.getLangOpts().CUDA && - !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "_Float16"; Result = Context.Float16Ty; break; case DeclSpec::TST_half: Result = Context.HalfTy; break; case DeclSpec::TST_BFloat16: - if (!S.Context.getTargetInfo().hasBFloat16Type()) - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) - << "__bf16"; + if (!S.Context.getTargetInfo().hasBFloat16Type() && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice) && + !S.getLangOpts().SYCLIsDevice) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__bf16"; Result = Context.BFloat16Ty; break; case DeclSpec::TST_float: Result = Context.FloatTy; break; @@ -1548,15 +1547,32 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.LongDoubleTy; else Result = Context.DoubleTy; + if (S.getLangOpts().OpenCL) { + if (!S.getOpenCLOptions().isSupported("cl_khr_fp64", S.getLangOpts())) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension) + << 0 << Result + << (S.getLangOpts().getOpenCLCompatibleVersion() == 300 + ? "cl_khr_fp64 and __opencl_c_fp64" + : "cl_khr_fp64"); + else if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp64", S.getLangOpts())) + S.Diag(DS.getTypeSpecTypeLoc(), diag::ext_opencl_double_without_pragma); + } break; case DeclSpec::TST_float128: if (!S.Context.getTargetInfo().hasFloat128Type() && !S.getLangOpts().SYCLIsDevice && - !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__float128"; Result = Context.Float128Ty; break; + case DeclSpec::TST_ibm128: + if (!S.Context.getTargetInfo().hasIbm128Type() && + !S.getLangOpts().SYCLIsDevice && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsTargetDevice)) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__ibm128"; + Result = Context.Ibm128Ty; + break; case DeclSpec::TST_bool: Result = Context.BoolTy; // _Bool or bool break; @@ -1611,6 +1627,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()); @@ -1619,13 +1636,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, DS.getTypeSpecTypeLoc()); + Result = S.BuildTypeofExprType(E, DS.getTypeSpecType() == + DeclSpec::TST_typeof_unqualExpr + ? TypeOfKind::Unqualified + : TypeOfKind::Qualified); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -1636,19 +1660,20 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. - Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); + Result = S.BuildDecltypeType(E); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); } 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); @@ -1656,29 +1681,39 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; case DeclSpec::TST_auto: + case DeclSpec::TST_decltype_auto: { + auto AutoKW = DS.getTypeSpecType() == DeclSpec::TST_decltype_auto + ? AutoTypeKeyword::DecltypeAuto + : AutoTypeKeyword::Auto; + + ConceptDecl *TypeConstraintConcept = nullptr; + llvm::SmallVector<TemplateArgument, 8> TemplateArgs; if (DS.isConstrainedAuto()) { - Result = ConvertConstrainedAutoDeclSpecToType(S, DS, - AutoTypeKeyword::Auto); - break; + if (TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId()) { + TypeConstraintConcept = + cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()); + TemplateArgumentListInfo TemplateArgsInfo; + TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); + for (const auto &ArgLoc : TemplateArgsInfo.arguments()) + TemplateArgs.push_back(ArgLoc.getArgument()); + } else { + declarator.setInvalidType(true); + } } - Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false); + Result = S.Context.getAutoType(QualType(), AutoKW, + /*IsDependent*/ false, /*IsPack=*/false, + TypeConstraintConcept, TemplateArgs); break; + } case DeclSpec::TST_auto_type: Result = Context.getAutoType(QualType(), AutoTypeKeyword::GNUAutoType, false); break; - case DeclSpec::TST_decltype_auto: - if (DS.isConstrainedAuto()) { - Result = - ConvertConstrainedAutoDeclSpecToType(S, DS, - AutoTypeKeyword::DecltypeAuto); - break; - } - Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto, - /*IsDependent*/ false); - break; - case DeclSpec::TST_unknown_anytype: Result = Context.UnknownAnyTy; break; @@ -1723,9 +1758,34 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { if (Result->containsErrors()) declarator.setInvalidType(); - if (S.getLangOpts().OpenCL && - S.checkOpenCLDisabledTypeDeclSpec(DS, Result)) - declarator.setInvalidType(true); + if (S.getLangOpts().OpenCL) { + const auto &OpenCLOptions = S.getOpenCLOptions(); + bool IsOpenCLC30Compatible = + S.getLangOpts().getOpenCLCompatibleVersion() == 300; + // OpenCL C v3.0 s6.3.3 - OpenCL image types require __opencl_c_images + // support. + // OpenCL C v3.0 s6.2.1 - OpenCL 3d image write types requires support + // for OpenCL C 2.0, or OpenCL C 3.0 or newer and the + // __opencl_c_3d_image_writes feature. OpenCL C v3.0 API s4.2 - For devices + // that support OpenCL 3.0, cl_khr_3d_image_writes must be returned when and + // only when the optional feature is supported + if ((Result->isImageType() || Result->isSamplerT()) && + (IsOpenCLC30Compatible && + !OpenCLOptions.isSupported("__opencl_c_images", S.getLangOpts()))) { + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension) + << 0 << Result << "__opencl_c_images"; + declarator.setInvalidType(); + } else if (Result->isOCLImage3dWOType() && + !OpenCLOptions.isSupported("cl_khr_3d_image_writes", + S.getLangOpts())) { + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension) + << 0 << Result + << (IsOpenCLC30Compatible + ? "cl_khr_3d_image_writes and __opencl_c_3d_image_writes" + : "cl_khr_3d_image_writes"); + declarator.setInvalidType(); + } + } bool IsFixedPointType = DS.getTypeSpecType() == DeclSpec::TST_accum || DS.getTypeSpecType() == DeclSpec::TST_fract; @@ -1744,11 +1804,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } else if (DS.isTypeAltiVecVector()) { unsigned typeSize = static_cast<unsigned>(Context.getTypeSize(Result)); assert(typeSize > 0 && "type size for vector must be greater than 0 bits"); - VectorType::VectorKind VecKind = VectorType::AltiVecVector; + VectorKind VecKind = VectorKind::AltiVecVector; if (DS.isTypeAltiVecPixel()) - VecKind = VectorType::AltiVecPixel; + VecKind = VectorKind::AltiVecPixel; else if (DS.isTypeAltiVecBool()) - VecKind = VectorType::AltiVecBool; + VecKind = VectorKind::AltiVecBool; Result = Context.getVectorType(Result, 128/typeSize, VecKind); } @@ -1765,8 +1825,42 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // list of type attributes to be temporarily saved while the type // attributes are pushed around. // pipe attributes will be handled later ( at GetFullTypeForDeclarator ) - if (!DS.isTypeSpecPipe()) + if (!DS.isTypeSpecPipe()) { + // We also apply declaration attributes that "slide" to the decl spec. + // Ordering can be important for attributes. The decalaration attributes + // come syntactically before the decl spec attributes, so we process them + // in that order. + ParsedAttributesView SlidingAttrs; + for (ParsedAttr &AL : declarator.getDeclarationAttributes()) { + if (AL.slidesFromDeclToDeclSpecLegacyBehavior()) { + SlidingAttrs.addAtEnd(&AL); + + // For standard syntax attributes, which would normally appertain to the + // declaration here, suggest moving them to the type instead. But only + // do this for our own vendor attributes; moving other vendors' + // attributes might hurt portability. + // There's one special case that we need to deal with here: The + // `MatrixType` attribute may only be used in a typedef declaration. If + // it's being used anywhere else, don't output the warning as + // ProcessDeclAttributes() will output an error anyway. + if (AL.isStandardAttributeSyntax() && AL.isClangScope() && + !(AL.getKind() == ParsedAttr::AT_MatrixType && + DS.getStorageClassSpec() != DeclSpec::SCS_typedef)) { + S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl) + << AL; + } + } + } + // During this call to processTypeAttrs(), + // TypeProcessingState::getCurrentAttributes() will erroneously return a + // reference to the DeclSpec attributes, rather than the declaration + // attributes. However, this doesn't matter, as getCurrentAttributes() + // is only called when distributing attributes from one attribute list + // to another. Declaration attributes are always C++11 attributes, and these + // are never distributed. + processTypeAttrs(state, Result, TAL_DeclSpec, SlidingAttrs); processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes()); + } // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -1842,6 +1936,14 @@ static std::string getPrintableNameForEntity(DeclarationName Entity) { return "type name"; } +static bool isDependentOrGNUAutoType(QualType T) { + if (T->isDependentType()) + return true; + + const auto *AT = dyn_cast<AutoType>(T); + return AT && AT->isGNUAutoType(); +} + QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs, const DeclSpec *DS) { if (T.isNull()) @@ -1875,7 +1977,10 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, DiagID = diag::err_typecheck_invalid_restrict_invalid_pointee; ProblemTy = EltTy; } - } else if (!T->isDependentType()) { + } else if (!isDependentOrGNUAutoType(T)) { + // For an __auto_type variable, we may not have seen the initializer yet + // and so have no idea whether the underlying type is a pointer type or + // not. DiagID = diag::err_typecheck_invalid_restrict_not_pointer; ProblemTy = T; } @@ -2060,10 +2165,7 @@ static QualType deduceOpenCLPointeeAddrSpace(Sema &S, QualType PointeeType) { !PointeeType->isSamplerT() && !PointeeType.hasAddressSpace()) PointeeType = S.getASTContext().getAddrSpaceQualType( - PointeeType, - S.getLangOpts().OpenCLCPlusPlus || S.getLangOpts().OpenCLVersion == 200 - ? LangAS::opencl_generic - : LangAS::opencl_private); + PointeeType, S.getASTContext().getDefaultOpenCLPointeeAddrSpace()); return PointeeType; } @@ -2090,8 +2192,14 @@ QualType Sema::BuildPointerType(QualType T, } if (T->isFunctionType() && getLangOpts().OpenCL && - !getOpenCLOptions().isEnabled("__cl_clang_function_pointers")) { - Diag(Loc, diag::err_opencl_function_pointer); + !getOpenCLOptions().isAvailableOption("__cl_clang_function_pointers", + getLangOpts())) { + Diag(Loc, diag::err_opencl_function_pointer) << /*pointer*/ 0; + return QualType(); + } + + if (getLangOpts().HLSL && Loc.isValid()) { + Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0; return QualType(); } @@ -2107,6 +2215,21 @@ QualType Sema::BuildPointerType(QualType T, if (getLangOpts().OpenCL) T = deduceOpenCLPointeeAddrSpace(*this, T); + // In WebAssembly, pointers to reference types and pointers to tables are + // illegal. + if (getASTContext().getTargetInfo().getTriple().isWasm()) { + if (T.isWebAssemblyReferenceType()) { + Diag(Loc, diag::err_wasm_reference_pr) << 0; + return QualType(); + } + + // We need to desugar the type here in case T is a ParenType. + if (T->getUnqualifiedDesugaredType()->isWebAssemblyTableType()) { + Diag(Loc, diag::err_wasm_table_pr) << 0; + return QualType(); + } + } + // Build the pointer type. return Context.getPointerType(T); } @@ -2160,9 +2283,21 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return QualType(); } + if (getLangOpts().HLSL && Loc.isValid()) { + Diag(Loc, diag::err_hlsl_pointers_unsupported) << 1; + return QualType(); + } + if (checkQualifiedFunction(*this, T, Loc, QFK_Reference)) return QualType(); + if (T->isFunctionType() && getLangOpts().OpenCL && + !getOpenCLOptions().isAvailableOption("__cl_clang_function_pointers", + getLangOpts())) { + Diag(Loc, diag::err_opencl_function_pointer) << /*reference*/ 1; + return QualType(); + } + // In ARC, it is forbidden to build references to unqualified pointers. if (getLangOpts().ObjCAutoRefCount) T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true); @@ -2170,6 +2305,17 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, if (getLangOpts().OpenCL) T = deduceOpenCLPointeeAddrSpace(*this, T); + // In WebAssembly, references to reference types and tables are illegal. + if (getASTContext().getTargetInfo().getTriple().isWasm() && + T.isWebAssemblyReferenceType()) { + Diag(Loc, diag::err_wasm_reference_pr) << 1; + return QualType(); + } + if (T->isWebAssemblyTableType()) { + Diag(Loc, diag::err_wasm_table_pr) << 1; + return QualType(); + } + // Handle restrict on references. if (LValueRef) return Context.getLValueReferenceType(T, SpelledAsLValue); @@ -2200,7 +2346,7 @@ QualType Sema::BuildWritePipeType(QualType T, SourceLocation Loc) { return Context.getWritePipeType(T); } -/// Build a extended int type. +/// Build a bit-precise integer type. /// /// \param IsUnsigned Boolean representing the signedness of the type. /// @@ -2208,10 +2354,10 @@ QualType Sema::BuildWritePipeType(QualType T, SourceLocation Loc) { /// that. /// /// \param Loc Location of the keyword. -QualType Sema::BuildExtIntType(bool IsUnsigned, Expr *BitWidth, +QualType Sema::BuildBitIntType(bool IsUnsigned, Expr *BitWidth, SourceLocation Loc) { if (BitWidth->isInstantiationDependent()) - return Context.getDependentExtIntType(IsUnsigned, BitWidth); + return Context.getDependentBitIntType(IsUnsigned, BitWidth); llvm::APSInt Bits(32); ExprResult ICE = @@ -2220,24 +2366,25 @@ QualType Sema::BuildExtIntType(bool IsUnsigned, Expr *BitWidth, if (ICE.isInvalid()) return QualType(); - int64_t NumBits = Bits.getSExtValue(); + size_t NumBits = Bits.getZExtValue(); if (!IsUnsigned && NumBits < 2) { - Diag(Loc, diag::err_ext_int_bad_size) << 0; + Diag(Loc, diag::err_bit_int_bad_size) << 0; return QualType(); } if (IsUnsigned && NumBits < 1) { - Diag(Loc, diag::err_ext_int_bad_size) << 1; + Diag(Loc, diag::err_bit_int_bad_size) << 1; return QualType(); } - if (NumBits > llvm::IntegerType::MAX_INT_BITS) { - Diag(Loc, diag::err_ext_int_max_size) << IsUnsigned - << llvm::IntegerType::MAX_INT_BITS; + const TargetInfo &TI = getASTContext().getTargetInfo(); + if (NumBits > TI.getMaxBitIntWidth()) { + Diag(Loc, diag::err_bit_int_max_size) + << IsUnsigned << static_cast<uint64_t>(TI.getMaxBitIntWidth()); return QualType(); } - return Context.getExtIntType(IsUnsigned, NumBits); + return Context.getBitIntType(IsUnsigned, NumBits); } /// Check whether the specified array bound can be evaluated using the relevant @@ -2298,6 +2445,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. @@ -2313,7 +2477,7 @@ static ExprResult checkArraySize(Sema &S, Expr *&ArraySize, /// /// \returns A suitable array type, if there are no errors. Otherwise, /// returns a NULL type. -QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, +QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, SourceRange Brackets, DeclarationName Entity) { @@ -2355,12 +2519,22 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } else { // C99 6.7.5.2p1: If the element type is an incomplete or function type, // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) - if (RequireCompleteSizedType(Loc, T, + if (!T.isWebAssemblyReferenceType() && + RequireCompleteSizedType(Loc, T, diag::err_array_incomplete_or_sizeless_type)) return QualType(); } - if (T->isSizelessType()) { + // Multi-dimensional arrays of WebAssembly references are not allowed. + if (Context.getTargetInfo().getTriple().isWasm() && T->isArrayType()) { + const auto *ATy = dyn_cast<ArrayType>(T); + if (ATy && ATy->getElementType().isWebAssemblyReferenceType()) { + Diag(Loc, diag::err_wasm_reftype_multidimensional_array); + return QualType(); + } + } + + if (T->isSizelessType() && !T.isWebAssemblyReferenceType()) { Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 1 << T; return QualType(); } @@ -2381,6 +2555,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); @@ -2389,7 +2566,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } // Do lvalue-to-rvalue conversions on the array size expression. - if (ArraySize && !ArraySize->isRValue()) { + if (ArraySize && !ArraySize->isPRValue()) { ExprResult Result = DefaultLvalueConversion(ArraySize); if (Result.isInvalid()) return QualType(); @@ -2407,6 +2584,27 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } + auto IsStaticAssertLike = [](const Expr *ArraySize, ASTContext &Context) { + if (!ArraySize) + return false; + + // If the array size expression is a conditional expression whose branches + // are both integer constant expressions, one negative and one positive, + // then it's assumed to be like an old-style static assertion. e.g., + // int old_style_assert[expr ? 1 : -1]; + // We will accept any integer constant expressions instead of assuming the + // values 1 and -1 are always used. + if (const auto *CondExpr = dyn_cast_if_present<ConditionalOperator>( + ArraySize->IgnoreParenImpCasts())) { + std::optional<llvm::APSInt> LHS = + CondExpr->getLHS()->getIntegerConstantExpr(Context); + std::optional<llvm::APSInt> RHS = + CondExpr->getRHS()->getIntegerConstantExpr(Context); + return LHS && RHS && LHS->isNegative() != RHS->isNegative(); + } + return false; + }; + // VLAs always produce at least a -Wvla diagnostic, sometimes an error. unsigned VLADiag; bool VLAIsError; @@ -2420,6 +2618,18 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } else if (isSFINAEContext()) { VLADiag = diag::err_vla_in_sfinae; VLAIsError = true; + } else if (getLangOpts().OpenMP && isInOpenMPTaskUntiedContext()) { + VLADiag = diag::err_openmp_vla_in_task_untied; + VLAIsError = true; + } else if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus11 && IsStaticAssertLike(ArraySize, Context)) + VLADiag = getLangOpts().GNUMode + ? diag::ext_vla_cxx_in_gnu_mode_static_assert + : diag::ext_vla_cxx_static_assert; + else + VLADiag = getLangOpts().GNUMode ? diag::ext_vla_cxx_in_gnu_mode + : diag::ext_vla_cxx; + VLAIsError = false; } else { VLADiag = diag::ext_vla; VLAIsError = false; @@ -2427,7 +2637,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, llvm::APSInt ConstVal(Context.getTypeSize(Context.getSizeType())); if (!ArraySize) { - if (ASM == ArrayType::Star) { + if (ASM == ArraySizeModifier::Star) { Diag(Loc, VLADiag); if (VLAIsError) return QualType(); @@ -2473,13 +2683,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, << ArraySize->getSourceRange(); return QualType(); } - if (ConstVal == 0) { + if (ConstVal == 0 && !T.isWebAssemblyReferenceType()) { // GCC accepts zero sized static arrays. We allow them when // we're not in a SFINAE context. Diag(ArraySize->getBeginLoc(), isSFINAEContext() ? diag::err_typecheck_zero_array_size : diag::ext_typecheck_zero_array_size) - << ArraySize->getSourceRange(); + << 0 << ArraySize->getSourceRange(); } // Is the array too large? @@ -2490,7 +2700,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, : ConstVal.getActiveBits(); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { Diag(ArraySize->getBeginLoc(), diag::err_array_too_large) - << ConstVal.toString(10) << ArraySize->getSourceRange(); + << toString(ConstVal, 10) << ArraySize->getSourceRange(); return QualType(); } @@ -2498,22 +2708,26 @@ 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); + if (T->isVariableArrayType()) { + if (!Context.getTargetInfo().isVLASupported()) { + // CUDA device code and some other targets don't support VLAs. + bool IsCUDADevice = (getLangOpts().CUDA && getLangOpts().CUDAIsDevice); + targetDiag(Loc, + IsCUDADevice ? diag::err_cuda_vla : diag::err_vla_unsupported) + << (IsCUDADevice ? CurrentCUDATarget() : 0); + } else if (sema::FunctionScopeInfo *FSI = getCurFunction()) { + // VLAs are supported on this target, but we may need to do delayed + // checking that the VLA is not being used within a coroutine. + FSI->setHasVLA(Loc); + } } // If this is not C99, diagnose array size modifiers on non-VLAs. if (!getLangOpts().C99 && !T->isVariableArrayType() && - (ASM != ArrayType::Normal || Quals != 0)) { + (ASM != ArraySizeModifier::Normal || Quals != 0)) { Diag(Loc, getLangOpts().CPlusPlus ? diag::err_c99_array_usage_cxx : diag::ext_c99_array_usage) - << ASM; + << llvm::to_underlying(ASM); } // OpenCL v2.0 s6.12.5 - Arrays of blocks are not supported. @@ -2537,17 +2751,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 (const auto *BIT = CurType->getAs<BitIntType>()) { + unsigned NumBits = BIT->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); + VectorKind::Generic); - 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 @@ -2557,7 +2782,7 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, if (CurType->isDependentType()) return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc, - VectorType::GenericVector); + VectorKind::Generic); // vecSize is specified in bytes - convert to bits. if (!VecSize->isIntN(61)) { @@ -2575,7 +2800,7 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, return QualType(); } - if (VectorSizeBits % TypeSize) { + if (!TypeSize || VectorSizeBits % TypeSize) { Diag(AttrLoc, diag::err_attribute_invalid_size) << SizeExpr->getSourceRange(); return QualType(); @@ -2588,7 +2813,7 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, } return Context.getVectorType(CurType, VectorSizeBits / TypeSize, - VectorType::GenericVector); + VectorKind::Generic); } /// Build an ext-vector type. @@ -2603,15 +2828,29 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, // reserved data type under OpenCL v2.0 s6.1.4), we don't support selects // on bitvectors, and we have no well-defined ABI for bitvectors, so vectors // of bool aren't allowed. + // + // We explictly allow bool elements in ext_vector_type for C/C++. + bool IsNoBoolVecLang = getLangOpts().OpenCL || getLangOpts().OpenCLCPlusPlus; if ((!T->isDependentType() && !T->isIntegerType() && !T->isRealFloatingType()) || - T->isBooleanType()) { + (IsNoBoolVecLang && T->isBooleanType())) { Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T; return QualType(); } + // Only support _BitInt elements with byte-sized power of 2 NumBits. + if (T->isBitIntType()) { + unsigned NumBits = T->castAs<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 @@ -2657,8 +2896,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(); @@ -2723,7 +2963,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; @@ -2747,6 +2988,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; } @@ -2758,16 +3001,21 @@ static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes, llvm::function_ref<SourceLocation(unsigned)> getParamLoc) { assert(EPI.ExtParameterInfos && "shouldn't get here without param infos"); - bool hasCheckedSwiftCall = false; - auto checkForSwiftCC = [&](unsigned paramIndex) { - // Only do this once. - if (hasCheckedSwiftCall) return; - hasCheckedSwiftCall = true; - if (EPI.ExtInfo.getCC() == CC_Swift) return; + bool emittedError = false; + auto actualCC = EPI.ExtInfo.getCC(); + enum class RequiredCC { OnlySwift, SwiftOrSwiftAsync }; + auto checkCompatible = [&](unsigned paramIndex, RequiredCC required) { + bool isCompatible = + (required == RequiredCC::OnlySwift) + ? (actualCC == CC_Swift) + : (actualCC == CC_Swift || actualCC == CC_SwiftAsync); + if (isCompatible || emittedError) + return; S.Diag(getParamLoc(paramIndex), diag::err_swift_param_attr_not_swiftcall) - << getParameterABISpelling(EPI.ExtParameterInfos[paramIndex].getABI()); + << getParameterABISpelling(EPI.ExtParameterInfos[paramIndex].getABI()) + << (required == RequiredCC::OnlySwift); + emittedError = true; }; - for (size_t paramIndex = 0, numParams = paramTypes.size(); paramIndex != numParams; ++paramIndex) { switch (EPI.ExtParameterInfos[paramIndex].getABI()) { @@ -2778,7 +3026,7 @@ static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes, // swift_indirect_result parameters must be a prefix of the function // arguments. case ParameterABI::SwiftIndirectResult: - checkForSwiftCC(paramIndex); + checkCompatible(paramIndex, RequiredCC::SwiftOrSwiftAsync); if (paramIndex != 0 && EPI.ExtParameterInfos[paramIndex - 1].getABI() != ParameterABI::SwiftIndirectResult) { @@ -2788,12 +3036,16 @@ static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes, continue; case ParameterABI::SwiftContext: - checkForSwiftCC(paramIndex); + checkCompatible(paramIndex, RequiredCC::SwiftOrSwiftAsync); + continue; + + // SwiftAsyncContext is not limited to swiftasynccall functions. + case ParameterABI::SwiftAsyncContext: continue; // swift_error parameters must be preceded by a swift_context parameter. case ParameterABI::SwiftErrorResult: - checkForSwiftCC(paramIndex); + checkCompatible(paramIndex, RequiredCC::OnlySwift); if (paramIndex == 0 || EPI.ExtParameterInfos[paramIndex - 1].getABI() != ParameterABI::SwiftContext) { @@ -2820,11 +3072,15 @@ 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, "*"); Invalid = true; + } else if (ParamType->isWebAssemblyTableType()) { + Diag(Loc, diag::err_wasm_table_as_function_parameter); + Invalid = true; } // C++2a [dcl.fct]p4: @@ -2889,13 +3145,25 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, return QualType(); } + if (T->isFunctionType() && getLangOpts().OpenCL && + !getOpenCLOptions().isAvailableOption("__cl_clang_function_pointers", + getLangOpts())) { + Diag(Loc, diag::err_opencl_function_pointer) << /*pointer*/ 0; + return QualType(); + } + + if (getLangOpts().HLSL && Loc.isValid()) { + Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0; + return QualType(); + } + // Adjust the default free function calling convention to the default method // calling convention. bool IsCtorOrDtor = (Entity.getNameKind() == DeclarationName::CXXConstructorName) || (Entity.getNameKind() == DeclarationName::CXXDestructorName); if (T->isFunctionType()) - adjustMemberFunctionCC(T, /*IsStatic=*/false, IsCtorOrDtor, Loc); + adjustMemberFunctionCC(T, /*HasThisPointer=*/true, IsCtorOrDtor, Loc); return Context.getMemberPointerType(T, Class.getTypePtr()); } @@ -3205,31 +3473,52 @@ InventTemplateParameter(TypeProcessingState &state, QualType T, // extract its type constraints to attach to the template parameter. AutoTypeLoc AutoLoc = TrailingTSI->getTypeLoc().getContainedAutoTypeLoc(); TemplateArgumentListInfo TAL(AutoLoc.getLAngleLoc(), AutoLoc.getRAngleLoc()); - for (unsigned Idx = 0; Idx < AutoLoc.getNumArgs(); ++Idx) + bool Invalid = false; + for (unsigned Idx = 0; Idx < AutoLoc.getNumArgs(); ++Idx) { + if (D.getEllipsisLoc().isInvalid() && !Invalid && + S.DiagnoseUnexpandedParameterPack(AutoLoc.getArgLoc(Idx), + Sema::UPPC_TypeConstraint)) + Invalid = true; TAL.addArgument(AutoLoc.getArgLoc(Idx)); + } - S.AttachTypeConstraint(AutoLoc.getNestedNameSpecifierLoc(), - AutoLoc.getConceptNameInfo(), - AutoLoc.getNamedConcept(), - AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, - InventedTemplateParam, D.getEllipsisLoc()); + if (!Invalid) { + S.AttachTypeConstraint( + AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(), + AutoLoc.getNamedConcept(), + AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, + InventedTemplateParam, D.getEllipsisLoc()); + } } else { // The 'auto' appears in the decl-specifiers; we've not finished forming // TypeSourceInfo for it yet. TemplateIdAnnotation *TemplateId = D.getDeclSpec().getRepAsTemplateId(); TemplateArgumentListInfo TemplateArgsInfo; + bool Invalid = false; if (TemplateId->LAngleLoc.isValid()) { ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); + + if (D.getEllipsisLoc().isInvalid()) { + for (TemplateArgumentLoc Arg : TemplateArgsInfo.arguments()) { + if (S.DiagnoseUnexpandedParameterPack(Arg, + Sema::UPPC_TypeConstraint)) { + Invalid = true; + break; + } + } + } + } + if (!Invalid) { + S.AttachTypeConstraint( + D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context), + DeclarationNameInfo(DeclarationName(TemplateId->Name), + TemplateId->TemplateNameLoc), + cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()), + TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, + InventedTemplateParam, D.getEllipsisLoc()); } - S.AttachTypeConstraint( - D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context), - DeclarationNameInfo(DeclarationName(TemplateId->Name), - TemplateId->TemplateNameLoc), - cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()), - TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, - InventedTemplateParam, D.getEllipsisLoc()); } } @@ -3298,8 +3587,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, break; } - if (!D.getAttributes().empty()) - distributeTypeAttrsFromDeclarator(state, T); + // Note: We don't need to distribute declaration attributes (i.e. + // D.getDeclarationAttributes()) because those are always C++11 attributes, + // and those don't get distributed. + distributeTypeAttrsFromDeclarator( + state, T, SemaRef.IdentifyCUDATarget(D.getAttributes())); // Find the deduced type in this type. Look in the trailing return type if we // have one, otherwise in the DeclSpec type. @@ -3377,11 +3669,20 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, Error = 6; // Interface member. } else { switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) { - case TTK_Enum: llvm_unreachable("unhandled tag kind"); - case TTK_Struct: Error = Cxx ? 1 : 2; /* Struct member */ break; - case TTK_Union: Error = Cxx ? 3 : 4; /* Union member */ break; - case TTK_Class: Error = 5; /* Class member */ break; - case TTK_Interface: Error = 6; /* Interface member */ break; + case TagTypeKind::Enum: + llvm_unreachable("unhandled tag kind"); + case TagTypeKind::Struct: + Error = Cxx ? 1 : 2; /* Struct member */ + break; + case TagTypeKind::Union: + Error = Cxx ? 3 : 4; /* Union member */ + break; + case TagTypeKind::Class: + Error = 5; /* Class member */ + break; + case TagTypeKind::Interface: + Error = 6; /* Interface member */ + break; } } if (D.getDeclSpec().isFriendSpecified()) @@ -3409,7 +3710,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; @@ -3431,8 +3732,12 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::FunctionalCast: if (isa<DeducedTemplateSpecializationType>(Deduced)) break; - LLVM_FALLTHROUGH; + if (SemaRef.getLangOpts().CPlusPlus23 && IsCXXAutoType && + !Auto->isDecltypeAuto()) + break; // auto(x) + [[fallthrough]]; case DeclaratorContext::TypeName: + case DeclaratorContext::Association: Error = 15; // Generic break; case DeclaratorContext::File: @@ -3489,7 +3794,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, << Kind << Error << (int)SemaRef.getTemplateNameKindForDiagnostics(TN) << QualType(Deduced, 0) << AutoRange; if (auto *TD = TN.getAsTemplateDecl()) - SemaRef.Diag(TD->getLocation(), diag::note_template_decl_here); + SemaRef.NoteTemplateLocation(*TD); T = SemaRef.Context.IntTy; D.setInvalidType(true); @@ -3543,6 +3848,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::ObjCCatch: case DeclaratorContext::TemplateArg: case DeclaratorContext::TemplateTypeArg: + case DeclaratorContext::Association: DiagID = diag::err_type_defined_in_type_specifier; break; case DeclaratorContext::Prototype: @@ -3698,7 +4004,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; @@ -3805,7 +4111,8 @@ static CallingConv getCCForDeclaratorChunk( // function type. We'll diagnose the failure to apply them in // handleFunctionTypeAttr. CallingConv CC; - if (!S.CheckCallingConvAttr(AL, CC) && + if (!S.CheckCallingConvAttr(AL, CC, /*FunctionDecl=*/nullptr, + S.IdentifyCUDATarget(D.getAttributes())) && (!FTI.isVariadic || supportsVariadicCall(CC))) { return CC; } @@ -3838,8 +4145,9 @@ static CallingConv getCCForDeclaratorChunk( D.getTypeObject(I).Kind == DeclaratorChunk::MemberPointer; } else if (D.getContext() == DeclaratorContext::LambdaExpr) { // This can only be a call operator for a lambda, which is an instance - // method. - IsCXXInstanceMethod = true; + // method, unless explicitly specified as 'static'. + IsCXXInstanceMethod = + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static; } else { // We're the innermost decl chunk, so must be a function declarator. assert(D.isFunctionDeclarator()); @@ -3867,6 +4175,20 @@ static CallingConv getCCForDeclaratorChunk( break; } } + } else if (S.getLangOpts().CUDA) { + // If we're compiling CUDA/HIP code and targeting SPIR-V we need to make + // sure the kernels will be marked with the right calling convention so that + // they will be visible by the APIs that ingest SPIR-V. + llvm::Triple Triple = S.Context.getTargetInfo().getTriple(); + if (Triple.getArch() == llvm::Triple::spirv32 || + Triple.getArch() == llvm::Triple::spirv64) { + for (const ParsedAttr &AL : D.getDeclSpec().getAttributes()) { + if (AL.getKind() == ParsedAttr::AT_CUDAGlobal) { + CC = CC_OpenCLKernel; + break; + } + } + } } return CC; @@ -4102,7 +4424,7 @@ bool Sema::isCFError(RecordDecl *RD) { // NSError. CFErrorRef used to be declared with "objc_bridge" but is now // declared with "objc_bridge_mutable", so look for either one of the two // attributes. - if (RD->getTagKind() == TTK_Struct) { + if (RD->getTagKind() == TagTypeKind::Struct) { IdentifierInfo *bridgedType = nullptr; if (auto bridgeAttr = RD->getAttr<ObjCBridgeAttr>()) bridgedType = bridgeAttr->getBridgedType(); @@ -4185,8 +4507,8 @@ static void fixItNullability(Sema &S, DiagBuilderT &Diag, InsertionText = InsertionText.drop_back().drop_front(); else InsertionText = InsertionText.drop_front(); - } else if (!isIdentifierBody(NextChar[0], /*allow dollar*/true) && - !isIdentifierBody(NextChar[-1], /*allow dollar*/true)) { + } else if (!isAsciiIdentifierContinue(NextChar[0], /*allow dollar*/ true) && + !isAsciiIdentifierContinue(NextChar[-1], /*allow dollar*/ true)) { InsertionText = InsertionText.drop_back().drop_front(); } @@ -4321,7 +4643,7 @@ static bool hasOuterPointerLikeChunk(const Declarator &D, unsigned endIndex) { return false; } -static bool IsNoDerefableChunk(DeclaratorChunk Chunk) { +static bool IsNoDerefableChunk(const DeclaratorChunk &Chunk) { return (Chunk.Kind == DeclaratorChunk::Pointer || Chunk.Kind == DeclaratorChunk::Array); } @@ -4454,7 +4776,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; @@ -4487,8 +4809,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; } @@ -4524,7 +4846,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) { @@ -4533,12 +4855,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: { @@ -4581,7 +4908,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, AttrList.hasAttribute(ParsedAttr::AT_CFReturnsNotRetained); }; if (const auto *InnermostChunk = D.getInnermostNonParenChunk()) { - if (hasCFReturnsAttr(D.getAttributes()) || + if (hasCFReturnsAttr(D.getDeclarationAttributes()) || + hasCFReturnsAttr(D.getAttributes()) || hasCFReturnsAttr(InnermostChunk->getAttrs()) || hasCFReturnsAttr(D.getDeclSpec().getAttributes())) { inferNullability = NullabilityKind::Nullable; @@ -4616,6 +4944,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::TypeName: case DeclaratorContext::FunctionalCast: case DeclaratorContext::RequiresExpr: + case DeclaratorContext::Association: // Don't infer in these contexts. break; } @@ -4654,12 +4983,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // If we're supposed to infer nullability, do so now. if (inferNullability && !inferNullabilityInnerOnlyComplete) { - ParsedAttr::Syntax syntax = inferNullabilityCS - ? ParsedAttr::AS_ContextSensitiveKeyword - : ParsedAttr::AS_Keyword; + ParsedAttr::Form form = + inferNullabilityCS + ? ParsedAttr::Form::ContextSensitiveKeyword() + : ParsedAttr::Form::Keyword(false /*IsAlignAs*/, + false /*IsRegularKeywordAttribute*/); ParsedAttr *nullabilityAttr = Pool.create( S.getNullabilityKeyword(*inferNullability), SourceRange(pointerLoc), - nullptr, SourceLocation(), nullptr, 0, syntax); + nullptr, SourceLocation(), nullptr, 0, form); attrs.addAtEnd(nullabilityAttr); @@ -4691,7 +5022,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case CAMN_InnerPointers: if (NumPointersRemaining == 0) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case CAMN_Yes: checkNullabilityConsistency(S, pointerKind, pointerLoc, pointerEndLoc); @@ -4702,8 +5033,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) @@ -4726,9 +5057,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()); @@ -4741,6 +5071,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). + + // Track if the produced type matches the structure of the declarator. + // This is used later to decide if we can fill `TypeLoc` from + // `DeclaratorChunk`s. E.g. it must be false if Clang recovers from + // an error by replacing the type with `int`. + bool AreDeclaratorChunksValid = true; for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { unsigned chunkIndex = e - i - 1; state.setCurrentChunkIndex(chunkIndex); @@ -4831,33 +5167,47 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr; Expr *ArraySize = static_cast<Expr*>(ATI.NumElts); - ArrayType::ArraySizeModifier ASM; + ArraySizeModifier ASM; + + // Microsoft property fields can have multiple sizeless array chunks + // (i.e. int x[][][]). Skip all of these except one to avoid creating + // bad incomplete array types. + if (chunkIndex != 0 && !ArraySize && + D.getDeclSpec().getAttributes().hasMSPropertyAttr()) { + // This is a sizeless chunk. If the next is also, skip this one. + DeclaratorChunk &NextDeclType = D.getTypeObject(chunkIndex - 1); + if (NextDeclType.Kind == DeclaratorChunk::Array && + !NextDeclType.Arr.NumElts) + break; + } + if (ATI.isStar) - ASM = ArrayType::Star; + ASM = ArraySizeModifier::Star; else if (ATI.hasStatic) - ASM = ArrayType::Static; + ASM = ArraySizeModifier::Static; else - ASM = ArrayType::Normal; - if (ASM == ArrayType::Star && !D.isPrototypeContext()) { + ASM = ArraySizeModifier::Normal; + if (ASM == ArraySizeModifier::Star && !D.isPrototypeContext()) { // FIXME: This check isn't quite right: it allows star in prototypes // for function definitions, and disallows some edge cases detailed // in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html S.Diag(DeclType.Loc, diag::err_array_star_outside_prototype); - ASM = ArrayType::Normal; + ASM = ArraySizeModifier::Normal; D.setInvalidType(true); } // C99 6.7.5.2p1: The optional type qualifiers and the keyword static // shall appear only in a declaration of a function parameter with an // array type, ... - if (ASM == ArrayType::Static || ATI.TypeQuals) { + if (ASM == ArraySizeModifier::Static || ATI.TypeQuals) { if (!(D.isPrototypeContext() || D.getContext() == DeclaratorContext::KNRTypeList)) { - S.Diag(DeclType.Loc, diag::err_array_static_outside_prototype) << - (ASM == ArrayType::Static ? "'static'" : "type qualifier"); + S.Diag(DeclType.Loc, diag::err_array_static_outside_prototype) + << (ASM == ArraySizeModifier::Static ? "'static'" + : "type qualifier"); // Remove the 'static' and the type qualifiers. - if (ASM == ArrayType::Static) - ASM = ArrayType::Normal; + if (ASM == ArraySizeModifier::Static) + ASM = ArraySizeModifier::Normal; ATI.TypeQuals = 0; D.setInvalidType(true); } @@ -4865,32 +5215,21 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // C99 6.7.5.2p1: ... and then only in the outermost array type // derivation. if (hasOuterPointerLikeChunk(D, chunkIndex)) { - S.Diag(DeclType.Loc, diag::err_array_static_not_outermost) << - (ASM == ArrayType::Static ? "'static'" : "type qualifier"); - if (ASM == ArrayType::Static) - ASM = ArrayType::Normal; + S.Diag(DeclType.Loc, diag::err_array_static_not_outermost) + << (ASM == ArraySizeModifier::Static ? "'static'" + : "type qualifier"); + if (ASM == ArraySizeModifier::Static) + ASM = ArraySizeModifier::Normal; ATI.TypeQuals = 0; D.setInvalidType(true); } } - const AutoType *AT = T->getContainedAutoType(); - // Allow arrays of auto if we are a generic lambda parameter. - // i.e. [](auto (&array)[5]) { return array[0]; }; OK - if (AT && D.getContext() != DeclaratorContext::LambdaExprParameter) { - // We've already diagnosed this for decltype(auto). - if (!AT->isDecltypeAuto()) - S.Diag(DeclType.Loc, diag::err_illegal_decl_array_of_auto) - << getPrintableNameForEntity(Name) << T; - T = QualType(); - break; - } // Array parameters can be marked nullable as well, although it's not // necessary if they're marked 'static'. if (complainAboutMissingNullability == CAMN_Yes && !hasNullabilityAttr(DeclType.getAttrs()) && - ASM != ArrayType::Static && - D.isPrototypeContext() && + ASM != ArraySizeModifier::Static && D.isPrototypeContext() && !hasOuterPointerLikeChunk(D, chunkIndex)) { checkNullabilityConsistency(S, SimplePointerKind::Array, DeclType.Loc); } @@ -4921,6 +5260,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, : diag::err_deduced_return_type); T = Context.IntTy; D.setInvalidType(true); + AreDeclaratorChunksValid = false; } else { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::warn_cxx11_compat_deduced_return_type); @@ -4931,6 +5271,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S.Diag(D.getBeginLoc(), diag::err_trailing_return_in_parens) << T << D.getSourceRange(); D.setInvalidType(true); + // FIXME: recover and fill decls in `TypeLoc`s. + AreDeclaratorChunksValid = false; } else if (D.getName().getKind() == UnqualifiedIdKind::IK_DeductionGuideName) { if (T != Context.DependentTy) { @@ -4938,6 +5280,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, diag::err_deduction_guide_with_complex_decl) << D.getSourceRange(); D.setInvalidType(true); + // FIXME: recover and fill decls in `TypeLoc`s. + AreDeclaratorChunksValid = false; } } else if (D.getContext() != DeclaratorContext::LambdaExpr && (T.hasQualifiers() || !isa<AutoType>(T) || @@ -4948,6 +5292,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); D.setInvalidType(true); + // FIXME: recover and fill decls in `TypeLoc`s. + AreDeclaratorChunksValid = false; } T = S.GetTypeFromParser(FTI.getTrailingReturnType(), &TInfo); if (T.isNull()) { @@ -4988,18 +5334,21 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S.Diag(DeclType.Loc, diagID) << T->isFunctionType() << T; T = Context.IntTy; D.setInvalidType(true); + AreDeclaratorChunksValid = false; } // Do not allow returning half FP value. // FIXME: This really should be in BuildFunctionType. if (T->isHalfType()) { if (S.getLangOpts().OpenCL) { - if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16")) { + if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp16", + S.getLangOpts())) { S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return) << 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); @@ -5019,11 +5368,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // (s6.9.e and s6.12.5 OpenCL v2.0) except for printf. // We also allow here any toolchain reserved identifiers. if (FTI.isVariadic && - !S.getOpenCLOptions().isEnabled("__cl_clang_variadic_functions") && + !S.getOpenCLOptions().isAvailableOption( + "__cl_clang_variadic_functions", S.getLangOpts()) && !(D.getIdentifier() && ((D.getIdentifier()->getName() == "printf" && - (LangOpts.OpenCLCPlusPlus || LangOpts.OpenCLVersion >= 120)) || - D.getIdentifier()->getName().startswith("__")))) { + LangOpts.getOpenCLCompatibleVersion() >= 120) || + D.getIdentifier()->getName().starts_with("__")))) { S.Diag(D.getIdentifierLoc(), diag::err_opencl_variadic_function); D.setInvalidType(true); } @@ -5051,6 +5401,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, ObjCObjectPointerTypeLoc TLoc = TLB.push<ObjCObjectPointerTypeLoc>(T); TLoc.setStarLoc(FixitLoc); TInfo = TLB.getTypeSourceInfo(Context, T); + } else { + AreDeclaratorChunksValid = false; } D.setInvalidType(true); @@ -5137,17 +5489,29 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, FunctionType::ExtInfo EI( getCCForDeclaratorChunk(S, D, DeclType.getAttrs(), FTI, chunkIndex)); - if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus - && !LangOpts.OpenCL) { + // OpenCL disallows functions without a prototype, but it doesn't enforce + // strict prototypes as in C23 because it allows a function definition to + // have an identifier list. See OpenCL 3.0 6.11/g for more details. + if (!FTI.NumParams && !FTI.isVariadic && + !LangOpts.requiresStrictPrototypes() && !LangOpts.OpenCL) { // Simple void foo(), where the incoming T is the result type. T = Context.getFunctionNoProtoType(T, EI); } 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.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable)) + // for this attribute now. We also allow it in C23 per WG14 N2975. + if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) { + if (LangOpts.C23) + 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 @@ -5155,8 +5519,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, S.Diag(FTI.Params[0].IdentLoc, diag::err_ident_list_in_fn_declaration); D.setInvalidType(true); - // Recover by creating a K&R-style function type. - T = Context.getFunctionNoProtoType(T, EI); + // Recover by creating a K&R-style function type, if possible. + T = (!LangOpts.requiresStrictPrototypes() && !LangOpts.OpenCL) + ? Context.getFunctionNoProtoType(T, EI) + : Context.IntTy; + AreDeclaratorChunksValid = false; break; } @@ -5214,22 +5581,24 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Disallow half FP parameters. // FIXME: This really should be in BuildFunctionType. if (S.getLangOpts().OpenCL) { - if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16")) { + if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp16", + S.getLangOpts())) { S.Diag(Param->getLocation(), diag::err_opencl_invalid_param) << ParamTy << 0; 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); @@ -5351,13 +5720,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Avoid emitting extra errors if we already errored on the scope. D.setInvalidType(true); } else if (S.isDependentScopeSpecifier(SS) || - dyn_cast_or_null<CXXRecordDecl>(S.computeDeclContext(SS))) { + isa_and_nonnull<CXXRecordDecl>(S.computeDeclContext(SS))) { NestedNameSpecifier *NNS = SS.getScopeRep(); NestedNameSpecifier *NNSPrefix = NNS->getPrefix(); switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: - ClsType = Context.getDependentNameType(ETK_None, NNSPrefix, - NNS->getAsIdentifier()); + ClsType = Context.getDependentNameType( + ElaboratedTypeKeyword::None, NNSPrefix, NNS->getAsIdentifier()); break; case NestedNameSpecifier::Namespace: @@ -5374,8 +5743,9 @@ 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())) - ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType); + if (isa<TemplateSpecializationType>(NNS->getAsType())) + ClsType = Context.getElaboratedType(ElaboratedTypeKeyword::None, + NNSPrefix, ClsType); break; } } else { @@ -5389,9 +5759,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (!ClsType.isNull()) T = S.BuildMemberPointerType(T, ClsType, DeclType.Loc, D.getIdentifier()); + else + AreDeclaratorChunksValid = false; + if (T.isNull()) { T = Context.IntTy; D.setInvalidType(true); + AreDeclaratorChunksValid = false; } else if (DeclType.Mem.TypeQuals) { T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Mem.TypeQuals); } @@ -5409,10 +5783,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (T.isNull()) { D.setInvalidType(true); T = Context.IntTy; + AreDeclaratorChunksValid = false; } // See if there are any attributes on this declarator chunk. - processTypeAttrs(state, T, TAL_DeclChunk, DeclType.getAttrs()); + processTypeAttrs(state, T, TAL_DeclChunk, DeclType.getAttrs(), + S.IdentifyCUDATarget(D.getAttributes())); if (DeclType.Kind != DeclaratorChunk::Paren) { if (ExpectNoDerefChunk && !IsNoDerefableChunk(DeclType)) @@ -5427,15 +5803,16 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, diag::warn_noderef_on_non_pointer_or_array); // GNU warning -Wstrict-prototypes - // Warn if a function declaration is without a prototype. + // Warn if a function declaration or definition is without a prototype. // This warning is issued for all kinds of unprototyped function // declarations (i.e. function type typedef, function pointer etc.) // C99 6.7.5.3p14: // The empty list in a function declarator that is not part of a definition // of that function specifies that no information about the number or types // of the parameters is supplied. - if (!LangOpts.CPlusPlus && - D.getFunctionDefinitionKind() == FunctionDefinitionKind::Declaration) { + // See ActOnFinishFunctionBody() and MergeFunctionDecl() for handling of + // function declarations whose behavior changes in C23. + if (!LangOpts.requiresStrictPrototypes()) { bool IsBlock = false; for (const DeclaratorChunk &DeclType : D.type_objects()) { switch (DeclType.Kind) { @@ -5444,10 +5821,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, break; case DeclaratorChunk::Function: { const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - // We supress the warning when there's no LParen location, as this + // We suppress the warning when there's no LParen location, as this // indicates the declaration was an implicit declaration, which gets - // warned about separately via -Wimplicit-function-declaration. - if (FTI.NumParams == 0 && !FTI.isVariadic && FTI.getLParenLoc().isValid()) + // warned about separately via -Wimplicit-function-declaration. We also + // suppress the warning when we know the function has a prototype. + if (!FTI.hasPrototype && FTI.NumParams == 0 && !FTI.isVariadic && + FTI.getLParenLoc().isValid()) S.Diag(DeclType.Loc, diag::warn_strict_prototypes) << IsBlock << FixItHint::CreateInsertion(FTI.getRParenLoc(), "void"); @@ -5474,7 +5853,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // // Core issue 547 also allows cv-qualifiers on function types that are // top-level template type arguments. - enum { NonMember, Member, DeductionGuide } Kind = NonMember; + enum { + NonMember, + Member, + ExplicitObjectMember, + DeductionGuide + } Kind = NonMember; if (D.getName().getKind() == UnqualifiedIdKind::IK_DeductionGuideName) Kind = DeductionGuide; else if (!D.getCXXScopeSpec().isSet()) { @@ -5488,6 +5872,18 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, Kind = Member; } + if (Kind == Member) { + unsigned I; + if (D.isFunctionDeclarator(I)) { + const DeclaratorChunk &Chunk = D.getTypeObject(I); + if (Chunk.Fun.NumParams) { + auto *P = dyn_cast_or_null<ParmVarDecl>(Chunk.Fun.Params->Param); + if (P && P->isExplicitObjectParameter()) + Kind = ExplicitObjectMember; + } + } + } + // C++11 [dcl.fct]p6 (w/DR1417): // An attempt to specify a function type with a cv-qualifier-seq or a // ref-qualifier (including by typedef-name) is ill-formed unless it is: @@ -5505,7 +5901,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // // ... for instance. if (IsQualifiedFunction && - !(Kind == Member && + !(Kind == Member && !D.isExplicitObjectMemberFunction() && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) && !IsTypedefName && D.getContext() != DeclaratorContext::TemplateArg && D.getContext() != DeclaratorContext::TemplateTypeArg) { @@ -5554,7 +5950,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } - // Apply any undistributed attributes from the declarator. + // Apply any undistributed attributes from the declaration or declarator. + ParsedAttributesView NonSlidingAttrs; + for (ParsedAttr &AL : D.getDeclarationAttributes()) { + if (!AL.slidesFromDeclToDeclSpecLegacyBehavior()) { + NonSlidingAttrs.addAtEnd(&AL); + } + } + processTypeAttrs(state, T, TAL_DeclName, NonSlidingAttrs); processTypeAttrs(state, T, TAL_DeclName, D.getAttributes()); // Diagnose any ignored type attributes. @@ -5601,7 +6004,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: @@ -5614,7 +6018,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 @@ -5645,6 +6049,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::TrailingReturnVar: case DeclaratorContext::TemplateArg: case DeclaratorContext::TemplateTypeArg: + case DeclaratorContext::Association: // FIXME: We may want to allow parameter packs in block-literal contexts // in the future. S.Diag(D.getEllipsisLoc(), @@ -5655,9 +6060,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } assert(!T.isNull() && "T must not be null at the end of this function"); - if (D.isInvalidType()) + if (!AreDeclaratorChunksValid) return Context.getTrivialTypeSourceInfo(T); - return GetTypeSourceInfoForDeclarator(state, T, TInfo); } @@ -5666,7 +6070,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, /// /// The result of this call will never be null, but the associated /// type may be a null type if there's an unrecoverable error. -TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S) { +TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D) { // Determine the type of the declarator. Not all forms of declarator // have a type. @@ -5722,7 +6126,7 @@ static void transferARCOwnershipToDeclaratorChunk(TypeProcessingState &state, ParsedAttr *attr = D.getAttributePool().create( &S.Context.Idents.get("objc_ownership"), SourceLocation(), /*scope*/ nullptr, SourceLocation(), - /*args*/ &Args, 1, ParsedAttr::AS_GNU); + /*args*/ &Args, 1, ParsedAttr::Form::GNU()); chunk.getAttrs().addAtEnd(attr); // TODO: mark whether we did this inference? } @@ -5799,6 +6203,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; @@ -5815,6 +6234,9 @@ namespace { Visit(TL.getModifiedLoc()); fillAttributedTypeLoc(TL, State); } + void VisitBTFTagAttributedTypeLoc(BTFTagAttributedTypeLoc TL) { + Visit(TL.getWrappedLoc()); + } void VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) { Visit(TL.getInnerLoc()); TL.setExpansionLoc( @@ -5823,13 +6245,16 @@ namespace { void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { Visit(TL.getUnqualifiedLoc()); } + // Allow to fill pointee's type locations, e.g., + // int __attr * __attr * __attr *p; + void VisitPointerTypeLoc(PointerTypeLoc TL) { Visit(TL.getNextTypeLoc()); } void VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); } void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); // FIXME. We should have DS.getTypeSpecTypeEndLoc(). But, it requires - // addition field. What we have is good enough for dispay of location + // addition field. What we have is good enough for display of location // of 'fixit' on interface name. TL.setNameEndLoc(DS.getEndLoc()); } @@ -5867,22 +6292,28 @@ 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); + TL.setDecltypeLoc(DS.getTypeSpecTypeLoc()); + 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()); @@ -5904,19 +6335,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() != ElaboratedTypeKeyword::None + ? DS.getTypeSpecTypeLoc() + : SourceLocation()); const CXXScopeSpec& SS = DS.getTypeSpecScope(); TL.setQualifierLoc(SS.getWithLocInContext(Context)); Visit(TL.getNextTypeLoc().getUnqualifiedLoc()); @@ -5943,27 +6374,34 @@ namespace { DS.getTypeSpecType() == TST_auto_type || DS.getTypeSpecType() == TST_unspecified); TL.setNameLoc(DS.getTypeSpecTypeLoc()); + if (DS.getTypeSpecType() == TST_decltype_auto) + TL.setRParenLoc(DS.getTypeofParensRange().getEnd()); if (!DS.isConstrainedAuto()) return; TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId(); - if (DS.getTypeSpecScope().isNotEmpty()) - TL.setNestedNameSpecifierLoc( - DS.getTypeSpecScope().getWithLocInContext(Context)); - else - TL.setNestedNameSpecifierLoc(NestedNameSpecifierLoc()); - TL.setTemplateKWLoc(TemplateId->TemplateKWLoc); - TL.setConceptNameLoc(TemplateId->TemplateNameLoc); - TL.setFoundDecl(nullptr); - TL.setLAngleLoc(TemplateId->LAngleLoc); - TL.setRAngleLoc(TemplateId->RAngleLoc); - if (TemplateId->NumArgs == 0) + if (!TemplateId) return; - TemplateArgumentListInfo TemplateArgsInfo; - ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), - TemplateId->NumArgs); - SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); - for (unsigned I = 0; I < TemplateId->NumArgs; ++I) - TL.setArgLocInfo(I, TemplateArgsInfo.arguments()[I].getLocInfo()); + + NestedNameSpecifierLoc NNS = + (DS.getTypeSpecScope().isNotEmpty() + ? DS.getTypeSpecScope().getWithLocInContext(Context) + : NestedNameSpecifierLoc()); + TemplateArgumentListInfo TemplateArgsInfo(TemplateId->LAngleLoc, + TemplateId->RAngleLoc); + if (TemplateId->NumArgs > 0) { + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); + } + DeclarationNameInfo DNI = DeclarationNameInfo( + TL.getTypePtr()->getTypeConstraintConcept()->getDeclName(), + TemplateId->TemplateNameLoc); + auto *CR = ConceptReference::Create( + Context, NNS, TemplateId->TemplateKWLoc, DNI, + /*FoundDecl=*/nullptr, + /*NamedDecl=*/TL.getTypePtr()->getTypeConstraintConcept(), + ASTTemplateArgumentListInfo::Create(Context, TemplateArgsInfo)); + TL.setConceptReference(CR); } void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); @@ -5995,11 +6433,11 @@ namespace { TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc()); } - void VisitExtIntTypeLoc(ExtIntTypeLoc TL) { + void VisitExtIntTypeLoc(BitIntTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); } - void VisitDependentExtIntTypeLoc(DependentExtIntTypeLoc TL) { + void VisitDependentExtIntTypeLoc(DependentBitIntTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); } @@ -6029,6 +6467,9 @@ namespace { void VisitAttributedTypeLoc(AttributedTypeLoc TL) { fillAttributedTypeLoc(TL, State); } + void VisitBTFTagAttributedTypeLoc(BTFTagAttributedTypeLoc TL) { + // nothing + } void VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { // nothing } @@ -6129,7 +6570,7 @@ namespace { assert(Chunk.Kind == DeclaratorChunk::Pipe); TL.setKWLoc(Chunk.Loc); } - void VisitExtIntTypeLoc(ExtIntTypeLoc TL) { + void VisitBitIntTypeLoc(BitIntTypeLoc TL) { TL.setNameLoc(Chunk.Loc); } void VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) { @@ -6146,6 +6587,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!"); @@ -6193,21 +6637,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. @@ -6232,6 +6661,12 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + // Microsoft property fields can have multiple sizeless array chunks + // (i.e. int x[][][]). Don't create more than one level of incomplete array. + if (CurrTL.getTypeLocClass() == TypeLoc::IncompleteArray && e != 1 && + D.getDeclSpec().getAttributes().hasMSPropertyAttr()) + continue; + // An AtomicTypeLoc might be produced by an atomic qualifier in this // declarator chunk. if (AtomicTypeLoc ATL = CurrTL.getAs<AtomicTypeLoc>()) { @@ -6239,29 +6674,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(); @@ -6285,8 +6733,8 @@ ParsedType Sema::CreateParsedType(QualType T, TypeSourceInfo *TInfo) { // FIXME: LocInfoTypes are "transient", only needed for passing to/from Parser // and Sema during declaration parsing. Try deallocating/caching them when // it's appropriate, instead of allocating them and keeping them around. - LocInfoType *LocT = (LocInfoType*)BumpAlloc.Allocate(sizeof(LocInfoType), - TypeAlignment); + LocInfoType *LocT = (LocInfoType *)BumpAlloc.Allocate(sizeof(LocInfoType), + alignof(LocInfoType)); new (LocT) LocInfoType(T, TInfo); assert(LocT->getTypeClass() != T->getTypeClass() && "LocInfoType's TypeClass conflicts with an existing Type class"); @@ -6300,13 +6748,13 @@ void LocInfoType::getAsStringInternal(std::string &Str, " GetTypeFromParser"); } -TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { +TypeResult Sema::ActOnTypeName(Declarator &D) { // C99 6.7.6: Type names have no identifier. This is already validated by // the parser. assert(D.getIdentifier() == nullptr && "Type name should have no identifier!"); - TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + TypeSourceInfo *TInfo = GetTypeForDeclarator(D); QualType T = TInfo->getType(); if (D.isInvalidType()) return true; @@ -6346,7 +6794,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) @@ -6369,6 +6817,7 @@ static bool BuildAddressSpaceIndex(Sema &S, LangAS &ASIdx, llvm::APSInt max(addrSpace.getBitWidth()); max = Qualifiers::MaxAddressSpace - (unsigned)LangAS::FirstTargetAddressSpace; + if (addrSpace > max) { S.Diag(AttrLoc, diag::err_attribute_address_space_too_high) << (unsigned)max.getZExtValue() << AddrSpace->getSourceRange(); @@ -6420,6 +6869,33 @@ QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, return BuildAddressSpaceAttr(T, ASIdx, AddrSpace, AttrLoc); } +static void HandleBTFTypeTagAttribute(QualType &Type, const ParsedAttr &Attr, + TypeProcessingState &State) { + Sema &S = State.getSema(); + + // Check the number of attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << Attr << 1; + Attr.setInvalid(); + return; + } + + // Ensure the argument is a string. + auto *StrLiteral = dyn_cast<StringLiteral>(Attr.getArgAsExpr(0)); + if (!StrLiteral) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) + << Attr << AANT_ArgumentString; + Attr.setInvalid(); + return; + } + + ASTContext &Ctx = S.Context; + StringRef BTFTypeTag = StrLiteral->getString(); + Type = State.getBTFTagAttributedType( + ::new (Ctx) BTFTypeTagAttr(Ctx, Attr, BTFTypeTag), Type); +} + /// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. @@ -6484,7 +6960,11 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, Attr.setInvalid(); } else { // The keyword-based type attributes imply which address space to use. - ASIdx = Attr.asOpenCLLangAS(); + ASIdx = S.getLangOpts().SYCLIsDevice ? Attr.asSYCLLangAS() + : Attr.asOpenCLLangAS(); + if (S.getLangOpts().HLSL) + ASIdx = Attr.asHLSLLangAS(); + if (ASIdx == LangAS::Default) llvm_unreachable("Invalid address space"); @@ -6935,17 +7415,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; @@ -6957,23 +7445,20 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, if (Attrs[attr::Ptr32] && Attrs[attr::Ptr64]) { S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) << "'__ptr32'" - << "'__ptr64'"; + << "'__ptr64'" << /*isRegularKeyword=*/0; return true; } else if (Attrs[attr::SPtr] && Attrs[attr::UPtr]) { S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) << "'__sptr'" - << "'__uptr'"; + << "'__uptr'" << /*isRegularKeyword=*/0; 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 @@ -6983,7 +7468,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; @@ -7004,6 +7490,56 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, return false; } +static bool HandleWebAssemblyFuncrefAttr(TypeProcessingState &State, + QualType &QT, ParsedAttr &PAttr) { + assert(PAttr.getKind() == ParsedAttr::AT_WebAssemblyFuncref); + + Sema &S = State.getSema(); + Attr *A = createSimpleAttr<WebAssemblyFuncrefAttr>(S.Context, PAttr); + + std::bitset<attr::LastAttr> Attrs; + attr::Kind NewAttrKind = A->getKind(); + const auto *AT = dyn_cast<AttributedType>(QT); + while (AT) { + Attrs[AT->getAttrKind()] = true; + AT = dyn_cast<AttributedType>(AT->getModifiedType()); + } + + // You cannot specify duplicate type attributes, so if the attribute has + // already been applied, flag it. + if (Attrs[NewAttrKind]) { + S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr; + return true; + } + + // Add address space to type based on its attributes. + LangAS ASIdx = LangAS::wasm_funcref; + QualType Pointee = QT->getPointeeType(); + Pointee = S.Context.getAddrSpaceQualType( + S.Context.removeAddrSpaceQualType(Pointee), ASIdx); + QT = State.getAttributedType(A, QT, S.Context.getPointerType(Pointee)); + return false; +} + +/// Rebuild an attributed type without the nullability attribute on it. +static QualType rebuildAttributedTypeWithoutNullability(ASTContext &Ctx, + QualType Type) { + auto Attributed = dyn_cast<AttributedType>(Type.getTypePtr()); + if (!Attributed) + return Type; + + // Skip the nullability attribute; we're done. + if (Attributed->getImmediateNullability()) + return Attributed->getModifiedType(); + + // Build the modified type. + QualType Modified = rebuildAttributedTypeWithoutNullability( + Ctx, Attributed->getModifiedType()); + assert(Modified.getTypePtr() != Attributed->getModifiedType().getTypePtr()); + return Ctx.getAttributedType(Attributed->getAttrKind(), Modified, + Attributed->getEquivalentType()); +} + /// Map a nullability attribute kind to a nullability kind. static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) { switch (kind) { @@ -7024,74 +7560,65 @@ static NullabilityKind mapNullabilityAttrKind(ParsedAttr::Kind kind) { } } -/// Applies a nullability type specifier to the given type, if possible. -/// -/// \param state The type processing state. -/// -/// \param type The type to which the nullability specifier will be -/// added. On success, this type will be updated appropriately. -/// -/// \param attr The attribute as written on the type. -/// -/// \param allowOnArrayType Whether to accept nullability specifiers on an -/// array type (e.g., because it will decay to a pointer). -/// -/// \returns true if a problem has been diagnosed, false on success. -static bool checkNullabilityTypeSpecifier(TypeProcessingState &state, - QualType &type, - ParsedAttr &attr, - bool allowOnArrayType) { - Sema &S = state.getSema(); - - NullabilityKind nullability = mapNullabilityAttrKind(attr.getKind()); - SourceLocation nullabilityLoc = attr.getLoc(); - bool isContextSensitive = attr.isContextSensitiveKeywordAttribute(); - - recordNullabilitySeen(S, nullabilityLoc); +static bool CheckNullabilityTypeSpecifier( + Sema &S, TypeProcessingState *State, ParsedAttr *PAttr, QualType &QT, + NullabilityKind Nullability, SourceLocation NullabilityLoc, + bool IsContextSensitive, bool AllowOnArrayType, bool OverrideExisting) { + bool Implicit = (State == nullptr); + if (!Implicit) + recordNullabilitySeen(S, NullabilityLoc); // Check for existing nullability attributes on the type. - QualType desugared = type; - while (auto attributed = dyn_cast<AttributedType>(desugared.getTypePtr())) { + QualType Desugared = QT; + while (auto *Attributed = dyn_cast<AttributedType>(Desugared.getTypePtr())) { // Check whether there is already a null - if (auto existingNullability = attributed->getImmediateNullability()) { + if (auto ExistingNullability = Attributed->getImmediateNullability()) { // Duplicated nullability. - if (nullability == *existingNullability) { - S.Diag(nullabilityLoc, diag::warn_nullability_duplicate) - << DiagNullabilityKind(nullability, isContextSensitive) - << FixItHint::CreateRemoval(nullabilityLoc); + if (Nullability == *ExistingNullability) { + if (Implicit) + break; + + S.Diag(NullabilityLoc, diag::warn_nullability_duplicate) + << DiagNullabilityKind(Nullability, IsContextSensitive) + << FixItHint::CreateRemoval(NullabilityLoc); break; } - // Conflicting nullability. - S.Diag(nullabilityLoc, diag::err_nullability_conflicting) - << DiagNullabilityKind(nullability, isContextSensitive) - << DiagNullabilityKind(*existingNullability, false); - return true; + if (!OverrideExisting) { + // Conflicting nullability. + S.Diag(NullabilityLoc, diag::err_nullability_conflicting) + << DiagNullabilityKind(Nullability, IsContextSensitive) + << DiagNullabilityKind(*ExistingNullability, false); + return true; + } + + // Rebuild the attributed type, dropping the existing nullability. + QT = rebuildAttributedTypeWithoutNullability(S.Context, QT); } - desugared = attributed->getModifiedType(); + Desugared = Attributed->getModifiedType(); } // If there is already a different nullability specifier, complain. // 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 (nullability != *existingNullability) { - S.Diag(nullabilityLoc, diag::err_nullability_conflicting) - << DiagNullabilityKind(nullability, isContextSensitive) - << DiagNullabilityKind(*existingNullability, false); + if (auto ExistingNullability = Desugared->getNullability()) { + if (Nullability != *ExistingNullability && !Implicit) { + S.Diag(NullabilityLoc, diag::err_nullability_conflicting) + << DiagNullabilityKind(Nullability, IsContextSensitive) + << DiagNullabilityKind(*ExistingNullability, false); // Try to find the typedef with the existing nullability specifier. - if (auto typedefType = desugared->getAs<TypedefType>()) { - TypedefNameDecl *typedefDecl = typedefType->getDecl(); + if (auto TT = Desugared->getAs<TypedefType>()) { + TypedefNameDecl *typedefDecl = TT->getDecl(); QualType underlyingType = typedefDecl->getUnderlyingType(); - if (auto typedefNullability - = AttributedType::stripOuterNullability(underlyingType)) { - if (*typedefNullability == *existingNullability) { + if (auto typedefNullability = + AttributedType::stripOuterNullability(underlyingType)) { + if (*typedefNullability == *ExistingNullability) { S.Diag(typedefDecl->getLocation(), diag::note_nullability_here) - << DiagNullabilityKind(*existingNullability, false); + << DiagNullabilityKind(*ExistingNullability, false); } } } @@ -7101,44 +7628,73 @@ static bool checkNullabilityTypeSpecifier(TypeProcessingState &state, } // If this definitely isn't a pointer type, reject the specifier. - if (!desugared->canHaveNullability() && - !(allowOnArrayType && desugared->isArrayType())) { - S.Diag(nullabilityLoc, diag::err_nullability_nonpointer) - << DiagNullabilityKind(nullability, isContextSensitive) << type; + if (!Desugared->canHaveNullability() && + !(AllowOnArrayType && Desugared->isArrayType())) { + if (!Implicit) + S.Diag(NullabilityLoc, diag::err_nullability_nonpointer) + << DiagNullabilityKind(Nullability, IsContextSensitive) << QT; + return true; } // For the context-sensitive keywords/Objective-C property // attributes, require that the type be a single-level pointer. - if (isContextSensitive) { + if (IsContextSensitive) { // Make sure that the pointee isn't itself a pointer type. const Type *pointeeType = nullptr; - if (desugared->isArrayType()) - pointeeType = desugared->getArrayElementTypeNoTypeQual(); - else if (desugared->isAnyPointerType()) - pointeeType = desugared->getPointeeType().getTypePtr(); + if (Desugared->isArrayType()) + pointeeType = Desugared->getArrayElementTypeNoTypeQual(); + else if (Desugared->isAnyPointerType()) + pointeeType = Desugared->getPointeeType().getTypePtr(); if (pointeeType && (pointeeType->isAnyPointerType() || pointeeType->isObjCObjectPointerType() || pointeeType->isMemberPointerType())) { - S.Diag(nullabilityLoc, diag::err_nullability_cs_multilevel) - << DiagNullabilityKind(nullability, true) - << type; - S.Diag(nullabilityLoc, diag::note_nullability_type_specifier) - << DiagNullabilityKind(nullability, false) - << type - << FixItHint::CreateReplacement(nullabilityLoc, - getNullabilitySpelling(nullability)); + S.Diag(NullabilityLoc, diag::err_nullability_cs_multilevel) + << DiagNullabilityKind(Nullability, true) << QT; + S.Diag(NullabilityLoc, diag::note_nullability_type_specifier) + << DiagNullabilityKind(Nullability, false) << QT + << FixItHint::CreateReplacement(NullabilityLoc, + getNullabilitySpelling(Nullability)); return true; } } // Form the attributed type. - type = state.getAttributedType( - createNullabilityAttr(S.Context, attr, nullability), type, type); + if (State) { + assert(PAttr); + Attr *A = createNullabilityAttr(S.Context, *PAttr, Nullability); + QT = State->getAttributedType(A, QT, QT); + } else { + attr::Kind attrKind = AttributedType::getNullabilityAttrKind(Nullability); + QT = S.Context.getAttributedType(attrKind, QT, QT); + } return false; } +static bool CheckNullabilityTypeSpecifier(TypeProcessingState &State, + QualType &Type, ParsedAttr &Attr, + bool AllowOnArrayType) { + NullabilityKind Nullability = mapNullabilityAttrKind(Attr.getKind()); + SourceLocation NullabilityLoc = Attr.getLoc(); + bool IsContextSensitive = Attr.isContextSensitiveKeywordAttribute(); + + return CheckNullabilityTypeSpecifier(State.getSema(), &State, &Attr, Type, + Nullability, NullabilityLoc, + IsContextSensitive, AllowOnArrayType, + /*overrideExisting*/ false); +} + +bool Sema::CheckImplicitNullabilityTypeSpecifier(QualType &Type, + NullabilityKind Nullability, + SourceLocation DiagLoc, + bool AllowArrayTypes, + bool OverrideExisting) { + return CheckNullabilityTypeSpecifier( + *this, nullptr, nullptr, Type, Nullability, DiagLoc, + /*isContextSensitive*/ false, AllowArrayTypes, OverrideExisting); +} + /// Check the application of the Objective-C '__kindof' qualifier to /// the given type. static bool checkObjCKindOfType(TypeProcessingState &state, QualType &type, @@ -7176,7 +7732,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 && @@ -7299,10 +7855,18 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { return createSimpleAttr<PascalAttr>(Ctx, Attr); case ParsedAttr::AT_SwiftCall: return createSimpleAttr<SwiftCallAttr>(Ctx, Attr); + case ParsedAttr::AT_SwiftAsyncCall: + return createSimpleAttr<SwiftAsyncCallAttr>(Ctx, Attr); case ParsedAttr::AT_VectorCall: return createSimpleAttr<VectorCallAttr>(Ctx, Attr); case ParsedAttr::AT_AArch64VectorPcs: return createSimpleAttr<AArch64VectorPcsAttr>(Ctx, Attr); + case ParsedAttr::AT_AArch64SVEPcs: + return createSimpleAttr<AArch64SVEPcsAttr>(Ctx, Attr); + case ParsedAttr::AT_ArmStreaming: + return createSimpleAttr<ArmStreamingAttr>(Ctx, Attr); + case ParsedAttr::AT_AMDGPUKernelCall: + return createSimpleAttr<AMDGPUKernelCallAttr>(Ctx, Attr); case ParsedAttr::AT_Pcs: { // The attribute may have had a fixit applied where we treated an // identifier as a string literal. The contents of the string are valid, @@ -7327,14 +7891,83 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) { return createSimpleAttr<PreserveMostAttr>(Ctx, Attr); case ParsedAttr::AT_PreserveAll: return createSimpleAttr<PreserveAllAttr>(Ctx, Attr); + case ParsedAttr::AT_M68kRTD: + return createSimpleAttr<M68kRTDAttr>(Ctx, Attr); } llvm_unreachable("unexpected attribute kind!"); } +static bool checkMutualExclusion(TypeProcessingState &state, + const FunctionProtoType::ExtProtoInfo &EPI, + ParsedAttr &Attr, + AttributeCommonInfo::Kind OtherKind) { + auto OtherAttr = std::find_if( + state.getCurrentAttributes().begin(), state.getCurrentAttributes().end(), + [OtherKind](const ParsedAttr &A) { return A.getKind() == OtherKind; }); + if (OtherAttr == state.getCurrentAttributes().end() || OtherAttr->isInvalid()) + return false; + + Sema &S = state.getSema(); + S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) + << *OtherAttr << Attr + << (OtherAttr->isRegularKeywordAttribute() || + Attr.isRegularKeywordAttribute()); + S.Diag(OtherAttr->getLoc(), diag::note_conflicting_attribute); + Attr.setInvalid(); + return true; +} + +static bool handleArmStateAttribute(Sema &S, + FunctionProtoType::ExtProtoInfo &EPI, + ParsedAttr &Attr, + FunctionType::ArmStateValue State) { + if (!Attr.getNumArgs()) { + S.Diag(Attr.getLoc(), diag::err_missing_arm_state) << Attr; + Attr.setInvalid(); + return true; + } + + for (unsigned I = 0; I < Attr.getNumArgs(); ++I) { + StringRef StateName; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(Attr, I, StateName, &LiteralLoc)) + return true; + + unsigned Shift; + FunctionType::ArmStateValue ExistingState; + if (StateName == "za") { + Shift = FunctionType::SME_ZAShift; + ExistingState = FunctionType::getArmZAState(EPI.AArch64SMEAttributes); + } else if (StateName == "zt0") { + Shift = FunctionType::SME_ZT0Shift; + ExistingState = FunctionType::getArmZT0State(EPI.AArch64SMEAttributes); + } else { + S.Diag(LiteralLoc, diag::err_unknown_arm_state) << StateName; + Attr.setInvalid(); + return true; + } + + // __arm_in(S), __arm_out(S), __arm_inout(S) and __arm_preserves(S) + // are all mutually exclusive for the same S, so check if there are + // conflicting attributes. + if (ExistingState != FunctionType::ARM_None && ExistingState != State) { + S.Diag(LiteralLoc, diag::err_conflicting_attributes_arm_state) + << StateName; + Attr.setInvalid(); + return true; + } + + EPI.setArmSMEAttribute( + (FunctionType::AArch64SMETypeAttributes)((State << Shift))); + } + return false; +} + /// Process an individual function attribute. Returns true to /// indicate that the attribute was handled, false if it wasn't. static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, - QualType &type) { + QualType &type, + Sema::CUDAFunctionTarget CFT) { Sema &S = state.getSema(); FunctionTypeUnwrapper unwrapped(S, type); @@ -7448,8 +8081,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, CallingConv CC = fn->getCallConv(); if (CC == CC_X86FastCall) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << FunctionType::getNameForCallConv(CC) - << "regparm"; + << FunctionType::getNameForCallConv(CC) << "regparm" + << attr.isRegularKeywordAttribute(); attr.setInvalid(); return true; } @@ -7460,6 +8093,72 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, return true; } + if (attr.getKind() == ParsedAttr::AT_ArmStreaming || + attr.getKind() == ParsedAttr::AT_ArmStreamingCompatible || + attr.getKind() == ParsedAttr::AT_ArmPreserves || + attr.getKind() == ParsedAttr::AT_ArmIn || + attr.getKind() == ParsedAttr::AT_ArmOut || + attr.getKind() == ParsedAttr::AT_ArmInOut) { + if (S.CheckAttrTarget(attr)) + return true; + + if (attr.getKind() == ParsedAttr::AT_ArmStreaming || + attr.getKind() == ParsedAttr::AT_ArmStreamingCompatible) + if (S.CheckAttrNoArgs(attr)) + return true; + + if (!unwrapped.isFunctionType()) + return false; + + const auto *FnTy = unwrapped.get()->getAs<FunctionProtoType>(); + if (!FnTy) { + // SME ACLE attributes are not supported on K&R-style unprototyped C + // functions. + S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) << + attr << attr.isRegularKeywordAttribute() << ExpectedFunctionWithProtoType; + attr.setInvalid(); + return false; + } + + FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo(); + switch (attr.getKind()) { + case ParsedAttr::AT_ArmStreaming: + if (checkMutualExclusion(state, EPI, attr, + ParsedAttr::AT_ArmStreamingCompatible)) + return true; + EPI.setArmSMEAttribute(FunctionType::SME_PStateSMEnabledMask); + break; + case ParsedAttr::AT_ArmStreamingCompatible: + if (checkMutualExclusion(state, EPI, attr, ParsedAttr::AT_ArmStreaming)) + return true; + EPI.setArmSMEAttribute(FunctionType::SME_PStateSMCompatibleMask); + break; + case ParsedAttr::AT_ArmPreserves: + if (handleArmStateAttribute(S, EPI, attr, FunctionType::ARM_Preserves)) + return true; + break; + case ParsedAttr::AT_ArmIn: + if (handleArmStateAttribute(S, EPI, attr, FunctionType::ARM_In)) + return true; + break; + case ParsedAttr::AT_ArmOut: + if (handleArmStateAttribute(S, EPI, attr, FunctionType::ARM_Out)) + return true; + break; + case ParsedAttr::AT_ArmInOut: + if (handleArmStateAttribute(S, EPI, attr, FunctionType::ARM_InOut)) + return true; + break; + default: + llvm_unreachable("Unsupported attribute"); + } + + QualType newtype = S.Context.getFunctionType(FnTy->getReturnType(), + FnTy->getParamTypes(), EPI); + type = unwrapped.wrap(S, newtype->getAs<FunctionType>()); + return true; + } + if (attr.getKind() == ParsedAttr::AT_NoThrow) { // Delay if this is not a function type. if (!unwrapped.isFunctionType()) @@ -7485,7 +8184,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: @@ -7516,7 +8215,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, // Otherwise, a calling convention. CallingConv CC; - if (S.CheckCallingConvAttr(attr, CC)) + if (S.CheckCallingConvAttr(attr, CC, /*FunctionDecl=*/nullptr, CFT)) return true; const FunctionType *fn = unwrapped.get(); @@ -7528,8 +8227,9 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, // and the CCs don't match. if (S.getCallingConvAttributedType(type)) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << FunctionType::getNameForCallConv(CC) - << FunctionType::getNameForCallConv(CCOld); + << FunctionType::getNameForCallConv(CC) + << FunctionType::getNameForCallConv(CCOld) + << attr.isRegularKeywordAttribute(); attr.setInvalid(); return true; } @@ -7561,7 +8261,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, // Also diagnose fastcall with regparm. if (CC == CC_X86FastCall && fn->getHasRegParm()) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall); + << "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall) + << attr.isRegularKeywordAttribute(); attr.setInvalid(); return true; } @@ -7595,14 +8296,15 @@ bool Sema::hasExplicitCallingConv(QualType T) { return false; } -void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, - SourceLocation Loc) { +void Sema::adjustMemberFunctionCC(QualType &T, bool HasThisPointer, + bool IsCtorOrDtor, SourceLocation Loc) { FunctionTypeUnwrapper Unwrapped(*this, T); const FunctionType *FT = Unwrapped.get(); bool IsVariadic = (isa<FunctionProtoType>(FT) && cast<FunctionProtoType>(FT)->isVariadic()); CallingConv CurCC = FT->getCallConv(); - CallingConv ToCC = Context.getDefaultCallingConvention(IsVariadic, !IsStatic); + CallingConv ToCC = + Context.getDefaultCallingConvention(IsVariadic, HasThisPointer); if (CurCC == ToCC) return; @@ -7622,9 +8324,9 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, // we should adjust a __cdecl type to __thiscall for instance methods, and a // __thiscall type to __cdecl for static methods. CallingConv DefaultCC = - Context.getDefaultCallingConvention(IsVariadic, IsStatic); + Context.getDefaultCallingConvention(IsVariadic, !HasThisPointer); - if (CurCC != DefaultCC || DefaultCC == ToCC) + if (CurCC != DefaultCC) return; if (hasExplicitCallingConv(T)) @@ -7678,8 +8380,7 @@ static void HandleExtVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, CurType = T; } -static bool isPermittedNeonBaseType(QualType &Ty, - VectorType::VectorKind VecKind, Sema &S) { +static bool isPermittedNeonBaseType(QualType &Ty, VectorKind VecKind, Sema &S) { const BuiltinType *BTy = Ty->getAs<BuiltinType>(); if (!BTy) return false; @@ -7691,7 +8392,7 @@ static bool isPermittedNeonBaseType(QualType &Ty, bool IsPolyUnsigned = Triple.getArch() == llvm::Triple::aarch64 || Triple.getArch() == llvm::Triple::aarch64_32 || Triple.getArch() == llvm::Triple::aarch64_be; - if (VecKind == VectorType::NeonPolyVector) { + if (VecKind == VectorKind::NeonPoly) { if (IsPolyUnsigned) { // AArch64 polynomial vectors are unsigned. return BTy->getKind() == BuiltinType::UChar || @@ -7730,8 +8431,8 @@ static bool isPermittedNeonBaseType(QualType &Ty, static bool verifyValidIntegerConstantExpr(Sema &S, const ParsedAttr &Attr, llvm::APSInt &Result) { const auto *AttrExpr = Attr.getArgAsExpr(0); - if (!AttrExpr->isTypeDependent() && !AttrExpr->isValueDependent()) { - if (Optional<llvm::APSInt> Res = + if (!AttrExpr->isTypeDependent()) { + if (std::optional<llvm::APSInt> Res = AttrExpr->getIntegerConstantExpr(S.Context)) { Result = *Res; return true; @@ -7751,20 +8452,41 @@ static bool verifyValidIntegerConstantExpr(Sema &S, const ParsedAttr &Attr, /// not the vector size in bytes. The vector width and element type must /// match one of the standard Neon vector types. static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, - Sema &S, VectorType::VectorKind VecKind) { + Sema &S, VectorKind VecKind) { + bool IsTargetCUDAAndHostARM = false; + if (S.getLangOpts().CUDAIsDevice) { + const TargetInfo *AuxTI = S.getASTContext().getAuxTargetInfo(); + IsTargetCUDAAndHostARM = + AuxTI && (AuxTI->getTriple().isAArch64() || AuxTI->getTriple().isARM()); + } + // Target must have NEON (or MVE, whose vectors are similar enough // not to need a separate attribute) - if (!S.Context.getTargetInfo().hasFeature("neon") && - !S.Context.getTargetInfo().hasFeature("mve")) { + if (!(S.Context.getTargetInfo().hasFeature("neon") || + S.Context.getTargetInfo().hasFeature("mve") || + S.Context.getTargetInfo().hasFeature("sve") || + S.Context.getTargetInfo().hasFeature("sme") || + IsTargetCUDAAndHostARM) && + VecKind == VectorKind::Neon) { + S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) + << Attr << "'neon', 'mve', 'sve' or 'sme'"; + Attr.setInvalid(); + return; + } + if (!(S.Context.getTargetInfo().hasFeature("neon") || + S.Context.getTargetInfo().hasFeature("mve") || + IsTargetCUDAAndHostARM) && + VecKind == VectorKind::NeonPoly) { S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr << "'neon' or 'mve'"; Attr.setInvalid(); return; } + // Check the attribute arguments. if (Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << Attr - << 1; + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << Attr << 1; Attr.setInvalid(); return; } @@ -7774,7 +8496,8 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, return; // Only certain element types are supported for Neon vectors. - if (!isPermittedNeonBaseType(CurType, VecKind, S)) { + if (!isPermittedNeonBaseType(CurType, VecKind, S) && + !IsTargetCUDAAndHostARM) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_vector_type) << CurType; Attr.setInvalid(); return; @@ -7805,8 +8528,10 @@ static void HandleArmSveVectorBitsTypeAttr(QualType &CurType, ParsedAttr &Attr, return; } - // Attribute is unsupported if '-msve-vector-bits=<bits>' isn't specified. - if (!S.getLangOpts().ArmSveVectorBits) { + // Attribute is unsupported if '-msve-vector-bits=<bits>' isn't specified, or + // if <bits>+ syntax is used. + if (!S.getLangOpts().VScaleMin || + S.getLangOpts().VScaleMin != S.getLangOpts().VScaleMax) { S.Diag(Attr.getLoc(), diag::err_attribute_arm_feature_sve_bits_unsupported) << Attr; Attr.setInvalid(); @@ -7829,15 +8554,15 @@ static void HandleArmSveVectorBitsTypeAttr(QualType &CurType, ParsedAttr &Attr, unsigned VecSize = static_cast<unsigned>(SveVectorSizeInBits.getZExtValue()); // The attribute vector size must match -msve-vector-bits. - if (VecSize != S.getLangOpts().ArmSveVectorBits) { + if (VecSize != S.getLangOpts().VScaleMin * 128) { S.Diag(Attr.getLoc(), diag::err_attribute_bad_sve_vector_size) - << VecSize << S.getLangOpts().ArmSveVectorBits; + << VecSize << S.getLangOpts().VScaleMin * 128; Attr.setInvalid(); return; } // Attribute can only be attached to a single SVE vector or predicate type. - if (!CurType->isVLSTBuiltinType()) { + if (!CurType->isSveVLSBuiltinType()) { S.Diag(Attr.getLoc(), diag::err_attribute_invalid_sve_type) << Attr << CurType; Attr.setInvalid(); @@ -7848,11 +8573,11 @@ static void HandleArmSveVectorBitsTypeAttr(QualType &CurType, ParsedAttr &Attr, QualType EltType = CurType->getSveEltType(S.Context); unsigned TypeSize = S.Context.getTypeSize(EltType); - VectorType::VectorKind VecKind = VectorType::SveFixedLengthDataVector; + VectorKind VecKind = VectorKind::SveFixedLengthData; if (BT->getKind() == BuiltinType::SveBool) { // Predicates are represented as i8. VecSize /= S.Context.getCharWidth() * S.Context.getCharWidth(); - VecKind = VectorType::SveFixedLengthPredicateVector; + VecKind = VectorKind::SveFixedLengthPredicate; } else VecSize /= TypeSize; CurType = S.Context.getVectorType(EltType, VecSize, VecKind); @@ -7862,7 +8587,7 @@ static void HandleArmMveStrictPolymorphismAttr(TypeProcessingState &State, QualType &CurType, ParsedAttr &Attr) { const VectorType *VT = dyn_cast<VectorType>(CurType); - if (!VT || VT->getVectorKind() != VectorType::NeonVector) { + if (!VT || VT->getVectorKind() != VectorKind::Neon) { State.getSema().Diag(Attr.getLoc(), diag::err_attribute_arm_mve_polymorphism); Attr.setInvalid(); @@ -7875,6 +8600,78 @@ static void HandleArmMveStrictPolymorphismAttr(TypeProcessingState &State, CurType, CurType); } +/// HandleRISCVRVVVectorBitsTypeAttr - The "riscv_rvv_vector_bits" attribute is +/// used to create fixed-length versions of sizeless RVV types such as +/// vint8m1_t_t. +static void HandleRISCVRVVVectorBitsTypeAttr(QualType &CurType, + ParsedAttr &Attr, Sema &S) { + // Target must have vector extension. + if (!S.Context.getTargetInfo().hasFeature("zve32x")) { + S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) + << Attr << "'zve32x'"; + Attr.setInvalid(); + return; + } + + auto VScale = S.Context.getTargetInfo().getVScaleRange(S.getLangOpts()); + if (!VScale || !VScale->first || VScale->first != VScale->second) { + S.Diag(Attr.getLoc(), diag::err_attribute_riscv_rvv_bits_unsupported) + << Attr; + Attr.setInvalid(); + return; + } + + // Check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << Attr << 1; + Attr.setInvalid(); + return; + } + + // The vector size must be an integer constant expression. + llvm::APSInt RVVVectorSizeInBits(32); + if (!verifyValidIntegerConstantExpr(S, Attr, RVVVectorSizeInBits)) + return; + + // Attribute can only be attached to a single RVV vector type. + if (!CurType->isRVVVLSBuiltinType()) { + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_rvv_type) + << Attr << CurType; + Attr.setInvalid(); + return; + } + + unsigned VecSize = static_cast<unsigned>(RVVVectorSizeInBits.getZExtValue()); + + ASTContext::BuiltinVectorTypeInfo Info = + S.Context.getBuiltinVectorTypeInfo(CurType->castAs<BuiltinType>()); + unsigned MinElts = Info.EC.getKnownMinValue(); + + VectorKind VecKind = VectorKind::RVVFixedLengthData; + unsigned ExpectedSize = VScale->first * MinElts; + QualType EltType = CurType->getRVVEltType(S.Context); + unsigned EltSize = S.Context.getTypeSize(EltType); + unsigned NumElts; + if (Info.ElementType == S.Context.BoolTy) { + NumElts = VecSize / S.Context.getCharWidth(); + VecKind = VectorKind::RVVFixedLengthMask; + } else { + ExpectedSize *= EltSize; + NumElts = VecSize / EltSize; + } + + // The attribute vector size must match -mrvv-vector-bits. + if (ExpectedSize % 8 != 0 || VecSize != ExpectedSize) { + S.Diag(Attr.getLoc(), diag::err_attribute_bad_rvv_vector_size) + << VecSize << ExpectedSize; + Attr.setInvalid(); + return; + } + + CurType = S.Context.getVectorType(EltType, NumElts, VecKind); +} + /// Handle OpenCL Access Qualifier Attribute. static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr, Sema &S) { @@ -7952,6 +8749,34 @@ static void HandleMatrixTypeAttr(QualType &CurType, const ParsedAttr &Attr, CurType = T; } +static void HandleAnnotateTypeAttr(TypeProcessingState &State, + QualType &CurType, const ParsedAttr &PA) { + Sema &S = State.getSema(); + + if (PA.getNumArgs() < 1) { + S.Diag(PA.getLoc(), diag::err_attribute_too_few_arguments) << PA << 1; + return; + } + + // Make sure that there is a string literal as the annotation's first + // argument. + StringRef Str; + if (!S.checkStringLiteralArgumentAttr(PA, 0, Str)) + return; + + llvm::SmallVector<Expr *, 4> Args; + Args.reserve(PA.getNumArgs() - 1); + for (unsigned Idx = 1; Idx < PA.getNumArgs(); Idx++) { + assert(!PA.isArgIdent(Idx)); + Args.push_back(PA.getArgAsExpr(Idx)); + } + if (!S.ConstantFoldAttrArgs(PA, Args)) + return; + auto *AnnotateTypeAttr = + AnnotateTypeAttr::Create(S.Context, Str, Args.data(), Args.size(), PA); + CurType = State.getAttributedType(AnnotateTypeAttr, CurType, CurType); +} + static void HandleLifetimeBoundAttr(TypeProcessingState &State, QualType &CurType, ParsedAttr &Attr) { @@ -7959,27 +8784,29 @@ static void HandleLifetimeBoundAttr(TypeProcessingState &State, CurType = State.getAttributedType( createSimpleAttr<LifetimeBoundAttr>(State.getSema().Context, Attr), CurType, CurType); - } else { - Attr.diagnoseAppertainsTo(State.getSema(), nullptr); } } -static bool isAddressSpaceKind(const ParsedAttr &attr) { - auto attrKind = attr.getKind(); - - return attrKind == ParsedAttr::AT_AddressSpace || - attrKind == ParsedAttr::AT_OpenCLPrivateAddressSpace || - attrKind == ParsedAttr::AT_OpenCLGlobalAddressSpace || - attrKind == ParsedAttr::AT_OpenCLGlobalDeviceAddressSpace || - attrKind == ParsedAttr::AT_OpenCLGlobalHostAddressSpace || - attrKind == ParsedAttr::AT_OpenCLLocalAddressSpace || - attrKind == ParsedAttr::AT_OpenCLConstantAddressSpace || - attrKind == ParsedAttr::AT_OpenCLGenericAddressSpace; +static void HandleHLSLParamModifierAttr(QualType &CurType, + const ParsedAttr &Attr, Sema &S) { + // Don't apply this attribute to template dependent types. It is applied on + // substitution during template instantiation. + if (CurType->isDependentType()) + return; + if (Attr.getSemanticSpelling() == HLSLParamModifierAttr::Keyword_inout || + Attr.getSemanticSpelling() == HLSLParamModifierAttr::Keyword_out) + CurType = S.getASTContext().getLValueReferenceType(CurType); } static void processTypeAttrs(TypeProcessingState &state, QualType &type, TypeAttrLocation TAL, - ParsedAttributesView &attrs) { + const ParsedAttributesView &attrs, + Sema::CUDAFunctionTarget CFT) { + + state.setParsedNoDeref(false); + if (attrs.empty()) + return; + // Scan through and apply attributes to this type where it makes sense. Some // attributes (such as __address_space__, __vector_size__, etc) apply to the // type, but others can be present in the type specifiers even though they @@ -7989,21 +8816,19 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // sure we visit every element once. Copy the attributes list, and iterate // over that. ParsedAttributesView AttrsCopy{attrs}; - - state.setParsedNoDeref(false); - for (ParsedAttr &attr : AttrsCopy) { // Skip attributes that were marked to be invalid. if (attr.isInvalid()) continue; - if (attr.isCXX11Attribute()) { + if (attr.isStandardAttributeSyntax() || attr.isRegularKeywordAttribute()) { // [[gnu::...]] attributes are treated as declaration attributes, so may // not appertain to a DeclaratorChunk. If we handle them as type // attributes, accept them in that position and diagnose the GCC // incompatibility. if (attr.isGNUScope()) { + assert(attr.isStandardAttributeSyntax()); bool IsTypeAttr = attr.isTypeAttr(); if (TAL == TAL_DeclChunk) { state.getSema().Diag(attr.getLoc(), @@ -8014,11 +8839,14 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, if (!IsTypeAttr) continue; } - } else if (TAL != TAL_DeclChunk && !isAddressSpaceKind(attr)) { + } else if (TAL != TAL_DeclSpec && TAL != TAL_DeclChunk && + !attr.isTypeAttr()) { // Otherwise, only consider type processing for a C++11 attribute if - // it's actually been applied to a type. - // We also allow C++11 address_space and - // OpenCL language address space attributes to pass through. + // - it has actually been applied to a type (decl-specifier-seq or + // declarator chunk), or + // - it is a type attribute, irrespective of where it was applied (so + // that we can support the legacy behavior of some type attributes + // that can be applied to the declaration name). continue; } } @@ -8027,24 +8855,35 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // otherwise, add it to the FnAttrs list for rechaining. switch (attr.getKind()) { default: - // A C++11 attribute on a declarator chunk must appertain to a type. - if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk) { + // A [[]] attribute on a declarator chunk must appertain to a type. + if ((attr.isStandardAttributeSyntax() || + attr.isRegularKeywordAttribute()) && + TAL == TAL_DeclChunk) { state.getSema().Diag(attr.getLoc(), diag::err_attribute_not_type_attr) - << attr; + << attr << attr.isRegularKeywordAttribute(); attr.setUsedAsTypeAttr(); } break; case ParsedAttr::UnknownAttribute: - if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk) + if (attr.isStandardAttributeSyntax()) { state.getSema().Diag(attr.getLoc(), diag::warn_unknown_attribute_ignored) << attr << attr.getRange(); + // Mark the attribute as invalid so we don't emit the same diagnostic + // multiple times. + attr.setInvalid(); + } break; case ParsedAttr::IgnoredAttribute: break; + case ParsedAttr::AT_BTFTypeTag: + HandleBTFTypeTagAttribute(type, attr, state); + attr.setUsedAsTypeAttr(); + break; + case ParsedAttr::AT_MayAlias: // FIXME: This attribute needs to actually be handled, but if we ignore // it it breaks large amounts of Linux software. @@ -8057,6 +8896,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(); @@ -8075,13 +8915,12 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.setUsedAsTypeAttr(); break; case ParsedAttr::AT_NeonVectorType: - HandleNeonVectorTypeAttr(type, attr, state.getSema(), - VectorType::NeonVector); + HandleNeonVectorTypeAttr(type, attr, state.getSema(), VectorKind::Neon); attr.setUsedAsTypeAttr(); break; case ParsedAttr::AT_NeonPolyVectorType: HandleNeonVectorTypeAttr(type, attr, state.getSema(), - VectorType::NeonPolyVector); + VectorKind::NeonPoly); attr.setUsedAsTypeAttr(); break; case ParsedAttr::AT_ArmSveVectorBits: @@ -8093,6 +8932,10 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.setUsedAsTypeAttr(); break; } + case ParsedAttr::AT_RISCVRVVVectorBits: + HandleRISCVRVVVectorBitsTypeAttr(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); + break; case ParsedAttr::AT_OpenCLAccess: HandleOpenCLAccessAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); @@ -8103,6 +8946,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, break; case ParsedAttr::AT_NoDeref: { + // FIXME: `noderef` currently doesn't work correctly in [[]] syntax. + // See https://github.com/llvm/llvm-project/issues/55790 for details. + // For the time being, we simply emit a warning that the attribute is + // ignored. + if (attr.isStandardAttributeSyntax()) { + state.getSema().Diag(attr.getLoc(), diag::warn_attribute_ignored) + << attr; + break; + } ASTContext &Ctx = state.getSema().Context; type = state.getAttributedType(createSimpleAttr<NoDerefAttr>(Ctx, attr), type, type); @@ -8116,6 +8968,18 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.setUsedAsTypeAttr(); break; + case ParsedAttr::AT_WebAssemblyFuncref: { + if (!HandleWebAssemblyFuncrefAttr(state, type, attr)) + attr.setUsedAsTypeAttr(); + break; + } + + case ParsedAttr::AT_HLSLParamModifier: { + HandleHLSLParamModifierAttr(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); + break; + } + MS_TYPE_ATTRS_CASELIST: if (!handleMSPointerTypeQualifierAttr(state, attr, type)) attr.setUsedAsTypeAttr(); @@ -8137,11 +9001,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, bool allowOnArrayType = state.getDeclarator().isPrototypeContext() && !hasOuterPointerLikeChunk(state.getDeclarator(), endIndex); - if (checkNullabilityTypeSpecifier( - state, - type, - attr, - allowOnArrayType)) { + if (CheckNullabilityTypeSpecifier(state, type, attr, + allowOnArrayType)) { attr.setInvalid(); } @@ -8176,17 +9037,28 @@ 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(); + // Attributes with standard syntax have strict rules for what they + // appertain to and hence should not use the "distribution" logic below. + if (attr.isStandardAttributeSyntax() || + attr.isRegularKeywordAttribute()) { + if (!handleFunctionTypeAttr(state, attr, type, CFT)) { + diagnoseBadTypeAttribute(state.getSema(), attr, type); + attr.setInvalid(); + } + break; + } + // Never process function type attributes as part of the // declaration-specifiers. if (TAL == TAL_DeclSpec) - distributeFunctionTypeAttrFromDeclSpec(state, attr, type); + distributeFunctionTypeAttrFromDeclSpec(state, attr, type, CFT); // Otherwise, handle the possible delays. - else if (!handleFunctionTypeAttr(state, attr, type)) + else if (!handleFunctionTypeAttr(state, attr, type, CFT)) distributeFunctionTypeAttr(state, attr, type); break; case ParsedAttr::AT_AcquireHandle: { @@ -8210,6 +9082,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.setUsedAsTypeAttr(); break; } + case ParsedAttr::AT_AnnotateType: { + HandleAnnotateTypeAttr(state, type, attr); + attr.setUsedAsTypeAttr(); + break; + } } // Handle attributes that are defined in a macro. We do not want this to be @@ -8226,10 +9103,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.getMacroExpansionLoc()); } } - - if (!state.getSema().getLangOpts().OpenCL || - type.getAddressSpace() != LangAS::Default) - return; } void Sema::completeExprArrayBound(Expr *E) { @@ -8364,17 +9237,8 @@ bool Sema::hasStructuralCompatLayout(Decl *D, Decl *Suggested) { return Ctx.IsEquivalent(D, Suggested); } -/// Determine whether there is any declaration of \p D that was ever a -/// definition (perhaps before module merging) and is currently visible. -/// \param D The definition of the entity. -/// \param Suggested Filled in with the declaration that should be made visible -/// in order to provide a definition of this entity. -/// \param OnlyNeedComplete If \c true, we only need the type to be complete, -/// not defined. This only matters for enums with a fixed underlying -/// type, since in all other cases, a type is complete if and only if it -/// is defined. -bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, - bool OnlyNeedComplete) { +bool Sema::hasAcceptableDefinition(NamedDecl *D, NamedDecl **Suggested, + AcceptableKind Kind, bool OnlyNeedComplete) { // Easy case: if we don't have modules, all declarations are visible. if (!getLangOpts().Modules && !getLangOpts().ModulesLocalVisibility) return true; @@ -8400,12 +9264,13 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, // of it will do. *Suggested = nullptr; for (auto *Redecl : ED->redecls()) { - if (isVisible(Redecl)) + if (isAcceptable(Redecl, Kind)) return true; if (Redecl->isThisDeclarationADefinition() || (Redecl->isCanonicalDecl() && !*Suggested)) *Suggested = Redecl; } + return false; } D = ED->getDefinition(); @@ -8418,13 +9283,14 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, VD = Pattern; D = VD->getDefinition(); } + assert(D && "missing definition for pattern of instantiated definition"); *Suggested = D; - auto DefinitionIsVisible = [&] { + auto DefinitionIsAcceptable = [&] { // The (primary) definition might be in a visible module. - if (isVisible(D)) + if (isAcceptable(D, Kind)) return true; // A visible module might have a merged definition instead. @@ -8442,19 +9308,51 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, return false; }; - if (DefinitionIsVisible()) + if (DefinitionIsAcceptable()) return true; // The external source may have additional definitions of this entity that are // visible, so complete the redeclaration chain now and ask again. if (auto *Source = Context.getExternalSource()) { Source->CompleteRedeclChain(D); - return DefinitionIsVisible(); + return DefinitionIsAcceptable(); } return false; } +/// Determine whether there is any declaration of \p D that was ever a +/// definition (perhaps before module merging) and is currently visible. +/// \param D The definition of the entity. +/// \param Suggested Filled in with the declaration that should be made visible +/// in order to provide a definition of this entity. +/// \param OnlyNeedComplete If \c true, we only need the type to be complete, +/// not defined. This only matters for enums with a fixed underlying +/// type, since in all other cases, a type is complete if and only if it +/// is defined. +bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete) { + return hasAcceptableDefinition(D, Suggested, Sema::AcceptableKind::Visible, + OnlyNeedComplete); +} + +/// Determine whether there is any declaration of \p D that was ever a +/// definition (perhaps before module merging) and is currently +/// reachable. +/// \param D The definition of the entity. +/// \param Suggested Filled in with the declaration that should be made +/// reachable +/// in order to provide a definition of this entity. +/// \param OnlyNeedComplete If \c true, we only need the type to be complete, +/// not defined. This only matters for enums with a fixed underlying +/// type, since in all other cases, a type is complete if and only if it +/// is defined. +bool Sema::hasReachableDefinition(NamedDecl *D, NamedDecl **Suggested, + bool OnlyNeedComplete) { + return hasAcceptableDefinition(D, Suggested, Sema::AcceptableKind::Reachable, + OnlyNeedComplete); +} + /// Locks in the inheritance model for the given class and all of its bases. static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { RD = RD->getMostRecentNonInjectedDecl(); @@ -8481,8 +9379,7 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { ? S.ImplicitMSInheritanceAttrLoc : RD->getSourceRange(); RD->addAttr(MSInheritanceAttr::CreateImplicit( - S.getASTContext(), BestCase, Loc, AttributeCommonInfo::AS_Microsoft, - MSInheritanceAttr::Spelling(IM))); + S.getASTContext(), BestCase, Loc, MSInheritanceAttr::Spelling(IM))); S.Consumer.AssignInheritanceModel(RD); } } @@ -8524,20 +9421,19 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // Check that any necessary explicit specializations are visible. For an // enum, we just need the declaration, so don't check this. if (Def && !isa<EnumDecl>(Def)) - checkSpecializationVisibility(Loc, Def); + checkSpecializationReachability(Loc, Def); // If we have a complete type, we're done. if (!Incomplete) { - // If we know about the definition but it is not visible, complain. - NamedDecl *SuggestedDef = nullptr; + NamedDecl *Suggested = nullptr; if (Def && - !hasVisibleDefinition(Def, &SuggestedDef, /*OnlyNeedComplete*/true)) { + !hasReachableDefinition(Def, &Suggested, /*OnlyNeedComplete=*/true)) { // If the user is going to see an error here, recover by making the // definition visible. bool TreatAsComplete = Diagnoser && !isSFINAEContext(); - if (Diagnoser && SuggestedDef) - diagnoseMissingImport(Loc, SuggestedDef, MissingImportKind::Definition, - /*Recover*/TreatAsComplete); + if (Diagnoser && Suggested) + diagnoseMissingImport(Loc, Suggested, MissingImportKind::Definition, + /*Recover*/ TreatAsComplete); return !TreatAsComplete; } else if (Def && !TemplateInstCallbacks.empty()) { CodeSynthesisContext TempInst; @@ -8670,9 +9566,12 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, /// \returns diagnostic %select index. static unsigned getLiteralDiagFromTagKind(TagTypeKind Tag) { switch (Tag) { - case TTK_Struct: return 0; - case TTK_Interface: return 1; - case TTK_Class: return 2; + case TagTypeKind::Struct: + return 0; + case TagTypeKind::Interface: + return 1; + case TagTypeKind::Class: + return 2; default: llvm_unreachable("Invalid tag kind for literal type diagnostic!"); } } @@ -8798,37 +9697,35 @@ 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, SourceLocation Loc) { +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 /// that expression, according to the rules in C++11 /// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18. -static QualType getDecltypeForExpr(Sema &S, Expr *E) { +QualType Sema::getDecltypeForExpr(Expr *E) { if (E->isTypeDependent()) - return S.Context.DependentTy; + return Context.DependentTy; + + Expr *IDExpr = E; + if (auto *ImplCastExpr = dyn_cast<ImplicitCastExpr>(E)) + IDExpr = ImplCastExpr->getSubExpr(); // C++11 [dcl.type.simple]p4: // The type denoted by decltype(e) is defined as follows: @@ -8840,8 +9737,8 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { // Note that this does not pick up the implicit 'const' for a template // parameter object. This rule makes no difference before C++20 so we apply // it unconditionally. - if (const auto *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) - return SNTTPE->getParameterType(S.Context); + if (const auto *SNTTPE = dyn_cast<SubstNonTypeTemplateParmExpr>(IDExpr)) + return SNTTPE->getParameterType(Context); // - if e is an unparenthesized id-expression or an unparenthesized class // member access (5.2.5), decltype(e) is the type of the entity named @@ -8849,21 +9746,21 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { // functions, the program is ill-formed; // // We apply the same rules for Objective-C ivar and property references. - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (const auto *DRE = dyn_cast<DeclRefExpr>(IDExpr)) { const ValueDecl *VD = DRE->getDecl(); - if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(VD)) - return TPO->getType().getUnqualifiedType(); - return VD->getType(); - } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { - if (const ValueDecl *VD = ME->getMemberDecl()) + QualType T = VD->getType(); + return isa<TemplateParamObjectDecl>(VD) ? T.getUnqualifiedType() : T; + } + if (const auto *ME = dyn_cast<MemberExpr>(IDExpr)) { + if (const auto *VD = ME->getMemberDecl()) if (isa<FieldDecl>(VD) || isa<VarDecl>(VD)) return VD->getType(); - } else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(E)) { + } else if (const auto *IR = dyn_cast<ObjCIvarRefExpr>(IDExpr)) { return IR->getDecl()->getType(); - } else if (const ObjCPropertyRefExpr *PR = dyn_cast<ObjCPropertyRefExpr>(E)) { + } else if (const auto *PR = dyn_cast<ObjCPropertyRefExpr>(IDExpr)) { if (PR->isExplicitProperty()) return PR->getExplicitProperty()->getType(); - } else if (auto *PE = dyn_cast<PredefinedExpr>(E)) { + } else if (const auto *PE = dyn_cast<PredefinedExpr>(IDExpr)) { return PE->getType(); } @@ -8874,39 +9771,20 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { // access to a corresponding data member of the closure type that // would have been declared if x were an odr-use of the denoted // entity. - using namespace sema; - if (S.getCurLambda()) { - if (isa<ParenExpr>(E)) { - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) { - if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) { - QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation()); - if (!T.isNull()) - return S.Context.getLValueReferenceType(T); - } + if (getCurLambda() && isa<ParenExpr>(IDExpr)) { + if (auto *DRE = dyn_cast<DeclRefExpr>(IDExpr->IgnoreParens())) { + if (auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) { + QualType T = getCapturedDeclRefType(Var, DRE->getLocation()); + if (!T.isNull()) + return Context.getLValueReferenceType(T); } } } - - // C++11 [dcl.type.simple]p4: - // [...] - QualType T = E->getType(); - switch (E->getValueKind()) { - // - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the - // type of e; - case VK_XValue: T = S.Context.getRValueReferenceType(T); break; - // - otherwise, if e is an lvalue, decltype(e) is T&, where T is the - // type of e; - case VK_LValue: T = S.Context.getLValueReferenceType(T); break; - // - otherwise, decltype(e) is the type of e. - case VK_RValue: break; - } - - return T; + return Context.getReferenceQualifiedType(E); } -QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc, - bool AsUnevaluated) { +QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (AsUnevaluated && CodeSynthesisContexts.empty() && @@ -8917,47 +9795,264 @@ QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc, // used to build SFINAE gadgets. Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); } + return Context.getDecltypeType(E, getDecltypeForExpr(E)); +} + +static QualType GetEnumUnderlyingType(Sema &S, QualType BaseType, + SourceLocation Loc) { + assert(BaseType->isEnumeralType()); + EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl(); + assert(ED && "EnumType has no EnumDecl"); + + S.DiagnoseUseOfDecl(ED, Loc); - return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); + QualType Underlying = ED->getIntegerType(); + assert(!Underlying.isNull()); + + return Underlying; } -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(); - } +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(); + } - EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl(); - assert(ED && "EnumType has no EnumDecl"); + return GetEnumUnderlyingType(*this, BaseType, Loc); +} - DiagnoseUseOfDecl(ED, Loc); +QualType Sema::BuiltinAddPointer(QualType BaseType, SourceLocation Loc) { + QualType Pointer = BaseType.isReferenceable() || BaseType->isVoidType() + ? BuildPointerType(BaseType.getNonReferenceType(), Loc, + DeclarationName()) + : BaseType; - Underlying = ED->getIntegerType(); - assert(!Underlying.isNull()); - } - return Context.getUnaryTransformType(BaseType, Underlying, - UnaryTransformType::EnumUnderlyingType); + 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) { - if (!T->isDependentType()) { + if (!isDependentOrGNUAutoType(T)) { // FIXME: It isn't entirely clear whether incomplete atomic types // are allowed or not; for simplicity, ban them for the moment. if (RequireCompleteType(Loc, T, diag::err_atomic_specifier_bad_type, 0)) @@ -8976,12 +10071,14 @@ QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { DisallowedKind = 5; else if (T->isSizelessType()) DisallowedKind = 6; - else if (!T.isTriviallyCopyableType(Context)) + else if (!T.isTriviallyCopyableType(Context) && getLangOpts().CPlusPlus) // Some other non-trivially-copyable type (probably a C++ class) DisallowedKind = 7; - else if (T->isExtIntType()) { - DisallowedKind = 8; - } + else if (T->isBitIntType()) + DisallowedKind = 8; + else if (getLangOpts().C23 && T->isUndeducedAutoType()) + // _Atomic auto is prohibited in C23 + DisallowedKind = 9; if (DisallowedKind != -1) { Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T; |