diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 80 | ||||
-rw-r--r-- | clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 2 | ||||
-rw-r--r-- | clang/lib/Sema/HLSLExternalSemaSource.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaConcept.cpp | 84 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 136 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 114 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Sema/SemaHLSL.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Sema/SemaRISCV.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 207 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 76 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 49 |
14 files changed, 662 insertions, 144 deletions
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 184d31e..9da3d0d 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -1369,7 +1369,8 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { if (S.getLangOpts().C23 && getConstexprSpecifier() == ConstexprSpecKind::Constexpr && - StorageClassSpec == SCS_extern) { + getTypeSpecType() != TST_unspecified && + (StorageClassSpec == SCS_extern || StorageClassSpec == SCS_auto)) { S.Diag(ConstexprLoc, diag::err_invalid_decl_spec_combination) << DeclSpec::getSpecifierName(getStorageClassSpec()) << SourceRange(getStorageClassSpecLoc()); diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 40c318a..066acf6 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -57,6 +57,29 @@ CXXConstructorDecl *lookupCopyConstructor(QualType ResTy) { return CD; return nullptr; } + +ParameterABI +convertParamModifierToParamABI(HLSLParamModifierAttr::Spelling Modifier) { + assert(Modifier != HLSLParamModifierAttr::Spelling::Keyword_in && + "HLSL 'in' parameters modifier cannot be converted to ParameterABI"); + switch (Modifier) { + case HLSLParamModifierAttr::Spelling::Keyword_out: + return ParameterABI::HLSLOut; + case HLSLParamModifierAttr::Spelling::Keyword_inout: + return ParameterABI::HLSLInOut; + default: + llvm_unreachable("Invalid HLSL parameter modifier"); + } +} + +QualType getInoutParameterType(ASTContext &AST, QualType Ty) { + assert(!Ty->isReferenceType() && + "Pointer and reference types cannot be inout or out parameters"); + Ty = AST.getLValueReferenceType(Ty); + Ty.addRestrict(); + return Ty; +} + } // namespace // Builder for template arguments of builtin types. Used internally @@ -430,19 +453,36 @@ BuiltinTypeMethodBuilder::addParam(StringRef Name, QualType Ty, void BuiltinTypeMethodBuilder::createDecl() { assert(Method == nullptr && "Method or constructor is already created"); - // create method or constructor type + // create function prototype ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); SmallVector<QualType> ParamTypes; - for (Param &MP : Params) + SmallVector<FunctionType::ExtParameterInfo> ParamExtInfos(Params.size()); + uint32_t ArgIndex = 0; + + // Create function prototype. + bool UseParamExtInfo = false; + for (Param &MP : Params) { + if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) { + UseParamExtInfo = true; + FunctionType::ExtParameterInfo &PI = ParamExtInfos[ArgIndex]; + ParamExtInfos[ArgIndex] = + PI.withABI(convertParamModifierToParamABI(MP.Modifier)); + if (!MP.Ty->isDependentType()) + MP.Ty = getInoutParameterType(AST, MP.Ty); + } ParamTypes.emplace_back(MP.Ty); + ++ArgIndex; + } FunctionProtoType::ExtProtoInfo ExtInfo; + if (UseParamExtInfo) + ExtInfo.ExtParameterInfos = ParamExtInfos.data(); if (IsConst) ExtInfo.TypeQuals.addConst(); QualType FuncTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo); - // create method or constructor decl + // Create method or constructor declaration. auto *TSInfo = AST.getTrivialTypeSourceInfo(FuncTy, SourceLocation()); DeclarationNameInfo NameInfo = DeclarationNameInfo(Name, SourceLocation()); if (IsCtor) @@ -455,7 +495,7 @@ void BuiltinTypeMethodBuilder::createDecl() { AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, SC, false, false, ConstexprSpecKind::Unspecified, SourceLocation()); - // create params & set them to the function prototype + // Create params & set them to the method/constructor and function prototype. SmallVector<ParmVarDecl *> ParmDecls; unsigned CurScopeDepth = DeclBuilder.SemaRef.getCurScope()->getDepth(); auto FnProtoLoc = @@ -1258,5 +1298,37 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() { .finalize(); } +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addGetDimensionsMethodForBuffer() { + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + ASTContext &AST = SemaRef.getASTContext(); + QualType UIntTy = AST.UnsignedIntTy; + + QualType HandleTy = getResourceHandleField()->getType(); + auto *AttrResTy = cast<HLSLAttributedResourceType>(HandleTy.getTypePtr()); + + // Structured buffers except {RW}ByteAddressBuffer have overload + // GetDimensions(out uint numStructs, out uint stride). + if (AttrResTy->getAttrs().RawBuffer && + AttrResTy->getContainedType() != AST.Char8Ty) { + return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy) + .addParam("numStructs", UIntTy, HLSLParamModifierAttr::Keyword_out) + .addParam("stride", UIntTy, HLSLParamModifierAttr::Keyword_out) + .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(), + PH::Handle, PH::_0) + .callBuiltin("__builtin_hlsl_resource_getstride", QualType(), + PH::Handle, PH::_1) + .finalize(); + } + + // Typed buffers and {RW}ByteAddressBuffer have overload + // GetDimensions(out uint dim). + return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy) + .addParam("dim", UIntTy, HLSLParamModifierAttr::Keyword_out) + .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(), + PH::Handle, PH::_0) + .finalize(); +} + } // namespace hlsl } // namespace clang diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h index 86cbd10..95e3a6c 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h @@ -94,6 +94,8 @@ public: BuiltinTypeDeclBuilder &addAppendMethod(); BuiltinTypeDeclBuilder &addConsumeMethod(); + BuiltinTypeDeclBuilder &addGetDimensionsMethodForBuffer(); + private: BuiltinTypeDeclBuilder &addCreateFromBinding(); BuiltinTypeDeclBuilder &addCreateFromImplicitBinding(); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index f28a037..6be84f1 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -380,6 +380,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/false, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -392,6 +393,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/false, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -404,6 +406,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/false, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -415,6 +418,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/true, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -428,6 +432,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { .addLoadMethods() .addIncrementCounterMethod() .addDecrementCounterMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -439,6 +444,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/true) .addAppendMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -450,6 +456,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/true) .addConsumeMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -464,6 +471,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { .addLoadMethods() .addIncrementCounterMethod() .addDecrementCounterMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -472,6 +480,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/false) + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWByteAddressBuffer") @@ -479,6 +488,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/false) + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, @@ -487,6 +497,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/true, /*RawBuffer=*/true, /*HasCounter=*/false) + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 652527a..ef1be23 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -12309,13 +12309,20 @@ static void DiagnoseMixedUnicodeImplicitConversion(Sema &S, const Type *Source, SourceLocation CC) { assert(Source->isUnicodeCharacterType() && Target->isUnicodeCharacterType() && Source != Target); + + // Lone surrogates have a distinct representation in UTF-32. + // Converting between UTF-16 and UTF-32 codepoints seems very widespread, + // so don't warn on such conversion. + if (Source->isChar16Type() && Target->isChar32Type()) + return; + Expr::EvalResult Result; if (E->EvaluateAsInt(Result, S.getASTContext(), Expr::SE_AllowSideEffects, S.isConstantEvaluatedContext())) { llvm::APSInt Value(32); Value = Result.Val.getInt(); bool IsASCII = Value <= 0x7F; - bool IsBMP = Value <= 0xD7FF || (Value >= 0xE000 && Value <= 0xFFFF); + bool IsBMP = Value <= 0xDFFF || (Value >= 0xE000 && Value <= 0xFFFF); bool ConversionPreservesSemantics = IsASCII || (!Source->isChar8Type() && !Target->isChar8Type() && IsBMP); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 87dd682..829bd87 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -432,7 +432,7 @@ private: // XXX: It is SLOW! Use it very carefully. std::optional<MultiLevelTemplateArgumentList> SubstitutionInTemplateArguments( const NormalizedConstraintWithParamMapping &Constraint, - MultiLevelTemplateArgumentList MLTAL, + const MultiLevelTemplateArgumentList &MLTAL, llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost); ExprResult EvaluateSlow(const AtomicConstraint &Constraint, @@ -564,8 +564,8 @@ ExprResult ConstraintSatisfactionChecker::EvaluateAtomicConstraint( std::optional<MultiLevelTemplateArgumentList> ConstraintSatisfactionChecker::SubstitutionInTemplateArguments( const NormalizedConstraintWithParamMapping &Constraint, - MultiLevelTemplateArgumentList MLTAL, - llvm::SmallVector<TemplateArgument> &SubstitutedOuterMost) { + const MultiLevelTemplateArgumentList &MLTAL, + llvm::SmallVector<TemplateArgument> &SubstitutedOutermost) { if (!Constraint.hasParameterMapping()) return std::move(MLTAL); @@ -607,7 +607,7 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments( // The empty MLTAL situation should only occur when evaluating non-dependent // constraints. if (MLTAL.getNumSubstitutedLevels()) - SubstitutedOuterMost = + SubstitutedOutermost = llvm::to_vector_of<TemplateArgument>(MLTAL.getOutermost()); unsigned Offset = 0; for (unsigned I = 0, MappedIndex = 0; I < Used.size(); I++) { @@ -615,19 +615,19 @@ ConstraintSatisfactionChecker::SubstitutionInTemplateArguments( if (Used[I]) Arg = S.Context.getCanonicalTemplateArgument( CTAI.SugaredConverted[MappedIndex++]); - if (I < SubstitutedOuterMost.size()) { - SubstitutedOuterMost[I] = Arg; + if (I < SubstitutedOutermost.size()) { + SubstitutedOutermost[I] = Arg; Offset = I + 1; } else { - SubstitutedOuterMost.push_back(Arg); - Offset = SubstitutedOuterMost.size(); + SubstitutedOutermost.push_back(Arg); + Offset = SubstitutedOutermost.size(); } } - if (Offset < SubstitutedOuterMost.size()) - SubstitutedOuterMost.erase(SubstitutedOuterMost.begin() + Offset); + if (Offset < SubstitutedOutermost.size()) + SubstitutedOutermost.erase(SubstitutedOutermost.begin() + Offset); MultiLevelTemplateArgumentList SubstitutedTemplateArgs; - SubstitutedTemplateArgs.addOuterTemplateArguments(TD, SubstitutedOuterMost, + SubstitutedTemplateArgs.addOuterTemplateArguments(TD, SubstitutedOutermost, /*Final=*/false); return std::move(SubstitutedTemplateArgs); } @@ -636,9 +636,9 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( const AtomicConstraint &Constraint, const MultiLevelTemplateArgumentList &MLTAL) { - llvm::SmallVector<TemplateArgument> SubstitutedOuterMost; + llvm::SmallVector<TemplateArgument> SubstitutedOutermost; std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs = - SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost); + SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOutermost); if (!SubstitutedArgs) { Satisfaction.IsSatisfied = false; return ExprEmpty(); @@ -786,13 +786,13 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( FoldExpandedConstraint::FoldOperatorKind::And; unsigned EffectiveDetailEndIndex = Satisfaction.Details.size(); - llvm::SmallVector<TemplateArgument> SubstitutedOuterMost; + llvm::SmallVector<TemplateArgument> SubstitutedOutermost; // FIXME: Is PackSubstitutionIndex correct? llvm::SaveAndRestore _(PackSubstitutionIndex, S.ArgPackSubstIndex); std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs = SubstitutionInTemplateArguments( static_cast<const NormalizedConstraintWithParamMapping &>(Constraint), - MLTAL, SubstitutedOuterMost); + MLTAL, SubstitutedOutermost); if (!SubstitutedArgs) { Satisfaction.IsSatisfied = false; return ExprError(); @@ -880,9 +880,9 @@ ExprResult ConstraintSatisfactionChecker::EvaluateSlow( const MultiLevelTemplateArgumentList &MLTAL, unsigned Size) { const ConceptReference *ConceptId = Constraint.getConceptId(); - llvm::SmallVector<TemplateArgument> SubstitutedOuterMost; + llvm::SmallVector<TemplateArgument> SubstitutedOutermost; std::optional<MultiLevelTemplateArgumentList> SubstitutedArgs = - SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOuterMost); + SubstitutionInTemplateArguments(Constraint, MLTAL, SubstitutedOutermost); if (!SubstitutedArgs) { Satisfaction.IsSatisfied = false; @@ -1217,13 +1217,51 @@ bool Sema::CheckConstraintSatisfaction( return false; } +static const ExprResult +SubstituteConceptsInConstrainExpression(Sema &S, const NamedDecl *D, + const ConceptSpecializationExpr *CSE, + UnsignedOrNone SubstIndex) { + + // [C++2c] [temp.constr.normal] + // Otherwise, to form CE, any non-dependent concept template argument Ai + // is substituted into the constraint-expression of C. + // If any such substitution results in an invalid concept-id, + // the program is ill-formed; no diagnostic is required. + + ConceptDecl *Concept = CSE->getNamedConcept()->getCanonicalDecl(); + Sema::ArgPackSubstIndexRAII _(S, SubstIndex); + + const ASTTemplateArgumentListInfo *ArgsAsWritten = + CSE->getTemplateArgsAsWritten(); + if (llvm::none_of( + ArgsAsWritten->arguments(), [&](const TemplateArgumentLoc &ArgLoc) { + return !ArgLoc.getArgument().isDependent() && + ArgLoc.getArgument().isConceptOrConceptTemplateParameter(); + })) { + return Concept->getConstraintExpr(); + } + + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( + Concept, Concept->getLexicalDeclContext(), + /*Final=*/false, CSE->getTemplateArguments(), + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); + return S.SubstConceptTemplateArguments(CSE, Concept->getConstraintExpr(), + MLTAL); +} + bool Sema::CheckConstraintSatisfaction( const ConceptSpecializationExpr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { + ExprResult Res = SubstituteConceptsInConstrainExpression( + *this, nullptr, ConstraintExpr, ArgPackSubstIndex); + if (!Res.isUsable()) + return true; + llvm::SmallVector<AssociatedConstraint, 1> Constraints; - Constraints.emplace_back( - ConstraintExpr->getNamedConcept()->getConstraintExpr()); + Constraints.emplace_back(Res.get()); MultiLevelTemplateArgumentList MLTAL(ConstraintExpr->getNamedConcept(), ConstraintExpr->getTemplateArguments(), @@ -2249,8 +2287,14 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr( // Use canonical declarations to merge ConceptDecls across // different modules. ConceptDecl *CD = CSE->getNamedConcept()->getCanonicalDecl(); + + ExprResult Res = + SubstituteConceptsInConstrainExpression(S, D, CSE, SubstIndex); + if (!Res.isUsable()) + return nullptr; + SubNF = NormalizedConstraint::fromAssociatedConstraints( - S, CD, AssociatedConstraint(CD->getConstraintExpr(), SubstIndex)); + S, CD, AssociatedConstraint(Res.get(), SubstIndex)); if (!SubNF) return nullptr; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 04d46d6..fc3aabf 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7640,6 +7640,58 @@ static bool isMainVar(DeclarationName Name, VarDecl *VD) { VD->isExternC()); } +void Sema::CheckAsmLabel(Scope *S, Expr *E, StorageClass SC, + TypeSourceInfo *TInfo, VarDecl *NewVD) { + + // Quickly return if the function does not have an `asm` attribute. + if (E == nullptr) + return; + + // The parser guarantees this is a string. + StringLiteral *SE = cast<StringLiteral>(E); + StringRef Label = SE->getString(); + QualType R = TInfo->getType(); + if (S->getFnParent() != nullptr) { + switch (SC) { + case SC_None: + case SC_Auto: + Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; + break; + case SC_Register: + // Local Named register + if (!Context.getTargetInfo().isValidGCCRegisterName(Label) && + DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) + Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; + break; + case SC_Static: + case SC_Extern: + case SC_PrivateExtern: + break; + } + } else if (SC == SC_Register) { + // Global Named register + if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) { + const auto &TI = Context.getTargetInfo(); + bool HasSizeMismatch; + + if (!TI.isValidGCCRegisterName(Label)) + Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; + else if (!TI.validateGlobalRegisterVariable(Label, Context.getTypeSize(R), + HasSizeMismatch)) + Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label; + else if (HasSizeMismatch) + Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label; + } + + if (!R->isIntegralType(Context) && !R->isPointerType()) { + Diag(TInfo->getTypeLoc().getBeginLoc(), + diag::err_asm_unsupported_register_type) + << TInfo->getTypeLoc().getSourceRange(); + NewVD->setInvalidDecl(true); + } + } +} + NamedDecl *Sema::ActOnVariableDeclarator( Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, @@ -8124,6 +8176,26 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } + if (Expr *E = D.getAsmLabel()) { + // The parser guarantees this is a string. + StringLiteral *SE = cast<StringLiteral>(E); + StringRef Label = SE->getString(); + + // Insert the asm attribute. + NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0))); + } else if (!ExtnameUndeclaredIdentifiers.empty()) { + llvm::DenseMap<IdentifierInfo *, AsmLabelAttr *>::iterator I = + ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); + if (I != ExtnameUndeclaredIdentifiers.end()) { + if (isDeclExternC(NewVD)) { + NewVD->addAttr(I->second); + ExtnameUndeclaredIdentifiers.erase(I); + } else + Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied) + << /*Variable*/ 1 << NewVD; + } + } + // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); @@ -8174,65 +8246,11 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (getLangOpts().ObjCAutoRefCount && ObjC().inferObjCARCLifetime(NewVD)) NewVD->setInvalidDecl(); - // Handle GNU asm-label extension (encoded as an attribute). - if (Expr *E = D.getAsmLabel()) { - // The parser guarantees this is a string. - StringLiteral *SE = cast<StringLiteral>(E); - StringRef Label = SE->getString(); - if (S->getFnParent() != nullptr) { - switch (SC) { - case SC_None: - case SC_Auto: - Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; - break; - case SC_Register: - // Local Named register - if (!Context.getTargetInfo().isValidGCCRegisterName(Label) && - DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) - Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; - break; - case SC_Static: - case SC_Extern: - case SC_PrivateExtern: - break; - } - } else if (SC == SC_Register) { - // Global Named register - if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) { - const auto &TI = Context.getTargetInfo(); - bool HasSizeMismatch; - - if (!TI.isValidGCCRegisterName(Label)) - Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; - else if (!TI.validateGlobalRegisterVariable(Label, - Context.getTypeSize(R), - HasSizeMismatch)) - Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label; - else if (HasSizeMismatch) - Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label; - } - - if (!R->isIntegralType(Context) && !R->isPointerType()) { - Diag(TInfo->getTypeLoc().getBeginLoc(), - diag::err_asm_unsupported_register_type) - << TInfo->getTypeLoc().getSourceRange(); - NewVD->setInvalidDecl(true); - } - } - - NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0))); - } else if (!ExtnameUndeclaredIdentifiers.empty()) { - llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I = - ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); - if (I != ExtnameUndeclaredIdentifiers.end()) { - if (isDeclExternC(NewVD)) { - NewVD->addAttr(I->second); - ExtnameUndeclaredIdentifiers.erase(I); - } else - Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied) - << /*Variable*/1 << NewVD; - } - } + // Check the ASM label here, as we need to know all other attributes of the + // Decl first. Otherwise, we can't know if the asm label refers to the + // host or device in a CUDA context. The device has other registers than + // host and we must know where the function will be placed. + CheckAsmLabel(S, D.getAsmLabel(), SC, TInfo, NewVD); // Find the shadowed declaration before filtering for scope. NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty() diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index e6f8748..9475b8a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5676,6 +5676,114 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { AL.getNumArgs() > 2 ? AL.getArgAsExpr(2) : nullptr); } +static std::pair<Expr *, int> +makeClusterDimsArgExpr(Sema &S, Expr *E, const CUDAClusterDimsAttr &AL, + const unsigned Idx) { + if (!E || S.DiagnoseUnexpandedParameterPack(E)) + return {}; + + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (E->isInstantiationDependent()) + return {E, 1}; + + std::optional<llvm::APSInt> I = E->getIntegerConstantExpr(S.Context); + if (!I) { + S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) + << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); + return {}; + } + // Make sure we can fit it in 4 bits. + if (!I->isIntN(4)) { + S.Diag(E->getExprLoc(), diag::err_ice_too_large) + << toString(*I, 10, false) << 4 << /*Unsigned=*/1; + return {}; + } + if (*I < 0) { + S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative) + << &AL << Idx << E->getSourceRange(); + } + + return {ConstantExpr::Create(S.getASTContext(), E, APValue(*I)), + I->getZExtValue()}; +} + +CUDAClusterDimsAttr *Sema::createClusterDimsAttr(const AttributeCommonInfo &CI, + Expr *X, Expr *Y, Expr *Z) { + CUDAClusterDimsAttr TmpAttr(Context, CI, X, Y, Z); + + auto [NewX, ValX] = makeClusterDimsArgExpr(*this, X, TmpAttr, /*Idx=*/0); + auto [NewY, ValY] = makeClusterDimsArgExpr(*this, Y, TmpAttr, /*Idx=*/1); + auto [NewZ, ValZ] = makeClusterDimsArgExpr(*this, Z, TmpAttr, /*Idx=*/2); + + if (!NewX || (Y && !NewY) || (Z && !NewZ)) + return nullptr; + + int FlatDim = ValX * ValY * ValZ; + const llvm::Triple TT = + (!Context.getLangOpts().CUDAIsDevice && Context.getAuxTargetInfo()) + ? Context.getAuxTargetInfo()->getTriple() + : Context.getTargetInfo().getTriple(); + int MaxDim = 1; + if (TT.isNVPTX()) + MaxDim = 8; + else if (TT.isAMDGPU()) + MaxDim = 16; + else + return nullptr; + + // A maximum of 8 thread blocks in a cluster is supported as a portable + // cluster size in CUDA. The number is 16 for AMDGPU. + if (FlatDim > MaxDim) { + Diag(CI.getLoc(), diag::err_cluster_dims_too_large) << MaxDim << FlatDim; + return nullptr; + } + + return CUDAClusterDimsAttr::Create(Context, NewX, NewY, NewZ, CI); +} + +void Sema::addClusterDimsAttr(Decl *D, const AttributeCommonInfo &CI, Expr *X, + Expr *Y, Expr *Z) { + if (auto *Attr = createClusterDimsAttr(CI, X, Y, Z)) + D->addAttr(Attr); +} + +void Sema::addNoClusterAttr(Decl *D, const AttributeCommonInfo &CI) { + D->addAttr(CUDANoClusterAttr::Create(Context, CI)); +} + +static void handleClusterDimsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const TargetInfo &TTI = S.Context.getTargetInfo(); + OffloadArch Arch = StringToOffloadArch(TTI.getTargetOpts().CPU); + if ((TTI.getTriple().isNVPTX() && Arch < clang::OffloadArch::SM_90) || + (TTI.getTriple().isAMDGPU() && + !TTI.hasFeatureEnabled(TTI.getTargetOpts().FeatureMap, "clusters"))) { + S.Diag(AL.getLoc(), diag::err_cluster_attr_not_supported) << AL; + return; + } + + if (!AL.checkAtLeastNumArgs(S, /*Num=*/1) || + !AL.checkAtMostNumArgs(S, /*Num=*/3)) + return; + + S.addClusterDimsAttr(D, AL, AL.getArgAsExpr(0), + AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr, + AL.getNumArgs() > 2 ? AL.getArgAsExpr(2) : nullptr); +} + +static void handleNoClusterAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const TargetInfo &TTI = S.Context.getTargetInfo(); + OffloadArch Arch = StringToOffloadArch(TTI.getTargetOpts().CPU); + if ((TTI.getTriple().isNVPTX() && Arch < clang::OffloadArch::SM_90) || + (TTI.getTriple().isAMDGPU() && + !TTI.hasFeatureEnabled(TTI.getTargetOpts().FeatureMap, "clusters"))) { + S.Diag(AL.getLoc(), diag::err_cluster_attr_not_supported) << AL; + return; + } + + S.addNoClusterAttr(D, AL); +} + static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { @@ -7141,6 +7249,12 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_CUDALaunchBounds: handleLaunchBoundsAttr(S, D, AL); break; + case ParsedAttr::AT_CUDAClusterDims: + handleClusterDimsAttr(S, D, AL); + break; + case ParsedAttr::AT_CUDANoCluster: + handleNoClusterAttr(S, D, AL); + break; case ParsedAttr::AT_Restrict: handleRestrictAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3e0e9bb..dca9d6e 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15944,6 +15944,20 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } + } else if (Context.getLangOpts().HLSL && resultType->isVectorType() && + !resultType->hasBooleanRepresentation()) { + // HLSL unary logical 'not' behaves like C++, which states that the + // operand is converted to bool and the result is bool, however HLSL + // extends this property to vectors. + const VectorType *VTy = resultType->castAs<VectorType>(); + resultType = + Context.getExtVectorType(Context.BoolTy, VTy->getNumElements()); + + Input = ImpCastExprToType( + Input.get(), resultType, + ScalarTypeToBooleanCastKind(VTy->getElementType())) + .get(); + break; } else if (resultType->isExtVectorType()) { if (Context.getLangOpts().OpenCL && Context.getLangOpts().getOpenCLCompatibleVersion() < 120) { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f347066..5b3e89f 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3006,6 +3006,24 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { TheCall->setType(CounterHandleTy); break; } + case Builtin::BI__builtin_hlsl_resource_getdimensions_x: { + ASTContext &AST = SemaRef.getASTContext(); + if (SemaRef.checkArgCount(TheCall, 2) || + CheckResourceHandle(&SemaRef, TheCall, 0) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) || + CheckModifiableLValue(&SemaRef, TheCall, 1)) + return true; + break; + } + case Builtin::BI__builtin_hlsl_resource_getstride: { + ASTContext &AST = SemaRef.getASTContext(); + if (SemaRef.checkArgCount(TheCall, 2) || + CheckResourceHandle(&SemaRef, TheCall, 0) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) || + CheckModifiableLValue(&SemaRef, TheCall, 1)) + return true; + break; + } case Builtin::BI__builtin_hlsl_and: case Builtin::BI__builtin_hlsl_or: { if (SemaRef.checkArgCount(TheCall, 2)) diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index 3ba93ff9..c5ef0d5 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -1464,7 +1464,8 @@ void SemaRISCV::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, } else if (Info.ElementType->isBFloat16Type() && !FeatureMap.lookup("zvfbfmin") && - !FeatureMap.lookup("xandesvbfhcvt")) + !FeatureMap.lookup("xandesvbfhcvt") && + !FeatureMap.lookup("experimental-zvfbfa")) if (DeclareAndesVectorBuiltins) { Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfbfmin or xandesvbfhcvt"; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index bec2820..7f85805 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -35,6 +35,7 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/ADT/SmallVectorExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SaveAndRestore.h" @@ -638,15 +639,8 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( } Invalid = SemaRef.pushCodeSynthesisContext(Inst); - if (!Invalid) { - AlreadyInstantiating = - !Inst.Entity - ? false - : !SemaRef.InstantiatingSpecializations - .insert({Inst.Entity->getCanonicalDecl(), Inst.Kind}) - .second; + if (!Invalid) atTemplateBegin(SemaRef.TemplateInstCallbacks, SemaRef, Inst); - } } Sema::InstantiatingTemplate::InstantiatingTemplate( @@ -901,13 +895,6 @@ void Sema::popCodeSynthesisContext() { void Sema::InstantiatingTemplate::Clear() { if (!Invalid) { - if (!AlreadyInstantiating) { - auto &Active = SemaRef.CodeSynthesisContexts.back(); - if (Active.Entity) - SemaRef.InstantiatingSpecializations.erase( - {Active.Entity->getCanonicalDecl(), Active.Kind}); - } - atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, SemaRef.CodeSynthesisContexts.back()); @@ -2863,9 +2850,9 @@ TemplateInstantiator::TransformNestedRequirement( TemplateArgs, Constraint->getSourceRange(), Satisfaction, /*TopLevelConceptId=*/nullptr, &NewConstraint); - assert(!Success || !Trap.hasErrorOccurred() && - "Substitution failures must be handled " - "by CheckConstraintSatisfaction."); + assert((!Success || !Trap.hasErrorOccurred()) && + "Substitution failures must be handled " + "by CheckConstraintSatisfaction."); } if (!Success || Satisfaction.HasSubstitutionFailure()) @@ -3311,17 +3298,20 @@ bool Sema::SubstDefaultArgument( FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext()); Expr *PatternExpr = Param->getUninstantiatedDefaultArg(); + RecursiveInstGuard AlreadyInstantiating( + *this, Param, RecursiveInstGuard::Kind::DefaultArgument); + if (AlreadyInstantiating) { + Param->setInvalidDecl(); + return Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) + << FD << PatternExpr->getSourceRange(); + } + EnterExpressionEvaluationContext EvalContext( *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); InstantiatingTemplate Inst(*this, Loc, Param, TemplateArgs.getInnermost()); if (Inst.isInvalid()) return true; - if (Inst.isAlreadyInstantiating()) { - Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; - Param->setInvalidDecl(); - return true; - } ExprResult Result; // C++ [dcl.fct.default]p5: @@ -3553,12 +3543,26 @@ namespace clang { } } -bool -Sema::InstantiateClass(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, - const MultiLevelTemplateArgumentList &TemplateArgs, - TemplateSpecializationKind TSK, - bool Complain) { +bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, bool Complain) { +#ifndef NDEBUG + RecursiveInstGuard AlreadyInstantiating(*this, Instantiation, + RecursiveInstGuard::Kind::Template); + assert(!AlreadyInstantiating && "should have been caught by caller"); +#endif + + return InstantiateClassImpl(PointOfInstantiation, Instantiation, Pattern, + TemplateArgs, TSK, Complain); +} + +bool Sema::InstantiateClassImpl( + SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, bool Complain) { + CXXRecordDecl *PatternDef = cast_or_null<CXXRecordDecl>(Pattern->getDefinition()); if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, @@ -3595,7 +3599,6 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; - assert(!Inst.isAlreadyInstantiating() && "should have been caught by caller"); PrettyDeclStackTraceEntry CrashInfo(Context, Instantiation, SourceLocation(), "instantiating class definition"); @@ -3807,6 +3810,12 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, EnumDecl *Instantiation, EnumDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK) { +#ifndef NDEBUG + RecursiveInstGuard AlreadyInstantiating(*this, Instantiation, + RecursiveInstGuard::Kind::Template); + assert(!AlreadyInstantiating && "should have been caught by caller"); +#endif + EnumDecl *PatternDef = Pattern->getDefinition(); if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, Instantiation->getInstantiatedFromMemberEnum(), @@ -3824,8 +3833,6 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; - if (Inst.isAlreadyInstantiating()) - return false; PrettyDeclStackTraceEntry CrashInfo(Context, Instantiation, SourceLocation(), "instantiating enum definition"); @@ -3864,6 +3871,14 @@ bool Sema::InstantiateInClassInitializer( Pattern->getInClassInitStyle() && "pattern and instantiation disagree about init style"); + RecursiveInstGuard AlreadyInstantiating(*this, Instantiation, + RecursiveInstGuard::Kind::Template); + if (AlreadyInstantiating) + // Error out if we hit an instantiation cycle for this initializer. + return Diag(PointOfInstantiation, + diag::err_default_member_initializer_cycle) + << Instantiation; + // Error out if we haven't parsed the initializer of the pattern yet because // we are waiting for the closing brace of the outer class. Expr *OldInit = Pattern->getInClassInitializer(); @@ -3882,12 +3897,6 @@ bool Sema::InstantiateInClassInitializer( InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; - if (Inst.isAlreadyInstantiating()) { - // Error out if we hit an instantiation cycle for this initializer. - Diag(PointOfInstantiation, diag::err_default_member_initializer_cycle) - << Instantiation; - return true; - } PrettyDeclStackTraceEntry CrashInfo(Context, Instantiation, SourceLocation(), "instantiating default member init"); @@ -3971,8 +3980,6 @@ static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization( Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec); if (Inst.isInvalid()) return {/*Invalid=*/true}; - if (Inst.isAlreadyInstantiating()) - return {/*Invalid=*/false}; llvm::PointerUnion<ClassTemplateDecl *, ClassTemplatePartialSpecializationDecl *> @@ -4135,6 +4142,11 @@ bool Sema::InstantiateClassTemplateSpecialization( if (ClassTemplateSpec->isInvalidDecl()) return true; + Sema::RecursiveInstGuard AlreadyInstantiating( + *this, ClassTemplateSpec, Sema::RecursiveInstGuard::Kind::Template); + if (AlreadyInstantiating) + return false; + bool HadAvaibilityWarning = ShouldDiagnoseAvailabilityOfDecl(ClassTemplateSpec, nullptr, nullptr) .first != AR_Available; @@ -4147,7 +4159,7 @@ bool Sema::InstantiateClassTemplateSpecialization( if (!Pattern.isUsable()) return Pattern.isInvalid(); - bool Err = InstantiateClass( + bool Err = InstantiateClassImpl( PointOfInstantiation, ClassTemplateSpec, Pattern.get(), getTemplateInstantiationArgs(ClassTemplateSpec), TSK, Complain); @@ -4487,6 +4499,119 @@ ExprResult Sema::SubstConstraintExprWithoutSatisfaction( return Instantiator.TransformExpr(E); } +ExprResult Sema::SubstConceptTemplateArguments( + const ConceptSpecializationExpr *CSE, const Expr *ConstraintExpr, + const MultiLevelTemplateArgumentList &MLTAL) { + TemplateInstantiator Instantiator(*this, MLTAL, SourceLocation(), + DeclarationName()); + const ASTTemplateArgumentListInfo *ArgsAsWritten = + CSE->getTemplateArgsAsWritten(); + TemplateArgumentListInfo SubstArgs(ArgsAsWritten->getLAngleLoc(), + ArgsAsWritten->getRAngleLoc()); + + Sema::InstantiatingTemplate Inst( + *this, ArgsAsWritten->arguments().front().getSourceRange().getBegin(), + Sema::InstantiatingTemplate::ConstraintNormalization{}, + CSE->getNamedConcept(), + ArgsAsWritten->arguments().front().getSourceRange()); + + if (Inst.isInvalid()) + return ExprError(); + + if (Instantiator.TransformConceptTemplateArguments( + ArgsAsWritten->getTemplateArgs(), + ArgsAsWritten->getTemplateArgs() + + ArgsAsWritten->getNumTemplateArgs(), + SubstArgs)) + return true; + + llvm::SmallVector<TemplateArgument, 4> NewArgList = llvm::map_to_vector( + SubstArgs.arguments(), + [](const TemplateArgumentLoc &Loc) { return Loc.getArgument(); }); + + MultiLevelTemplateArgumentList MLTALForConstraint = + getTemplateInstantiationArgs( + CSE->getNamedConcept(), + CSE->getNamedConcept()->getLexicalDeclContext(), + /*Final=*/false, + /*Innermost=*/NewArgList, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); + + // Rebuild a constraint, only substituting non-dependent concept names + // and nothing else. + // Given C<SomeType, SomeValue, SomeConceptName, SomeDependentConceptName>. + // only SomeConceptName is substituted, in the constraint expression of C. + struct ConstraintExprTransformer : TreeTransform<ConstraintExprTransformer> { + using Base = TreeTransform<ConstraintExprTransformer>; + MultiLevelTemplateArgumentList &MLTAL; + + ConstraintExprTransformer(Sema &SemaRef, + MultiLevelTemplateArgumentList &MLTAL) + : TreeTransform(SemaRef), MLTAL(MLTAL) {} + + ExprResult TransformExpr(Expr *E) { + if (!E) + return E; + switch (E->getStmtClass()) { + case Stmt::BinaryOperatorClass: + case Stmt::ConceptSpecializationExprClass: + case Stmt::ParenExprClass: + case Stmt::UnresolvedLookupExprClass: + return Base::TransformExpr(E); + default: + break; + } + return E; + } + + // Rebuild both branches of a conjunction / disjunction + // even if there is a substitution failure in one of + // the branch. + ExprResult TransformBinaryOperator(BinaryOperator *E) { + if (!(E->getOpcode() == BinaryOperatorKind::BO_LAnd || + E->getOpcode() == BinaryOperatorKind::BO_LOr)) + return E; + + ExprResult LHS = TransformExpr(E->getLHS()); + ExprResult RHS = TransformExpr(E->getRHS()); + + if (LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) + return E; + + return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(), + E->getOpcode(), SemaRef.Context.BoolTy, + VK_PRValue, OK_Ordinary, + E->getOperatorLoc(), FPOptionsOverride{}); + } + + bool TransformTemplateArgument(const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output, + bool Uneval = false) { + if (Input.getArgument().isConceptOrConceptTemplateParameter()) + return Base::TransformTemplateArgument(Input, Output, Uneval); + + Output = Input; + return false; + } + + ExprResult TransformUnresolvedLookupExpr(UnresolvedLookupExpr *E, + bool IsAddressOfOperand = false) { + if (E->isConceptReference()) { + ExprResult Res = SemaRef.SubstExpr(E, MLTAL); + return Res; + } + return E; + } + }; + + ConstraintExprTransformer Transformer(*this, MLTALForConstraint); + ExprResult Res = + Transformer.TransformExpr(const_cast<Expr *>(ConstraintExpr)); + return Res; +} + ExprResult Sema::SubstInitializer(Expr *Init, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 468bc1d..28925cc 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -707,6 +707,23 @@ static void instantiateDependentAMDGPUMaxNumWorkGroupsAttr( S.AMDGPU().addAMDGPUMaxNumWorkGroupsAttr(New, Attr, XExpr, YExpr, ZExpr); } +static void instantiateDependentCUDAClusterDimsAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const CUDAClusterDimsAttr &Attr, Decl *New) { + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + auto SubstElt = [&S, &TemplateArgs](Expr *E) { + return E ? S.SubstExpr(E, TemplateArgs).get() : nullptr; + }; + + Expr *XExpr = SubstElt(Attr.getX()); + Expr *YExpr = SubstElt(Attr.getY()); + Expr *ZExpr = SubstElt(Attr.getZ()); + + S.addClusterDimsAttr(New, Attr, XExpr, YExpr, ZExpr); +} + // This doesn't take any template parameters, but we have a custom action that // needs to happen when the kernel itself is instantiated. We need to run the // ItaniumMangler to mark the names required to name this kernel. @@ -765,10 +782,18 @@ static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) { static void instantiateDependentHLSLParamModifierAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, - const HLSLParamModifierAttr *Attr, Decl *New) { - ParmVarDecl *P = cast<ParmVarDecl>(New); - P->addAttr(Attr->clone(S.getASTContext())); - P->setType(S.HLSL().getInoutParameterType(P->getType())); + const HLSLParamModifierAttr *Attr, const Decl *Old, Decl *New) { + ParmVarDecl *NewParm = cast<ParmVarDecl>(New); + NewParm->addAttr(Attr->clone(S.getASTContext())); + + const Type *OldParmTy = cast<ParmVarDecl>(Old)->getType().getTypePtr(); + if (OldParmTy->isDependentType() && Attr->isAnyOut()) + NewParm->setType(S.HLSL().getInoutParameterType(NewParm->getType())); + + assert( + (!Attr->isAnyOut() || (NewParm->getType().isRestrictQualified() && + NewParm->getType()->isReferenceType())) && + "out or inout parameter type must be a reference and restrict qualified"); } void Sema::InstantiateAttrsForDecl( @@ -921,9 +946,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, *this, TemplateArgs, *AMDGPUMaxNumWorkGroups, New); } + if (const auto *CUDAClusterDims = dyn_cast<CUDAClusterDimsAttr>(TmplAttr)) { + instantiateDependentCUDAClusterDimsAttr(*this, TemplateArgs, + *CUDAClusterDims, New); + } + if (const auto *ParamAttr = dyn_cast<HLSLParamModifierAttr>(TmplAttr)) { instantiateDependentHLSLParamModifierAttr(*this, TemplateArgs, ParamAttr, - New); + Tmpl, New); continue; } @@ -5282,6 +5312,16 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, if (Proto->getExceptionSpecType() != EST_Uninstantiated) return; + RecursiveInstGuard AlreadyInstantiating( + *this, Decl, RecursiveInstGuard::Kind::ExceptionSpec); + if (AlreadyInstantiating) { + // This exception specification indirectly depends on itself. Reject. + // FIXME: Corresponding rule in the standard? + Diag(PointOfInstantiation, diag::err_exception_spec_cycle) << Decl; + UpdateExceptionSpec(Decl, EST_None); + return; + } + InstantiatingTemplate Inst(*this, PointOfInstantiation, Decl, InstantiatingTemplate::ExceptionSpecification()); if (Inst.isInvalid()) { @@ -5290,13 +5330,6 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, UpdateExceptionSpec(Decl, EST_None); return; } - if (Inst.isAlreadyInstantiating()) { - // This exception specification indirectly depends on itself. Reject. - // FIXME: Corresponding rule in the standard? - Diag(PointOfInstantiation, diag::err_exception_spec_cycle) << Decl; - UpdateExceptionSpec(Decl, EST_None); - return; - } // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. @@ -5356,8 +5389,6 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, if (ActiveInst.Kind == ActiveInstType::ExplicitTemplateArgumentSubstitution || ActiveInst.Kind == ActiveInstType::DeducedTemplateArgumentSubstitution) { if (isa<FunctionTemplateDecl>(ActiveInst.Entity)) { - SemaRef.InstantiatingSpecializations.erase( - {ActiveInst.Entity->getCanonicalDecl(), ActiveInst.Kind}); atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, ActiveInst); ActiveInst.Kind = ActiveInstType::TemplateInstantiation; ActiveInst.Entity = New; @@ -5515,6 +5546,12 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, Function = const_cast<FunctionDecl*>(ExistingDefn); } +#ifndef NDEBUG + RecursiveInstGuard AlreadyInstantiating(*this, Function, + RecursiveInstGuard::Kind::Template); + assert(!AlreadyInstantiating && "should have been caught by caller"); +#endif + // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); assert(PatternDecl && "instantiating a non-template"); @@ -5654,7 +5691,7 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, } InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); - if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) + if (Inst.isInvalid()) return; PrettyDeclStackTraceEntry CrashInfo(Context, Function, SourceLocation(), "instantiating function definition"); @@ -6223,6 +6260,11 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, if (TSK == TSK_ExplicitSpecialization) return; + RecursiveInstGuard AlreadyInstantiating(*this, Var, + RecursiveInstGuard::Kind::Template); + if (AlreadyInstantiating) + return; + // Find the pattern and the arguments to substitute into it. VarDecl *PatternDecl = Var->getTemplateInstantiationPattern(); assert(PatternDecl && "no pattern for templated variable"); @@ -6246,7 +6288,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // FIXME: Factor out the duplicated instantiation context setup/tear down // code here. InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); - if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) + if (Inst.isInvalid()) return; PrettyDeclStackTraceEntry CrashInfo(Context, Var, SourceLocation(), "instantiating variable initializer"); @@ -6350,7 +6392,7 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, } InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); - if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) + if (Inst.isInvalid()) return; PrettyDeclStackTraceEntry CrashInfo(Context, Var, SourceLocation(), "instantiating variable definition"); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 86896ab..29f0c30 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -694,6 +694,12 @@ public: TemplateArgumentListInfo &Outputs, bool Uneval = false); + template <typename InputIterator> + bool TransformConceptTemplateArguments(InputIterator First, + InputIterator Last, + TemplateArgumentListInfo &Outputs, + bool Uneval = false); + /// Checks if the argument pack from \p In will need to be expanded and does /// the necessary prework. /// Whether the expansion is needed is captured in Info.Expand. @@ -5192,6 +5198,49 @@ bool TreeTransform<Derived>::TransformTemplateArguments( return false; } +template <typename Derived> +template <typename InputIterator> +bool TreeTransform<Derived>::TransformConceptTemplateArguments( + InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs, + bool Uneval) { + + // [C++26][temp.constr.normal] + // any non-dependent concept template argument + // is substituted into the constraint-expression of C. + auto isNonDependentConceptArgument = [](const TemplateArgument &Arg) { + return !Arg.isDependent() && Arg.isConceptOrConceptTemplateParameter(); + }; + + for (; First != Last; ++First) { + TemplateArgumentLoc Out; + TemplateArgumentLoc In = *First; + + if (In.getArgument().getKind() == TemplateArgument::Pack) { + typedef TemplateArgumentLocInventIterator<Derived, + TemplateArgument::pack_iterator> + PackLocIterator; + if (TransformConceptTemplateArguments( + PackLocIterator(*this, In.getArgument().pack_begin()), + PackLocIterator(*this, In.getArgument().pack_end()), Outputs, + Uneval)) + return true; + continue; + } + + if (!isNonDependentConceptArgument(In.getArgument())) { + Outputs.addArgument(In); + continue; + } + + if (getDerived().TransformTemplateArgument(In, Out, Uneval)) + return true; + + Outputs.addArgument(Out); + } + + return false; +} + // FIXME: Find ways to reduce code duplication for pack expansions. template <typename Derived> bool TreeTransform<Derived>::PreparePackForExpansion(TemplateArgumentLoc In, |