diff options
| author | Mingming Liu <mingmingl@google.com> | 2025-09-10 15:25:31 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-10 15:25:31 -0700 |
| commit | 1417dafa1db9cb1b2b09438aa9f53ea5ab6e36e2 (patch) | |
| tree | 57f4b1f313c8cf74eed8819870f39c36ea263c68 /clang/lib/Sema | |
| parent | 898b813bc8a6d0276bf0f4769f5f2f64b34e632d (diff) | |
| parent | b8cefcb601ddaa18482555c4ff363c01a270c2fe (diff) | |
Merge branch 'main' into users/mingmingl-llvm/samplefdo-profile-formatusers/mingmingl-llvm/samplefdo-profile-format
Diffstat (limited to 'clang/lib/Sema')
49 files changed, 2099 insertions, 1295 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 0b94b1044f07..1b66d83df517 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2905,6 +2905,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( AC.getCFGBuildOptions().AddCXXNewAllocator = false; AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true; + bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety; + // Force that certain expressions appear as CFGElements in the CFG. This // is used to speed up various analyses. // FIXME: This isn't the right factoring. This is here for initial @@ -2912,11 +2914,10 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( // expect to always be CFGElements and then fill in the BuildOptions // appropriately. This is essentially a layering violation. if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis || - P.enableConsumedAnalysis) { + P.enableConsumedAnalysis || EnableLifetimeSafetyAnalysis) { // Unreachable code analysis and thread safety require a linearized CFG. AC.getCFGBuildOptions().setAllAlwaysAdd(); - } - else { + } else { AC.getCFGBuildOptions() .setAlwaysAdd(Stmt::BinaryOperatorClass) .setAlwaysAdd(Stmt::CompoundAssignOperatorClass) @@ -2927,7 +2928,6 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( .setAlwaysAdd(Stmt::UnaryOperatorClass); } - bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety; // Install the logical handler. std::optional<LogicalErrorHandler> LEH; if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 806800cb7b21..ecf9cfde8aa7 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaHLSL.h" @@ -102,6 +103,13 @@ private: : NameII(NameII), Ty(Ty), Modifier(Modifier) {} }; + struct LocalVar { + StringRef Name; + QualType Ty; + VarDecl *Decl; + LocalVar(StringRef Name, QualType Ty) : Name(Name), Ty(Ty), Decl(nullptr) {} + }; + BuiltinTypeDeclBuilder &DeclBuilder; DeclarationName Name; QualType ReturnTy; @@ -110,6 +118,7 @@ private: CXXMethodDecl *Method; bool IsConst; bool IsCtor; + StorageClass SC; llvm::SmallVector<Param> Params; llvm::SmallVector<Stmt *> StmtsList; @@ -123,6 +132,7 @@ private: enum class PlaceHolder { _0, _1, _2, _3, _4, Handle = 128, LastStmt }; Expr *convertPlaceholder(PlaceHolder PH); + Expr *convertPlaceholder(LocalVar &Var); Expr *convertPlaceholder(Expr *E) { return E; } public: @@ -130,13 +140,13 @@ public: BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name, QualType ReturnTy, bool IsConst = false, - bool IsCtor = false) + bool IsCtor = false, StorageClass SC = SC_None) : DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr), - IsConst(IsConst), IsCtor(IsCtor) {} + IsConst(IsConst), IsCtor(IsCtor), SC(SC) {} BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr, QualType ReturnTy, bool IsConst = false, - bool IsCtor = false); + bool IsCtor = false, StorageClass SC = SC_None); BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete; ~BuiltinTypeMethodBuilder() { finalize(); } @@ -147,12 +157,20 @@ public: BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty, HLSLParamModifierAttr::Spelling Modifier = HLSLParamModifierAttr::Keyword_in); + BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var); template <typename... Ts> BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName, QualType ReturnType, Ts... ArgSpecs); template <typename TLHS, typename TRHS> BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS); template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr); + template <typename T> + BuiltinTypeMethodBuilder &accessHandleFieldOnResource(T ResourceRecord); + template <typename ResourceT, typename ValueT> + BuiltinTypeMethodBuilder &setHandleFieldOnResource(ResourceT ResourceRecord, + ValueT HandleValue); + template <typename T> BuiltinTypeMethodBuilder &returnValue(T ReturnValue); + BuiltinTypeMethodBuilder &returnThis(); BuiltinTypeDeclBuilder &finalize(); Expr *getResourceHandleExpr(); @@ -332,15 +350,25 @@ Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) { return DeclRefExpr::Create( AST, NestedNameSpecifierLoc(), SourceLocation(), ParamDecl, false, DeclarationNameInfo(ParamDecl->getDeclName(), SourceLocation()), - ParamDecl->getType(), VK_PRValue); + ParamDecl->getType().getNonReferenceType(), VK_PRValue); +} + +Expr *BuiltinTypeMethodBuilder::convertPlaceholder(LocalVar &Var) { + VarDecl *VD = Var.Decl; + assert(VD && "local variable is not declared"); + return DeclRefExpr::Create( + VD->getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), VD, + false, DeclarationNameInfo(VD->getDeclName(), SourceLocation()), + VD->getType(), VK_LValue); } BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr, QualType ReturnTy, - bool IsConst, bool IsCtor) + bool IsConst, bool IsCtor, + StorageClass SC) : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst), - IsCtor(IsCtor) { + IsCtor(IsCtor), SC(SC) { assert((!NameStr.empty() || IsCtor) && "method needs a name"); assert(((IsCtor && !IsConst) || !IsCtor) && "constructor cannot be const"); @@ -390,10 +418,9 @@ void BuiltinTypeMethodBuilder::createDecl() { ExplicitSpecifier(), false, true, false, ConstexprSpecKind::Unspecified); else - Method = - CXXMethodDecl::Create(AST, DeclBuilder.Record, SourceLocation(), - NameInfo, FuncTy, TSInfo, SC_None, false, false, - ConstexprSpecKind::Unspecified, SourceLocation()); + Method = CXXMethodDecl::Create( + AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, SC, + false, false, ConstexprSpecKind::Unspecified, SourceLocation()); // create params & set them to the function prototype SmallVector<ParmVarDecl *> ParmDecls; @@ -431,15 +458,41 @@ Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() { OK_Ordinary); } +BuiltinTypeMethodBuilder & +BuiltinTypeMethodBuilder::declareLocalVar(LocalVar &Var) { + ensureCompleteDecl(); + + assert(Var.Decl == nullptr && "local variable is already declared"); + + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + Var.Decl = VarDecl::Create( + AST, Method, SourceLocation(), SourceLocation(), + &AST.Idents.get(Var.Name, tok::TokenKind::identifier), Var.Ty, + AST.getTrivialTypeSourceInfo(Var.Ty, SourceLocation()), SC_None); + DeclStmt *DS = new (AST) clang::DeclStmt(DeclGroupRef(Var.Decl), + SourceLocation(), SourceLocation()); + StmtsList.push_back(DS); + return *this; +} + +BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() { + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + CXXThisExpr *ThisExpr = CXXThisExpr::Create( + AST, SourceLocation(), Method->getFunctionObjectParameterType(), + /*IsImplicit=*/true); + StmtsList.push_back(ThisExpr); + return *this; +} + template <typename... Ts> BuiltinTypeMethodBuilder & BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName, QualType ReturnType, Ts... ArgSpecs) { + ensureCompleteDecl(); + std::array<Expr *, sizeof...(ArgSpecs)> Args{ convertPlaceholder(std::forward<Ts>(ArgSpecs))...}; - ensureCompleteDecl(); - ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName); DeclRefExpr *DRE = DeclRefExpr::Create( @@ -483,6 +536,55 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) { return *this; } +template <typename T> +BuiltinTypeMethodBuilder & +BuiltinTypeMethodBuilder::accessHandleFieldOnResource(T ResourceRecord) { + ensureCompleteDecl(); + + Expr *ResourceExpr = convertPlaceholder(ResourceRecord); + + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + FieldDecl *HandleField = DeclBuilder.getResourceHandleField(); + MemberExpr *HandleExpr = MemberExpr::CreateImplicit( + AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue, + OK_Ordinary); + StmtsList.push_back(HandleExpr); + return *this; +} + +template <typename ResourceT, typename ValueT> +BuiltinTypeMethodBuilder & +BuiltinTypeMethodBuilder::setHandleFieldOnResource(ResourceT ResourceRecord, + ValueT HandleValue) { + ensureCompleteDecl(); + + Expr *ResourceExpr = convertPlaceholder(ResourceRecord); + Expr *HandleValueExpr = convertPlaceholder(HandleValue); + + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + FieldDecl *HandleField = DeclBuilder.getResourceHandleField(); + MemberExpr *HandleMemberExpr = MemberExpr::CreateImplicit( + AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue, + OK_Ordinary); + Stmt *AssignStmt = BinaryOperator::Create( + DeclBuilder.SemaRef.getASTContext(), HandleMemberExpr, HandleValueExpr, + BO_Assign, HandleMemberExpr->getType(), ExprValueKind::VK_PRValue, + ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride()); + StmtsList.push_back(AssignStmt); + return *this; +} + +template <typename T> +BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnValue(T ReturnValue) { + ensureCompleteDecl(); + + Expr *ReturnValueExpr = convertPlaceholder(ReturnValue); + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + StmtsList.push_back( + ReturnStmt::Create(AST, SourceLocation(), ReturnValueExpr, nullptr)); + return *this; +} + BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() { assert(!DeclBuilder.Record->isCompleteDefinition() && "record is already complete"); @@ -510,7 +612,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() { Method->setBody(CompoundStmt::Create(AST, StmtsList, FPOptionsOverride(), SourceLocation(), SourceLocation())); Method->setLexicalDeclContext(DeclBuilder.Record); - Method->setAccess(AccessSpecifier::AS_public); + Method->setAccess(AS_public); Method->addAttr(AlwaysInlineAttr::CreateImplicit( AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline)); DeclBuilder.Record->addDecl(Method); @@ -670,12 +772,127 @@ BuiltinTypeDeclBuilder::addHandleConstructorFromImplicitBinding() { .addParam("orderId", AST.UnsignedIntTy) .addParam("name", AST.getPointerType(AST.CharTy.withConst())) .callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding", - HandleType, PH::Handle, PH::_0, PH::_1, PH::_2, PH::_3, + HandleType, PH::Handle, PH::_3, PH::_0, PH::_1, PH::_2, PH::_4) .assign(PH::Handle, PH::LastStmt) .finalize(); } +// Adds static method that initializes resource from binding: +// +// static Resource<T> __createFromBinding(unsigned registerNo, +// unsigned spaceNo, int range, +// unsigned index, const char *name) { +// Resource<T> tmp; +// tmp.__handle = __builtin_hlsl_resource_handlefrombinding( +// tmp.__handle, registerNo, spaceNo, +// range, index, name); +// return tmp; +// } +BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromBinding() { + if (Record->isCompleteDefinition()) + return *this; + + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + ASTContext &AST = SemaRef.getASTContext(); + QualType HandleType = getResourceHandleField()->getType(); + QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record)); + BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType); + + return BuiltinTypeMethodBuilder(*this, "__createFromBinding", RecordType, + false, false, SC_Static) + .addParam("registerNo", AST.UnsignedIntTy) + .addParam("spaceNo", AST.UnsignedIntTy) + .addParam("range", AST.IntTy) + .addParam("index", AST.UnsignedIntTy) + .addParam("name", AST.getPointerType(AST.CharTy.withConst())) + .declareLocalVar(TmpVar) + .accessHandleFieldOnResource(TmpVar) + .callBuiltin("__builtin_hlsl_resource_handlefrombinding", HandleType, + PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3, PH::_4) + .setHandleFieldOnResource(TmpVar, PH::LastStmt) + .returnValue(TmpVar) + .finalize(); +} + +// Adds static method that initializes resource from binding: +// +// static Resource<T> __createFromImplicitBinding(unsigned orderId, +// unsigned spaceNo, int range, +// unsigned index, +// const char *name) { +// Resource<T> tmp; +// tmp.__handle = __builtin_hlsl_resource_handlefromimplicitbinding( +// tmp.__handle, spaceNo, +// range, index, orderId, name); +// return tmp; +// } +BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromImplicitBinding() { + if (Record->isCompleteDefinition()) + return *this; + + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + ASTContext &AST = SemaRef.getASTContext(); + QualType HandleType = getResourceHandleField()->getType(); + QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record)); + BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType); + + return BuiltinTypeMethodBuilder(*this, "__createFromImplicitBinding", + RecordType, false, false, SC_Static) + .addParam("orderId", AST.UnsignedIntTy) + .addParam("spaceNo", AST.UnsignedIntTy) + .addParam("range", AST.IntTy) + .addParam("index", AST.UnsignedIntTy) + .addParam("name", AST.getPointerType(AST.CharTy.withConst())) + .declareLocalVar(TmpVar) + .accessHandleFieldOnResource(TmpVar) + .callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding", + HandleType, PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3, + PH::_4) + .setHandleFieldOnResource(TmpVar, PH::LastStmt) + .returnValue(TmpVar) + .finalize(); +} + +BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() { + if (Record->isCompleteDefinition()) + return *this; + + ASTContext &AST = SemaRef.getASTContext(); + QualType RecordType = AST.getCanonicalTagType(Record); + QualType ConstRecordType = RecordType.withConst(); + QualType ConstRecordRefType = AST.getLValueReferenceType(ConstRecordType); + + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + + return BuiltinTypeMethodBuilder(*this, /*Name=*/"", AST.VoidTy, + /*IsConst=*/false, /*IsCtor=*/true) + .addParam("other", ConstRecordRefType) + .accessHandleFieldOnResource(PH::_0) + .assign(PH::Handle, PH::LastStmt) + .finalize(); +} + +BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() { + if (Record->isCompleteDefinition()) + return *this; + + ASTContext &AST = SemaRef.getASTContext(); + QualType RecordType = AST.getCanonicalTagType(Record); + QualType ConstRecordType = RecordType.withConst(); + QualType ConstRecordRefType = AST.getLValueReferenceType(ConstRecordType); + QualType RecordRefType = AST.getLValueReferenceType(RecordType); + + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + DeclarationName Name = AST.DeclarationNames.getCXXOperatorName(OO_Equal); + return BuiltinTypeMethodBuilder(*this, Name, RecordRefType) + .addParam("other", ConstRecordRefType) + .accessHandleFieldOnResource(PH::_0) + .assign(PH::Handle, PH::LastStmt) + .returnThis() + .finalize(); +} + BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() { ASTContext &AST = Record->getASTContext(); DeclarationName Subscript = diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h index 098b72692bd3..b898417e9fe1 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h @@ -80,6 +80,12 @@ public: BuiltinTypeDeclBuilder &addDefaultHandleConstructor(); BuiltinTypeDeclBuilder &addHandleConstructorFromBinding(); BuiltinTypeDeclBuilder &addHandleConstructorFromImplicitBinding(); + BuiltinTypeDeclBuilder &addCopyConstructor(); + BuiltinTypeDeclBuilder &addCopyAssignmentOperator(); + + // Static create methods + BuiltinTypeDeclBuilder &addCreateFromBinding(); + BuiltinTypeDeclBuilder &addCreateFromImplicitBinding(); // Builtin types methods BuiltinTypeDeclBuilder &addLoadMethods(); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 726581d13162..3386d8da281e 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -132,6 +132,10 @@ static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S, return BuiltinTypeDeclBuilder(S, Decl) .addHandleMember(RC, IsROV, RawBuffer) .addDefaultHandleConstructor() + .addCopyConstructor() + .addCopyAssignmentOperator() + .addCreateFromBinding() + .addCreateFromImplicitBinding() .addHandleConstructorFromBinding() .addHandleConstructorFromImplicitBinding(); } diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 933841beeac3..6d79f3feeaac 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -255,6 +255,21 @@ QualType HeuristicResolverImpl::simplifyType(QualType Type, const Expr *E, } } } + // Check if the expression refers to an explicit object parameter of + // templated type. If so, heuristically treat it as having the type of the + // enclosing class. + if (!T.Type.isNull() && + (T.Type->isUndeducedAutoType() || T.Type->isTemplateTypeParmType())) { + if (auto *DRE = dyn_cast_if_present<DeclRefExpr>(T.E)) { + auto *PrDecl = dyn_cast<ParmVarDecl>(DRE->getDecl()); + if (PrDecl && PrDecl->isExplicitObjectParameter()) { + const auto *Parent = + dyn_cast<TagDecl>(PrDecl->getDeclContext()->getParent()); + return {Ctx.getCanonicalTagType(Parent)}; + } + } + } + return T; }; // As an additional protection against infinite loops, bound the number of diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp index ab04fe554be8..e66cce255230 100644 --- a/clang/lib/Sema/Scope.cpp +++ b/clang/lib/Sema/Scope.cpp @@ -99,6 +99,7 @@ void Scope::Init(Scope *parent, unsigned flags) { UsingDirectives.clear(); Entity = nullptr; ErrorTrap.reset(); + PrecedingLabel = nullptr; NRVO = std::nullopt; } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index b870c5af1e58..39fa25f66f3b 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1882,23 +1882,21 @@ public: // Visit the dtors of all members for (const FieldDecl *FD : RD->fields()) { QualType FT = FD->getType(); - if (const auto *RT = FT->getAs<RecordType>()) - if (const auto *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) - if (const auto *Def = ClassDecl->getDefinition()) - if (CXXDestructorDecl *MemberDtor = Def->getDestructor()) - asImpl().visitUsedDecl(MemberDtor->getLocation(), MemberDtor); + if (const auto *ClassDecl = FT->getAsCXXRecordDecl(); + ClassDecl && + (ClassDecl->isBeingDefined() || ClassDecl->isCompleteDefinition())) + if (CXXDestructorDecl *MemberDtor = ClassDecl->getDestructor()) + asImpl().visitUsedDecl(MemberDtor->getLocation(), MemberDtor); } // Also visit base class dtors for (const auto &Base : RD->bases()) { QualType BaseType = Base.getType(); - if (const auto *RT = BaseType->getAs<RecordType>()) - if (const auto *BaseDecl = - dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) - if (const auto *Def = BaseDecl->getDefinition()) - if (CXXDestructorDecl *BaseDtor = Def->getDestructor()) - asImpl().visitUsedDecl(BaseDtor->getLocation(), BaseDtor); + if (const auto *BaseDecl = BaseType->getAsCXXRecordDecl(); + BaseDecl && + (BaseDecl->isBeingDefined() || BaseDecl->isCompleteDefinition())) + if (CXXDestructorDecl *BaseDtor = BaseDecl->getDestructor()) + asImpl().visitUsedDecl(BaseDtor->getLocation(), BaseDtor); } } @@ -1909,12 +1907,11 @@ public: if (VD->isThisDeclarationADefinition() && VD->needsDestruction(S.Context)) { QualType VT = VD->getType(); - if (const auto *RT = VT->getAs<RecordType>()) - if (const auto *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) - if (const auto *Def = ClassDecl->getDefinition()) - if (CXXDestructorDecl *Dtor = Def->getDestructor()) - asImpl().visitUsedDecl(Dtor->getLocation(), Dtor); + if (const auto *ClassDecl = VT->getAsCXXRecordDecl(); + ClassDecl && (ClassDecl->isBeingDefined() || + ClassDecl->isCompleteDefinition())) + if (CXXDestructorDecl *Dtor = ClassDecl->getDestructor()) + asImpl().visitUsedDecl(Dtor->getLocation(), Dtor); } Inherited::VisitDeclStmt(DS); diff --git a/clang/lib/Sema/SemaAMDGPU.cpp b/clang/lib/Sema/SemaAMDGPU.cpp index 1913bb830ccd..baba503239e9 100644 --- a/clang/lib/Sema/SemaAMDGPU.cpp +++ b/clang/lib/Sema/SemaAMDGPU.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/TargetBuiltins.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Sema.h" +#include "llvm/Support/AMDGPUAddrSpace.h" #include "llvm/Support/AtomicOrdering.h" #include <cstdint> @@ -100,6 +101,14 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f32_fp6: case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f32_bf6: return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7); + case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_load_32x4B: + case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_load_16x8B: + case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_load_8x16B: + return checkCoopAtomicFunctionCall(TheCall, /*IsStore=*/false); + case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_store_32x4B: + case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_store_16x8B: + case AMDGPU::BI__builtin_amdgcn_cooperative_atomic_store_8x16B: + return checkCoopAtomicFunctionCall(TheCall, /*IsStore=*/true); default: return false; } @@ -145,6 +154,50 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, return false; } +bool SemaAMDGPU::checkCoopAtomicFunctionCall(CallExpr *TheCall, bool IsStore) { + bool Fail = false; + + // First argument is a global or generic pointer. + Expr *PtrArg = TheCall->getArg(0); + QualType PtrTy = PtrArg->getType()->getPointeeType(); + unsigned AS = getASTContext().getTargetAddressSpace(PtrTy.getAddressSpace()); + if (AS != llvm::AMDGPUAS::FLAT_ADDRESS && + AS != llvm::AMDGPUAS::GLOBAL_ADDRESS) { + Fail = true; + Diag(TheCall->getBeginLoc(), diag::err_amdgcn_coop_atomic_invalid_as) + << PtrArg->getSourceRange(); + } + + // Check atomic ordering + Expr *AtomicOrdArg = TheCall->getArg(IsStore ? 2 : 1); + Expr::EvalResult AtomicOrdArgRes; + if (!AtomicOrdArg->EvaluateAsInt(AtomicOrdArgRes, getASTContext())) + llvm_unreachable("Intrinsic requires imm for atomic ordering argument!"); + auto Ord = + llvm::AtomicOrderingCABI(AtomicOrdArgRes.Val.getInt().getZExtValue()); + + // Atomic ordering cannot be acq_rel in any case, acquire for stores or + // release for loads. + if (!llvm::isValidAtomicOrderingCABI((unsigned)Ord) || + (Ord == llvm::AtomicOrderingCABI::acq_rel) || + Ord == (IsStore ? llvm::AtomicOrderingCABI::acquire + : llvm::AtomicOrderingCABI::release)) { + return Diag(AtomicOrdArg->getBeginLoc(), + diag::warn_atomic_op_has_invalid_memory_order) + << 0 << AtomicOrdArg->getSourceRange(); + } + + // Last argument is a string literal + Expr *Arg = TheCall->getArg(TheCall->getNumArgs() - 1); + if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts())) { + Fail = true; + Diag(TheCall->getBeginLoc(), diag::err_expr_not_string_literal) + << Arg->getSourceRange(); + } + + return Fail; +} + bool SemaAMDGPU::checkMovDPPFunctionCall(CallExpr *TheCall, unsigned NumArgs, unsigned NumDataArgs) { assert(NumDataArgs <= 2); diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index ba560d3c5234..17415b4185ef 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -439,10 +439,8 @@ static AccessResult MatchesFriend(Sema &S, static AccessResult MatchesFriend(Sema &S, const EffectiveContext &EC, CanQualType Friend) { - if (const RecordType *RT = Friend->getAs<RecordType>()) - return MatchesFriend( - S, EC, - cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf()); + if (const auto *RD = Friend->getAsCXXRecordDecl()) + return MatchesFriend(S, EC, RD); // TODO: we can do better than this if (Friend->isDependentType()) @@ -1786,10 +1784,7 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, if (!getLangOpts().AccessControl || Found.getAccess() == AS_public) return AR_accessible; - const RecordType *RT = ObjectExpr->getType()->castAs<RecordType>(); - CXXRecordDecl *NamingClass = - cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(); - + auto *NamingClass = ObjectExpr->getType()->castAsCXXRecordDecl(); AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, ObjectExpr->getType()); Entity.setDiag(diag::err_access) << ObjectExpr->getSourceRange() << Range; diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 1c48b3ca86fb..f8d61d9f8f5e 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -187,7 +187,9 @@ static bool ShouldDiagnoseAvailabilityInContext( // For libraries the availability will be checked later in // DiagnoseHLSLAvailability class once where the specific environment/shader // stage of the caller is known. - if (S.getLangOpts().HLSL) { + // We only do this for APIs that are not explicitly deprecated. Any API that + // is explicitly deprecated we always issue a diagnostic on. + if (S.getLangOpts().HLSL && K != AR_Deprecated) { if (!S.getLangOpts().HLSLStrictAvailability || (DeclEnv != nullptr && S.getASTContext().getTargetInfo().getTriple().getEnvironment() == diff --git a/clang/lib/Sema/SemaBPF.cpp b/clang/lib/Sema/SemaBPF.cpp index 6428435ed9d2..be890ab7fa75 100644 --- a/clang/lib/Sema/SemaBPF.cpp +++ b/clang/lib/Sema/SemaBPF.cpp @@ -56,14 +56,9 @@ static bool isValidPreserveTypeInfoArg(Expr *Arg) { return true; // Record type or Enum type. - const Type *Ty = ArgType->getUnqualifiedDesugaredType(); - if (const auto *RT = Ty->getAs<RecordType>()) { + if (const auto *RT = ArgType->getAsCanonical<TagType>()) if (!RT->getOriginalDecl()->getDeclName().isEmpty()) return true; - } else if (const auto *ET = Ty->getAs<EnumType>()) { - if (!ET->getOriginalDecl()->getDeclName().isEmpty()) - return true; - } return false; } @@ -99,13 +94,12 @@ static bool isValidPreserveEnumValueArg(Expr *Arg) { return false; // The type must be EnumType. - const Type *Ty = ArgType->getUnqualifiedDesugaredType(); - const auto *ET = Ty->getAs<EnumType>(); - if (!ET) + const auto *ED = ArgType->getAsEnumDecl(); + if (!ED) return false; // The enum value must be supported. - return llvm::is_contained(ET->getOriginalDecl()->enumerators(), Enumerator); + return llvm::is_contained(ED->enumerators(), Enumerator); } bool SemaBPF::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index fbf64d3d5705..2e3cbb336a0c 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -421,13 +421,10 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, } for (const auto *B : Bases) { - const RecordType *BaseType = B->getType()->getAs<RecordType>(); - if (!BaseType) { + auto *BaseClassDecl = B->getType()->getAsCXXRecordDecl(); + if (!BaseClassDecl) continue; - } - CXXRecordDecl *BaseClassDecl = - cast<CXXRecordDecl>(BaseType->getOriginalDecl())->getDefinitionOrSelf(); Sema::SpecialMemberOverloadResult SMOR = SemaRef.LookupSpecialMember(BaseClassDecl, CSM, /* ConstArg */ ConstRHS, @@ -466,15 +463,11 @@ bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, continue; } - const RecordType *FieldType = - getASTContext().getBaseElementType(F->getType())->getAs<RecordType>(); - if (!FieldType) { + auto *FieldRecDecl = + getASTContext().getBaseElementType(F->getType())->getAsCXXRecordDecl(); + if (!FieldRecDecl) continue; - } - CXXRecordDecl *FieldRecDecl = - cast<CXXRecordDecl>(FieldType->getOriginalDecl()) - ->getDefinitionOrSelf(); Sema::SpecialMemberOverloadResult SMOR = SemaRef.LookupSpecialMember(FieldRecDecl, CSM, /* ConstArg */ ConstRHS && !F->isMutable(), diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 45de8ff3ba26..437c69aa1587 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -133,11 +133,8 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, return const_cast<NamespaceDecl *>( NNS.getAsNamespaceAndPrefix().Namespace->getNamespace()); - case NestedNameSpecifier::Kind::Type: { - auto *TD = NNS.getAsType()->getAsTagDecl(); - assert(TD && "Non-tag type in nested-name-specifier"); - return TD; - } + case NestedNameSpecifier::Kind::Type: + return NNS.getAsType()->castAsTagDecl(); case NestedNameSpecifier::Kind::Global: return Context.getTranslationUnitDecl(); @@ -401,6 +398,54 @@ public: } +[[nodiscard]] static bool ExtendNestedNameSpecifier(Sema &S, CXXScopeSpec &SS, + const NamedDecl *ND, + SourceLocation NameLoc, + SourceLocation CCLoc) { + TypeLocBuilder TLB; + QualType T; + if (const auto *USD = dyn_cast<UsingShadowDecl>(ND)) { + T = S.Context.getUsingType(ElaboratedTypeKeyword::None, SS.getScopeRep(), + USD); + TLB.push<UsingTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(), + SS.getWithLocInContext(S.Context), NameLoc); + } else if (const auto *TD = dyn_cast<TypeDecl>(ND)) { + T = S.Context.getTypeDeclType(ElaboratedTypeKeyword::None, SS.getScopeRep(), + TD); + switch (T->getTypeClass()) { + case Type::Record: + case Type::InjectedClassName: + case Type::Enum: { + auto TTL = TLB.push<TagTypeLoc>(T); + TTL.setElaboratedKeywordLoc(SourceLocation()); + TTL.setQualifierLoc(SS.getWithLocInContext(S.Context)); + TTL.setNameLoc(NameLoc); + break; + } + case Type::Typedef: + TLB.push<TypedefTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(), + SS.getWithLocInContext(S.Context), + NameLoc); + break; + case Type::UnresolvedUsing: + TLB.push<UnresolvedUsingTypeLoc>(T).set( + /*ElaboratedKeywordLoc=*/SourceLocation(), + SS.getWithLocInContext(S.Context), NameLoc); + break; + default: + assert(SS.isEmpty()); + T = S.Context.getTypeDeclType(TD); + TLB.pushTypeSpec(T).setNameLoc(NameLoc); + break; + } + } else { + return false; + } + SS.clear(); + SS.Make(S.Context, TLB.getTypeLocInContext(S.Context, T), CCLoc); + return true; +} + bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, @@ -656,40 +701,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, if (isa<EnumDecl>(TD)) Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); - QualType T; - TypeLocBuilder TLB; - if (const auto *USD = dyn_cast<UsingShadowDecl>(SD)) { - T = Context.getUsingType(ElaboratedTypeKeyword::None, SS.getScopeRep(), - USD); - TLB.push<UsingTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(), - SS.getWithLocInContext(Context), - IdInfo.IdentifierLoc); - } else if (const auto *Tag = dyn_cast<TagDecl>(TD)) { - T = Context.getTagType(ElaboratedTypeKeyword::None, SS.getScopeRep(), Tag, - /*OwnsTag=*/false); - auto TTL = TLB.push<TagTypeLoc>(T); - TTL.setElaboratedKeywordLoc(SourceLocation()); - TTL.setQualifierLoc(SS.getWithLocInContext(SemaRef.Context)); - TTL.setNameLoc(IdInfo.IdentifierLoc); - } else if (auto *TN = dyn_cast<TypedefNameDecl>(TD)) { - T = Context.getTypedefType(ElaboratedTypeKeyword::None, SS.getScopeRep(), - TN); - TLB.push<TypedefTypeLoc>(T).set(/*ElaboratedKeywordLoc=*/SourceLocation(), - SS.getWithLocInContext(SemaRef.Context), - IdInfo.IdentifierLoc); - } else if (auto *UD = dyn_cast<UnresolvedUsingTypenameDecl>(TD)) { - T = Context.getUnresolvedUsingType(ElaboratedTypeKeyword::None, - SS.getScopeRep(), UD); - TLB.push<UnresolvedUsingTypeLoc>(T).set( - /*ElaboratedKeywordLoc=*/SourceLocation(), - SS.getWithLocInContext(SemaRef.Context), IdInfo.IdentifierLoc); - } else { - assert(SS.isEmpty()); - T = Context.getTypeDeclType(TD); - TLB.pushTypeSpec(T).setNameLoc(IdInfo.IdentifierLoc); - } - SS.clear(); - SS.Make(Context, TLB.getTypeLocInContext(Context, T), IdInfo.CCLoc); + [[maybe_unused]] bool IsType = ::ExtendNestedNameSpecifier( + *this, SS, SD, IdInfo.IdentifierLoc, IdInfo.CCLoc); + assert(IsType && "unhandled declaration kind"); return false; } @@ -765,21 +779,16 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, NestedNameSpecInfo &IdInfo, } if (!Found.empty()) { - if (TypeDecl *TD = Found.getAsSingle<TypeDecl>()) { - QualType T; - if (auto *TN = dyn_cast<TypedefNameDecl>(TD)) { - T = Context.getTypedefType(ElaboratedTypeKeyword::None, - SS.getScopeRep(), TN); - } else { - // FIXME: Enumerate the possibilities here. - assert(!isa<TagDecl>(TD)); - assert(SS.isEmpty()); - T = Context.getTypeDeclType(TD); - } - + const auto *ND = Found.getAsSingle<NamedDecl>(); + if (::ExtendNestedNameSpecifier(*this, SS, ND, IdInfo.IdentifierLoc, + IdInfo.CCLoc)) { + const Type *T = SS.getScopeRep().getAsType(); Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace) - << T << getLangOpts().CPlusPlus; - } else if (Found.getAsSingle<TemplateDecl>()) { + << QualType(T, 0) << getLangOpts().CPlusPlus; + // Recover with this type if it would be a valid nested name specifier. + return !T->getAsCanonical<TagType>(); + } + if (isa<TemplateDecl>(ND)) { ParsedType SuggestedType; DiagnoseUnknownTypeName(IdInfo.Identifier, IdInfo.IdentifierLoc, S, &SS, SuggestedType); diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index da43848a1a7d..d986e3b2b7ac 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -595,13 +595,11 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, DifferentPtrness--; } if (!DifferentPtrness) { - auto RecFrom = From->getAs<RecordType>(); - auto RecTo = To->getAs<RecordType>(); - if (RecFrom && RecTo) { - auto DeclFrom = RecFrom->getAsCXXRecordDecl(); + if (auto *DeclFrom = From->getAsCXXRecordDecl(), + *DeclTo = To->getAsCXXRecordDecl(); + DeclFrom && DeclTo) { if (!DeclFrom->isCompleteDefinition()) S.Diag(DeclFrom->getLocation(), diag::note_type_incomplete) << DeclFrom; - auto DeclTo = RecTo->getAsCXXRecordDecl(); if (!DeclTo->isCompleteDefinition()) S.Diag(DeclTo->getLocation(), diag::note_type_incomplete) << DeclTo; } @@ -865,7 +863,7 @@ void CastOperation::CheckDynamicCast() { return; } - const RecordType *DestRecord = DestPointee->getAs<RecordType>(); + const auto *DestRecord = DestPointee->getAsCanonical<RecordType>(); if (DestPointee->isVoidType()) { assert(DestPointer && "Reference to void is not possible"); } else if (DestRecord) { @@ -912,7 +910,7 @@ void CastOperation::CheckDynamicCast() { SrcPointee = SrcType; } - const RecordType *SrcRecord = SrcPointee->getAs<RecordType>(); + const auto *SrcRecord = SrcPointee->getAsCanonical<RecordType>(); if (SrcRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, diag::err_bad_cast_incomplete, @@ -1454,7 +1452,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // C++0x 5.2.9p9: A value of a scoped enumeration type can be explicitly // converted to an integral type. [...] A value of a scoped enumeration type // can also be explicitly converted to a floating-point type [...]. - if (const EnumType *Enum = SrcType->getAs<EnumType>()) { + if (const EnumType *Enum = dyn_cast<EnumType>(SrcType)) { if (Enum->getOriginalDecl()->isScoped()) { if (DestType->isBooleanType()) { Kind = CK_IntegralToBoolean; @@ -1486,8 +1484,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, if (SrcType->isIntegralOrEnumerationType()) { // [expr.static.cast]p10 If the enumeration type has a fixed underlying // type, the value is first converted to that type by integral conversion - const EnumType *Enum = DestType->castAs<EnumType>(); - const EnumDecl *ED = Enum->getOriginalDecl()->getDefinitionOrSelf(); + const auto *ED = DestType->castAsEnumDecl(); Kind = ED->isFixed() && ED->getIntegerType()->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast; @@ -1581,11 +1578,11 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // See if it looks like the user is trying to convert between // related record types, and select a better diagnostic if so. - if (auto SrcPointer = SrcType->getAs<PointerType>()) - if (auto DestPointer = DestType->getAs<PointerType>()) - if (SrcPointer->getPointeeType()->getAs<RecordType>() && - DestPointer->getPointeeType()->getAs<RecordType>()) - msg = diag::err_bad_cxx_cast_unrelated_class; + if (const auto *SrcPointer = SrcType->getAs<PointerType>()) + if (const auto *DestPointer = DestType->getAs<PointerType>()) + if (SrcPointer->getPointeeType()->isRecordType() && + DestPointer->getPointeeType()->isRecordType()) + msg = diag::err_bad_cxx_cast_unrelated_class; if (SrcType->isMatrixType() && DestType->isMatrixType()) { if (Self.CheckMatrixCast(OpRange, DestType, SrcType, Kind)) { @@ -3097,7 +3094,8 @@ void CastOperation::CheckCStyleCast() { if (!DestType->isScalarType() && !DestType->isVectorType() && !DestType->isMatrixType()) { - if (const RecordType *DestRecordTy = DestType->getAs<RecordType>()) { + if (const RecordType *DestRecordTy = + DestType->getAsCanonical<RecordType>()) { if (Self.Context.hasSameUnqualifiedType(DestType, SrcType)) { // GCC struct/union extension: allow cast to self. Self.Diag(OpRange.getBegin(), diag::ext_typecheck_cast_nonscalar) @@ -3173,7 +3171,12 @@ void CastOperation::CheckCStyleCast() { SrcExpr = ExprError(); return; } - if (!DestType->isNullPtrType()) { + if (DestType->isBooleanType()) { + SrcExpr = ImplicitCastExpr::Create( + Self.Context, DestType, CK_PointerToBoolean, SrcExpr.get(), nullptr, + VK_PRValue, Self.CurFPFeatureOverrides()); + + } else if (!DestType->isNullPtrType()) { // Implicitly cast from the null pointer type to the type of the // destination. CastKind CK = DestType->isPointerType() ? CK_NullToPointer : CK_BitCast; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 6e777fb9aec8..077f4311ed72 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -286,6 +286,9 @@ static bool BuiltinFunctionStart(Sema &S, CallExpr *TheCall) { if (S.checkArgCount(TheCall, 1)) return true; + if (TheCall->getArg(0)->containsErrors()) + return true; + ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0)); if (Arg.isInvalid()) return true; @@ -2214,7 +2217,7 @@ static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) { QualType ArgTy = Arg->getType(); - if (!ArgTy->isUnsignedIntegerType()) { + if (!ArgTy->isUnsignedIntegerType() && !ArgTy->isExtVectorBoolType()) { S.Diag(Arg->getBeginLoc(), diag::err_builtin_invalid_arg_type) << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0 << ArgTy; @@ -2239,7 +2242,7 @@ static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { QualType Arg0Ty = Arg0->getType(); - if (!Arg0Ty->isUnsignedIntegerType()) { + if (!Arg0Ty->isUnsignedIntegerType() && !Arg0Ty->isExtVectorBoolType()) { S.Diag(Arg0->getBeginLoc(), diag::err_builtin_invalid_arg_type) << 1 << /* scalar */ 1 << /* unsigned integer ty */ 3 << /* no fp */ 0 << Arg0Ty; @@ -2282,7 +2285,7 @@ static bool CheckMaskedBuiltinArgs(Sema &S, Expr *MaskArg, Expr *PtrArg, } static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) { - if (S.checkArgCount(TheCall, 2)) + if (S.checkArgCountRange(TheCall, 2, 3)) return ExprError(); Expr *MaskArg = TheCall->getArg(0); @@ -2295,10 +2298,21 @@ static ExprResult BuiltinMaskedLoad(Sema &S, CallExpr *TheCall) { QualType PointeeTy = PtrTy->getPointeeType(); const VectorType *MaskVecTy = MaskTy->getAs<VectorType>(); const VectorType *DataVecTy = PointeeTy->getAs<VectorType>(); + + if (TheCall->getNumArgs() == 3) { + Expr *PassThruArg = TheCall->getArg(2); + QualType PassThruTy = PassThruArg->getType(); + if (!S.Context.hasSameType(PassThruTy, PointeeTy)) + return S.Diag(PtrArg->getExprLoc(), diag::err_vec_masked_load_store_ptr) + << /* third argument */ 3 << PointeeTy; + } + if (MaskVecTy->getNumElements() != DataVecTy->getNumElements()) return ExprError( S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size) - << "__builtin_masked_load" << MaskTy << PointeeTy); + << S.getASTContext().BuiltinInfo.getQuotedName( + TheCall->getBuiltinCallee()) + << MaskTy << PointeeTy); TheCall->setType(PointeeTy); return TheCall; @@ -2332,7 +2346,9 @@ static ExprResult BuiltinMaskedStore(Sema &S, CallExpr *TheCall) { MaskVecTy->getNumElements() != PtrVecTy->getNumElements()) return ExprError( S.Diag(TheCall->getBeginLoc(), diag::err_vec_masked_load_store_size) - << "__builtin_masked_store" << MaskTy << PointeeTy); + << S.getASTContext().BuiltinInfo.getQuotedName( + TheCall->getBuiltinCallee()) + << MaskTy << PointeeTy); if (!S.Context.hasSameType(ValTy, PointeeTy)) return ExprError(S.Diag(TheCall->getBeginLoc(), @@ -2598,8 +2614,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // TheCall will be freed by the smart pointer here, but that's fine, since // BuiltinShuffleVector guts it, but then doesn't release it. case Builtin::BI__builtin_masked_load: + case Builtin::BI__builtin_masked_expand_load: return BuiltinMaskedLoad(*this, TheCall); case Builtin::BI__builtin_masked_store: + case Builtin::BI__builtin_masked_compress_store: return BuiltinMaskedStore(*this, TheCall); case Builtin::BI__builtin_invoke: return BuiltinInvoke(*this, TheCall); @@ -5278,13 +5296,10 @@ bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { // extra checking to see what their promotable type actually is. if (!Context.isPromotableIntegerType(Type)) return false; - if (!Type->isEnumeralType()) + const auto *ED = Type->getAsEnumDecl(); + if (!ED) return true; - const EnumDecl *ED = Type->castAs<EnumType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); - return !(ED && - Context.typesAreCompatible(ED->getPromotionType(), Type)); + return !Context.typesAreCompatible(ED->getPromotionType(), Type); }()) { unsigned Reason = 0; if (Type->isReferenceType()) Reason = 1; @@ -5536,16 +5551,6 @@ bool Sema::BuiltinComplex(CallExpr *TheCall) { << Real->getSourceRange() << Imag->getSourceRange(); } - // We don't allow _Complex _Float16 nor _Complex __fp16 as type specifiers; - // don't allow this builtin to form those types either. - // FIXME: Should we allow these types? - if (Real->getType()->isFloat16Type()) - return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec) - << "_Float16"; - if (Real->getType()->isHalfType()) - return Diag(TheCall->getBeginLoc(), diag::err_invalid_complex_spec) - << "half"; - TheCall->setType(Context.getComplexType(Real->getType())); return false; } @@ -7891,16 +7896,10 @@ bool DecomposePrintfHandler::HandlePrintfSpecifier( template<typename MemberKind> static llvm::SmallPtrSet<MemberKind*, 1> CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) { - const RecordType *RT = Ty->getAs<RecordType>(); + auto *RD = Ty->getAsCXXRecordDecl(); llvm::SmallPtrSet<MemberKind*, 1> Results; - if (!RT) - return Results; - CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getOriginalDecl()); - if (!RD) - return Results; - RD = RD->getDefinition(); - if (!RD) + if (!RD || !(RD->isBeingDefined() || RD->isCompleteDefinition())) return Results; LookupResult R(S, &S.Context.Idents.get(Name), SourceLocation(), @@ -8438,10 +8437,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, bool IsEnum = false; bool IsScopedEnum = false; QualType IntendedTy = ExprTy; - if (auto EnumTy = ExprTy->getAs<EnumType>()) { - IntendedTy = - EnumTy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); - if (EnumTy->isUnscopedEnumerationType()) { + if (const auto *ED = ExprTy->getAsEnumDecl()) { + IntendedTy = ED->getIntegerType(); + if (!ED->isScoped()) { ExprTy = IntendedTy; // This controls whether we're talking about the underlying type or not, // which we only want to do when it's an unscoped enum. @@ -9741,10 +9739,7 @@ struct SearchNonTrivialToInitializeField S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 1); } void visitStruct(QualType FT, SourceLocation SL) { - for (const FieldDecl *FD : FT->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->fields()) + for (const FieldDecl *FD : FT->castAsRecordDecl()->fields()) visit(FD->getType(), FD->getLocation()); } void visitArray(QualType::PrimitiveDefaultInitializeKind PDIK, @@ -9789,10 +9784,7 @@ struct SearchNonTrivialToCopyField S.DiagRuntimeBehavior(SL, E, S.PDiag(diag::note_nontrivial_field) << 0); } void visitStruct(QualType FT, SourceLocation SL) { - for (const FieldDecl *FD : FT->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->fields()) + for (const FieldDecl *FD : FT->castAsRecordDecl()->fields()) visit(FD->getType(), FD->getLocation()); } void visitArray(QualType::PrimitiveCopyKind PCK, const ArrayType *AT, @@ -10063,17 +10055,16 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, PDiag(diag::warn_arc_object_memaccess) << ArgIdx << FnName << PointeeTy << Call->getCallee()->getSourceRange()); - else if (const auto *RT = PointeeTy->getAs<RecordType>()) { + else if (const auto *RD = PointeeTy->getAsRecordDecl()) { // FIXME: Do not consider incomplete types even though they may be // completed later. GCC does not diagnose such code, but we may want to // consider diagnosing it in the future, perhaps under a different, but // related, diagnostic group. bool NonTriviallyCopyableCXXRecord = - getLangOpts().CPlusPlus && !RT->isIncompleteType() && - !RT->desugar().isTriviallyCopyableType(Context); + getLangOpts().CPlusPlus && RD->isCompleteDefinition() && + !PointeeTy.isTriviallyCopyableType(Context); - const auto *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && RD->isNonTrivialToPrimitiveDefaultInitialize()) { DiagRuntimeBehavior(Dest->getExprLoc(), Dest, @@ -10593,20 +10584,15 @@ struct IntRange { if (!C.getLangOpts().CPlusPlus) { // For enum types in C code, use the underlying datatype. - if (const auto *ET = dyn_cast<EnumType>(T)) - T = ET->getOriginalDecl() - ->getDefinitionOrSelf() - ->getIntegerType() - .getDesugaredType(C) - .getTypePtr(); - } else if (const auto *ET = dyn_cast<EnumType>(T)) { + if (const auto *ED = T->getAsEnumDecl()) + T = ED->getIntegerType().getDesugaredType(C).getTypePtr(); + } else if (auto *Enum = T->getAsEnumDecl()) { // For enum types in C++, use the known bit width of the enumerators. - EnumDecl *Enum = ET->getOriginalDecl()->getDefinitionOrSelf(); // In C++11, enums can have a fixed underlying type. Use this type to // compute the range. if (Enum->isFixed()) { return IntRange(C.getIntWidth(QualType(T, 0)), - !ET->isSignedIntegerOrEnumerationType()); + !Enum->getIntegerType()->isSignedIntegerType()); } unsigned NumPositive = Enum->getNumPositiveBits(); @@ -10642,10 +10628,8 @@ struct IntRange { T = CT->getElementType().getTypePtr(); if (const AtomicType *AT = dyn_cast<AtomicType>(T)) T = AT->getValueType().getTypePtr(); - if (const EnumType *ET = dyn_cast<EnumType>(T)) - T = C.getCanonicalType( - ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType()) - .getTypePtr(); + if (const auto *ED = T->getAsEnumDecl()) + T = C.getCanonicalType(ED->getIntegerType()).getTypePtr(); if (const auto *EIT = dyn_cast<BitIntType>(T)) return IntRange(EIT->getNumBits(), EIT->isUnsigned()); @@ -11616,10 +11600,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, if (BitfieldType->isBooleanType()) return false; - if (BitfieldType->isEnumeralType()) { - EnumDecl *BitfieldEnumDecl = BitfieldType->castAs<EnumType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + if (auto *BitfieldEnumDecl = BitfieldType->getAsEnumDecl()) { // If the underlying enum type was not explicitly specified as an unsigned // type and the enum contain only positive values, MSVC++ will cause an // inconsistency by storing this as a signed type. @@ -11648,15 +11629,14 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, // The RHS is not constant. If the RHS has an enum type, make sure the // bitfield is wide enough to hold all the values of the enum without // truncation. - const auto *EnumTy = OriginalInit->getType()->getAs<EnumType>(); + const auto *ED = OriginalInit->getType()->getAsEnumDecl(); const PreferredTypeAttr *PTAttr = nullptr; - if (!EnumTy) { + if (!ED) { PTAttr = Bitfield->getAttr<PreferredTypeAttr>(); if (PTAttr) - EnumTy = PTAttr->getType()->getAs<EnumType>(); + ED = PTAttr->getType()->getAsEnumDecl(); } - if (EnumTy) { - EnumDecl *ED = EnumTy->getOriginalDecl()->getDefinitionOrSelf(); + if (ED) { bool SignedBitfield = BitfieldType->isSignedIntegerOrEnumerationType(); // Enum types are implicitly signed on Windows, so check if there are any @@ -12720,8 +12700,8 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T, SourceLocation CC, // type, to give us better diagnostics. Source = Context.getCanonicalType(SourceType).getTypePtr(); - if (const EnumType *SourceEnum = Source->getAs<EnumType>()) - if (const EnumType *TargetEnum = Target->getAs<EnumType>()) + if (const EnumType *SourceEnum = Source->getAsCanonical<EnumType>()) + if (const EnumType *TargetEnum = Target->getAsCanonical<EnumType>()) if (SourceEnum->getOriginalDecl()->hasNameForLinkage() && TargetEnum->getOriginalDecl()->hasNameForLinkage() && SourceEnum != TargetEnum) { @@ -15361,17 +15341,14 @@ static bool isLayoutCompatible(const ASTContext &C, QualType T1, QualType T2) { if (TC1 != TC2) return false; - if (TC1 == Type::Enum) { - return isLayoutCompatible( - C, cast<EnumType>(T1)->getOriginalDecl()->getDefinitionOrSelf(), - cast<EnumType>(T2)->getOriginalDecl()->getDefinitionOrSelf()); - } else if (TC1 == Type::Record) { + if (TC1 == Type::Enum) + return isLayoutCompatible(C, T1->castAsEnumDecl(), T2->castAsEnumDecl()); + if (TC1 == Type::Record) { if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType()) return false; - return isLayoutCompatible( - C, cast<RecordType>(T1)->getOriginalDecl()->getDefinitionOrSelf(), - cast<RecordType>(T2)->getOriginalDecl()->getDefinitionOrSelf()); + return isLayoutCompatible(C, T1->castAsRecordDecl(), + T2->castAsRecordDecl()); } return false; @@ -15728,9 +15705,7 @@ void Sema::RefersToMemberWithReducedAlignment( return; if (ME->isArrow()) BaseType = BaseType->getPointeeType(); - RecordDecl *RD = BaseType->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *RD = BaseType->castAsRecordDecl(); if (RD->isInvalidDecl()) return; @@ -15891,6 +15866,54 @@ static bool checkBuiltinVectorMathMixedEnums(Sema &S, Expr *LHS, Expr *RHS, return false; } +/// Check if all arguments have the same type. If the types don't match, emit an +/// error message and return true. Otherwise return false. +/// +/// For scalars we directly compare their unqualified types. But even if we +/// compare unqualified vector types, a difference in qualifiers in the element +/// types can make the vector types be considered not equal. For example, +/// vector of 4 'const float' values vs vector of 4 'float' values. +/// So we compare unqualified types of their elements and number of elements. +static bool checkBuiltinVectorMathArgTypes(Sema &SemaRef, + ArrayRef<Expr *> Args) { + assert(!Args.empty() && "Should have at least one argument."); + + Expr *Arg0 = Args.front(); + QualType Ty0 = Arg0->getType(); + + auto EmitError = [&](Expr *ArgI) { + SemaRef.Diag(Arg0->getBeginLoc(), + diag::err_typecheck_call_different_arg_types) + << Arg0->getType() << ArgI->getType(); + }; + + // Compare scalar types. + if (!Ty0->isVectorType()) { + for (Expr *ArgI : Args.drop_front()) + if (!SemaRef.Context.hasSameUnqualifiedType(Ty0, ArgI->getType())) { + EmitError(ArgI); + return true; + } + + return false; + } + + // Compare vector types. + const auto *Vec0 = Ty0->castAs<VectorType>(); + for (Expr *ArgI : Args.drop_front()) { + const auto *VecI = ArgI->getType()->getAs<VectorType>(); + if (!VecI || + !SemaRef.Context.hasSameUnqualifiedType(Vec0->getElementType(), + VecI->getElementType()) || + Vec0->getNumElements() != VecI->getNumElements()) { + EmitError(ArgI); + return true; + } + } + + return false; +} + std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall, EltwiseBuiltinArgTyRestriction ArgTyRestr) { @@ -15912,15 +15935,12 @@ Sema::BuiltinVectorMath(CallExpr *TheCall, SourceLocation LocA = Args[0]->getBeginLoc(); QualType TyA = Args[0]->getType(); - QualType TyB = Args[1]->getType(); if (checkMathBuiltinElementType(*this, LocA, TyA, ArgTyRestr, 1)) return std::nullopt; - if (!Context.hasSameUnqualifiedType(TyA, TyB)) { - Diag(LocA, diag::err_typecheck_call_different_arg_types) << TyA << TyB; + if (checkBuiltinVectorMathArgTypes(*this, Args)) return std::nullopt; - } TheCall->setArg(0, Args[0]); TheCall->setArg(1, Args[1]); @@ -15955,17 +15975,11 @@ bool Sema::BuiltinElementwiseTernaryMath( return true; } - TheCall->setArg(0, Args[0]); - for (int I = 1; I < 3; ++I) { - if (Args[0]->getType().getCanonicalType() != - Args[I]->getType().getCanonicalType()) { - return Diag(Args[0]->getBeginLoc(), - diag::err_typecheck_call_different_arg_types) - << Args[0]->getType() << Args[I]->getType(); - } + if (checkBuiltinVectorMathArgTypes(*this, Args)) + return true; + for (int I = 0; I < 3; ++I) TheCall->setArg(I, Args[I]); - } TheCall->setType(Args[0]->getType()); return false; diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index c6adead5a65f..03bf4b3690b1 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -5113,10 +5113,7 @@ void SemaCodeCompletion::CodeCompleteExpression( PreferredTypeIsPointer = Data.PreferredType->isAnyPointerType() || Data.PreferredType->isMemberPointerType() || Data.PreferredType->isBlockPointerType(); - if (Data.PreferredType->isEnumeralType()) { - EnumDecl *Enum = Data.PreferredType->castAs<EnumType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + if (auto *Enum = Data.PreferredType->getAsEnumDecl()) { // FIXME: collect covered enumerators in cases like: // if (x == my_enum::one) { ... } else if (x == ^) {} AddEnumerators(Results, getASTContext(), Enum, SemaRef.CurContext, @@ -6240,18 +6237,14 @@ void SemaCodeCompletion::CodeCompleteCase(Scope *S) { if (!Switch->getCond()) return; QualType type = Switch->getCond()->IgnoreImplicit()->getType(); - if (!type->isEnumeralType()) { + EnumDecl *Enum = type->getAsEnumDecl(); + if (!Enum) { CodeCompleteExpressionData Data(type); Data.IntegralConstantExpression = true; CodeCompleteExpression(S, Data); return; } - // Code-complete the cases of a switch statement over an enumeration type - // by providing the list of - EnumDecl *Enum = - type->castAs<EnumType>()->getOriginalDecl()->getDefinitionOrSelf(); - // Determine which enumerators we have already seen in the switch statement. // FIXME: Ideally, we would also be able to look *past* the code-completion // token, in case we are code-completing in the middle of the switch and not diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 160d7353cacd..7c1459e32016 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1653,6 +1653,17 @@ void Sema::FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, F.done(); } +static bool isImplicitInstantiation(NamedDecl *D) { + if (auto *VD = dyn_cast<VarDecl>(D)) + return VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation; + if (auto *FD = dyn_cast<FunctionDecl>(D)) + return FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation; + if (auto *RD = dyn_cast<CXXRecordDecl>(D)) + return RD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation; + + return false; +} + bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { // [module.interface]p7: // A declaration is attached to a module as follows: @@ -1668,6 +1679,14 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { return false; } + // Although we have questions for the module ownership of implicit + // instantiations, it should be sure that we shouldn't diagnose the + // redeclaration of incorrect module ownership for different implicit + // instantiations in different modules. We will diagnose the redeclaration of + // incorrect module ownership for the template itself. + if (isImplicitInstantiation(New) || isImplicitInstantiation(Old)) + return false; + Module *NewM = New->getOwningModule(); Module *OldM = Old->getOwningModule(); @@ -5291,15 +5310,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // UNION_TYPE; <- where UNION_TYPE is a typedef union. if ((Tag && Tag->getDeclName()) || DS.getTypeSpecType() == DeclSpec::TST_typename) { - RecordDecl *Record = nullptr; - if (Tag) - Record = dyn_cast<RecordDecl>(Tag); - else if (const RecordType *RT = - DS.getRepAsType().get()->getAsStructureType()) - Record = RT->getOriginalDecl()->getDefinitionOrSelf(); - else if (const RecordType *UT = DS.getRepAsType().get()->getAsUnionType()) - Record = UT->getOriginalDecl()->getDefinitionOrSelf(); - + RecordDecl *Record = Tag ? dyn_cast<RecordDecl>(Tag) + : DS.getRepAsType().get()->getAsRecordDecl(); if (Record && getLangOpts().MicrosoftExt) { Diag(DS.getBeginLoc(), diag::ext_ms_anonymous_record) << Record->isUnion() << DS.getSourceRange(); @@ -9816,8 +9828,7 @@ static void checkIsValidOpenCLKernelParameter( // At this point we already handled everything except of a RecordType. assert(PT->isRecordType() && "Unexpected type."); - const RecordDecl *PD = - PT->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *PD = PT->castAsRecordDecl(); VisitStack.push_back(PD); assert(VisitStack.back() && "First decl null?"); @@ -9845,9 +9856,7 @@ static void checkIsValidOpenCLKernelParameter( "Unexpected type."); const Type *FieldRecTy = FieldTy->getPointeeOrArrayElementType(); - RD = FieldRecTy->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + RD = FieldRecTy->castAsRecordDecl(); } else { RD = cast<RecordDecl>(Next); } @@ -13375,8 +13384,7 @@ struct DiagNonTrivalCUnionDefaultInitializeVisitor } void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - const RecordDecl *RD = - QT->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = QT->castAsRecordDecl(); if (RD->isUnion()) { if (OrigLoc.isValid()) { bool IsUnion = false; @@ -13442,8 +13450,7 @@ struct DiagNonTrivalCUnionDestructedTypeVisitor } void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - const RecordDecl *RD = - QT->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = QT->castAsRecordDecl(); if (RD->isUnion()) { if (OrigLoc.isValid()) { bool IsUnion = false; @@ -13508,8 +13515,7 @@ struct DiagNonTrivalCUnionCopyVisitor } void visitStruct(QualType QT, const FieldDecl *FD, bool InNonTrivialUnion) { - const RecordDecl *RD = - QT->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); + const auto *RD = QT->castAsRecordDecl(); if (RD->isUnion()) { if (OrigLoc.isValid()) { bool IsUnion = false; @@ -14406,9 +14412,12 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { return; } - // Provide a specific diagnostic for uninitialized variable - // definitions with incomplete array type. - if (Type->isIncompleteArrayType()) { + // Provide a specific diagnostic for uninitialized variable definitions + // with incomplete array type, unless it is a global unbounded HLSL resource + // array. + if (Type->isIncompleteArrayType() && + !(getLangOpts().HLSL && Var->hasGlobalStorage() && + Type->isHLSLResourceRecordArray())) { if (Var->isConstexpr()) Diag(Var->getLocation(), diag::err_constexpr_var_requires_const_init) << Var; @@ -14480,11 +14489,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { // version of one of these types, or an array of one of the preceding // types and is declared without an initializer. if (getLangOpts().CPlusPlus && Var->hasLocalStorage()) { - if (const RecordType *Record - = Context.getBaseElementType(Type)->getAs<RecordType>()) { - CXXRecordDecl *CXXRecord = - cast<CXXRecordDecl>(Record->getOriginalDecl()) - ->getDefinitionOrSelf(); + if (const auto *CXXRecord = + Context.getBaseElementType(Type)->getAsCXXRecordDecl()) { // Mark the function (if we're in one) for further checking even if the // looser rules of C++11 do not require such checks, so that we can // diagnose incompatibilities with C++98. @@ -14947,8 +14953,8 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // Require the destructor. if (!type->isDependentType()) - if (const RecordType *recordType = baseType->getAs<RecordType>()) - FinalizeVarWithDestructor(var, recordType); + if (auto *RD = baseType->getAsCXXRecordDecl()) + FinalizeVarWithDestructor(var, RD); // If this variable must be emitted, add it as an initializer for the current // module. @@ -15492,6 +15498,14 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D, } } + // Incomplete resource arrays are not allowed as function parameters in HLSL + if (getLangOpts().HLSL && parmDeclType->isIncompleteArrayType() && + parmDeclType->isHLSLResourceRecordArray()) { + Diag(D.getIdentifierLoc(), + diag::err_hlsl_incomplete_resource_array_in_function_param); + D.setInvalidType(true); + } + // Temporarily put parameter variables in the translation unit, not // the enclosing context. This prevents them from accidentally // looking like class members in C++. @@ -18066,7 +18080,8 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, } } } else if (auto *RD = dyn_cast<CXXRecordDecl>(PrevDecl); - RD && RD->isInjectedClassName()) { + TUK == TagUseKind::Reference && RD && + RD->isInjectedClassName()) { // If lookup found the injected class name, the previous declaration is // the class being injected into. PrevDecl = cast<TagDecl>(RD->getDeclContext()); @@ -18558,8 +18573,14 @@ CreateNewDecl: if (PrevDecl) CheckRedeclarationInModule(New, PrevDecl); - if (TUK == TagUseKind::Definition && (!SkipBody || !SkipBody->ShouldSkip)) - New->startDefinition(); + if (TUK == TagUseKind::Definition) { + if (!SkipBody || !SkipBody->ShouldSkip) { + New->startDefinition(); + } else { + New->setCompleteDefinition(); + New->demoteThisDefinitionToDeclaration(); + } + } ProcessDeclAttributeList(S, New, Attrs); AddPragmaAttributes(S, New); @@ -19119,17 +19140,16 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, if (!InvalidDecl && getLangOpts().CPlusPlus) { if (Record->isUnion()) { - if (const RecordType *RT = EltTy->getAs<RecordType>()) { - CXXRecordDecl *RDecl = cast<CXXRecordDecl>(RT->getOriginalDecl()); - if (RDecl->getDefinition()) { - // C++ [class.union]p1: An object of a class with a non-trivial - // constructor, a non-trivial copy constructor, a non-trivial - // destructor, or a non-trivial copy assignment operator - // cannot be a member of a union, nor can an array of such - // objects. - if (CheckNontrivialField(NewFD)) - NewFD->setInvalidDecl(); - } + if (const auto *RD = EltTy->getAsCXXRecordDecl(); + RD && (RD->isBeingDefined() || RD->isCompleteDefinition())) { + + // C++ [class.union]p1: An object of a class with a non-trivial + // constructor, a non-trivial copy constructor, a non-trivial + // destructor, or a non-trivial copy assignment operator + // cannot be a member of a union, nor can an array of such + // objects. + if (CheckNontrivialField(NewFD)) + NewFD->setInvalidDecl(); } // C++ [class.union]p1: If a union contains a member of reference type, @@ -19185,55 +19205,51 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { return false; QualType EltTy = Context.getBaseElementType(FD->getType()); - if (const RecordType *RT = EltTy->getAs<RecordType>()) { - CXXRecordDecl *RDecl = - cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(); - if (RDecl->getDefinition()) { - // We check for copy constructors before constructors - // because otherwise we'll never get complaints about - // copy constructors. - - CXXSpecialMemberKind member = CXXSpecialMemberKind::Invalid; - // We're required to check for any non-trivial constructors. Since the - // implicit default constructor is suppressed if there are any - // user-declared constructors, we just need to check that there is a - // trivial default constructor and a trivial copy constructor. (We don't - // worry about move constructors here, since this is a C++98 check.) - if (RDecl->hasNonTrivialCopyConstructor()) - member = CXXSpecialMemberKind::CopyConstructor; - else if (!RDecl->hasTrivialDefaultConstructor()) - member = CXXSpecialMemberKind::DefaultConstructor; - else if (RDecl->hasNonTrivialCopyAssignment()) - member = CXXSpecialMemberKind::CopyAssignment; - else if (RDecl->hasNonTrivialDestructor()) - member = CXXSpecialMemberKind::Destructor; - - if (member != CXXSpecialMemberKind::Invalid) { - if (!getLangOpts().CPlusPlus11 && - getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) { - // Objective-C++ ARC: it is an error to have a non-trivial field of - // a union. However, system headers in Objective-C programs - // occasionally have Objective-C lifetime objects within unions, - // and rather than cause the program to fail, we make those - // members unavailable. - SourceLocation Loc = FD->getLocation(); - if (getSourceManager().isInSystemHeader(Loc)) { - if (!FD->hasAttr<UnavailableAttr>()) - FD->addAttr(UnavailableAttr::CreateImplicit(Context, "", - UnavailableAttr::IR_ARCFieldWithOwnership, Loc)); - return false; - } + if (const auto *RDecl = EltTy->getAsCXXRecordDecl(); + RDecl && (RDecl->isBeingDefined() || RDecl->isCompleteDefinition())) { + // We check for copy constructors before constructors + // because otherwise we'll never get complaints about + // copy constructors. + + CXXSpecialMemberKind member = CXXSpecialMemberKind::Invalid; + // We're required to check for any non-trivial constructors. Since the + // implicit default constructor is suppressed if there are any + // user-declared constructors, we just need to check that there is a + // trivial default constructor and a trivial copy constructor. (We don't + // worry about move constructors here, since this is a C++98 check.) + if (RDecl->hasNonTrivialCopyConstructor()) + member = CXXSpecialMemberKind::CopyConstructor; + else if (!RDecl->hasTrivialDefaultConstructor()) + member = CXXSpecialMemberKind::DefaultConstructor; + else if (RDecl->hasNonTrivialCopyAssignment()) + member = CXXSpecialMemberKind::CopyAssignment; + else if (RDecl->hasNonTrivialDestructor()) + member = CXXSpecialMemberKind::Destructor; + + if (member != CXXSpecialMemberKind::Invalid) { + if (!getLangOpts().CPlusPlus11 && getLangOpts().ObjCAutoRefCount && + RDecl->hasObjectMember()) { + // Objective-C++ ARC: it is an error to have a non-trivial field of + // a union. However, system headers in Objective-C programs + // occasionally have Objective-C lifetime objects within unions, + // and rather than cause the program to fail, we make those + // members unavailable. + SourceLocation Loc = FD->getLocation(); + if (getSourceManager().isInSystemHeader(Loc)) { + if (!FD->hasAttr<UnavailableAttr>()) + FD->addAttr(UnavailableAttr::CreateImplicit( + Context, "", UnavailableAttr::IR_ARCFieldWithOwnership, Loc)); + return false; } - - Diag( - FD->getLocation(), - getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member - : diag::err_illegal_union_or_anon_struct_member) - << FD->getParent()->isUnion() << FD->getDeclName() << member; - DiagnoseNontrivial(RDecl, member); - return !getLangOpts().CPlusPlus11; } + + Diag(FD->getLocation(), + getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member + : diag::err_illegal_union_or_anon_struct_member) + << FD->getParent()->isUnion() << FD->getDeclName() << member; + DiagnoseNontrivial(RDecl, member); + return !getLangOpts().CPlusPlus11; } } @@ -19509,11 +19525,9 @@ bool Sema::EntirelyFunctionPointers(const RecordDecl *Record) { return PointeeType.getDesugaredType(Context)->isFunctionType(); } // If a member is a struct entirely of function pointers, that counts too. - if (const RecordType *RT = FieldType->getAs<RecordType>()) { - const RecordDecl *Record = RT->getOriginalDecl()->getDefinitionOrSelf(); - if (Record->isStruct() && EntirelyFunctionPointers(Record)) - return true; - } + if (const auto *Record = FieldType->getAsRecordDecl(); + Record && Record->isStruct() && EntirelyFunctionPointers(Record)) + return true; return false; }; @@ -19667,10 +19681,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } else if (const RecordType *FDTTy = FDTy->getAs<RecordType>()) { - if (Record && FDTTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) { + } else if (const auto *RD = FDTy->getAsRecordDecl()) { + if (Record && RD->hasFlexibleArrayMember()) { // A type which contains a flexible array member is considered to be a // flexible array member. Record->setHasFlexibleArrayMember(true); @@ -19696,7 +19708,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, // Ivars can not have abstract class types FD->setInvalidDecl(); } - const RecordDecl *RD = FDTTy->getOriginalDecl()->getDefinitionOrSelf(); if (Record && RD->hasObjectMember()) Record->setHasObjectMember(true); if (Record && RD->hasVolatileMember()) @@ -19730,10 +19741,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Record->setHasObjectMember(true); else if (Context.getAsArrayType(FD->getType())) { QualType BaseType = Context.getBaseElementType(FD->getType()); - if (BaseType->isRecordType() && BaseType->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasObjectMember()) + if (const auto *RD = BaseType->getAsRecordDecl(); + RD && RD->hasObjectMember()) Record->setHasObjectMember(true); else if (BaseType->isObjCObjectPointerType() || BaseType.isObjCGCStrong()) @@ -19765,10 +19774,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Record->setHasNonTrivialToPrimitiveDestructCUnion(true); } - if (const auto *RT = FT->getAs<RecordType>()) { - if (RT->getOriginalDecl() - ->getDefinitionOrSelf() - ->getArgPassingRestrictions() == + if (const auto *RD = FT->getAsRecordDecl()) { + if (RD->getArgPassingRestrictions() == RecordArgPassingKind::CanNeverPassInRegs) Record->setArgPassingRestrictions( RecordArgPassingKind::CanNeverPassInRegs); @@ -19779,6 +19786,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Q && Q.isAddressDiscriminated()) { Record->setArgPassingRestrictions( RecordArgPassingKind::CanNeverPassInRegs); + Record->setNonTrivialToPrimitiveCopy(true); } } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 3685bcefbf76..cb2c132cca97 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -58,6 +59,7 @@ #include "clang/Sema/SemaSwift.h" #include "clang/Sema/SemaWasm.h" #include "clang/Sema/SemaX86.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Demangle/Demangle.h" @@ -169,7 +171,7 @@ static bool isIntOrBool(Expr *Exp) { // Check to see if the type is a smart pointer of some kind. We assume // it's a smart pointer if it defines both operator-> and operator*. -static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { +static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordDecl *Record) { auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record, OverloadedOperatorKind Op) { DeclContextLookupResult Result = @@ -177,7 +179,6 @@ static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { return !Result.empty(); }; - const RecordDecl *Record = RT->getOriginalDecl()->getDefinitionOrSelf(); bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star); bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow); if (foundStarOperator && foundArrowOperator) @@ -212,14 +213,14 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, if (QT->isAnyPointerType()) return true; - if (const auto *RT = QT->getAs<RecordType>()) { + if (const auto *RD = QT->getAsRecordDecl()) { // If it's an incomplete type, it could be a smart pointer; skip it. // (We don't want to force template instantiation if we can avoid it, // since that would alter the order in which templates are instantiated.) - if (RT->isIncompleteType()) + if (!RD->isCompleteDefinition()) return true; - if (threadSafetyCheckIsSmartPointer(S, RT)) + if (threadSafetyCheckIsSmartPointer(S, RD)) return true; } @@ -229,13 +230,13 @@ static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D, /// Checks that the passed in QualType either is of RecordType or points /// to RecordType. Returns the relevant RecordType, null if it does not exit. -static const RecordType *getRecordType(QualType QT) { - if (const auto *RT = QT->getAs<RecordType>()) - return RT; +static const RecordDecl *getRecordDecl(QualType QT) { + if (const auto *RD = QT->getAsRecordDecl()) + return RD; - // Now check if we point to record type. - if (const auto *PT = QT->getAs<PointerType>()) - return PT->getPointeeType()->getAs<RecordType>(); + // Now check if we point to a record. + if (const auto *PT = QT->getAsCanonical<PointerType>()) + return PT->getPointeeType()->getAsRecordDecl(); return nullptr; } @@ -257,36 +258,34 @@ static bool checkRecordDeclForAttr(const RecordDecl *RD) { } static bool checkRecordTypeForCapability(Sema &S, QualType Ty) { - const RecordType *RT = getRecordType(Ty); + const auto *RD = getRecordDecl(Ty); - if (!RT) + if (!RD) return false; // Don't check for the capability if the class hasn't been defined yet. - if (RT->isIncompleteType()) + if (!RD->isCompleteDefinition()) return true; // Allow smart pointers to be used as capability objects. // FIXME -- Check the type that the smart pointer points to. - if (threadSafetyCheckIsSmartPointer(S, RT)) + if (threadSafetyCheckIsSmartPointer(S, RD)) return true; - return checkRecordDeclForAttr<CapabilityAttr>( - RT->getOriginalDecl()->getDefinitionOrSelf()); + return checkRecordDeclForAttr<CapabilityAttr>(RD); } static bool checkRecordTypeForScopedCapability(Sema &S, QualType Ty) { - const RecordType *RT = getRecordType(Ty); + const auto *RD = getRecordDecl(Ty); - if (!RT) + if (!RD) return false; // Don't check for the capability if the class hasn't been defined yet. - if (RT->isIncompleteType()) + if (!RD->isCompleteDefinition()) return true; - return checkRecordDeclForAttr<ScopedLockableAttr>( - RT->getOriginalDecl()->getDefinitionOrSelf()); + return checkRecordDeclForAttr<ScopedLockableAttr>(RD); } static bool checkTypedefTypeForCapability(QualType Ty) { @@ -401,10 +400,10 @@ static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D, ArgTy = DRE->getDecl()->getType(); // First see if we can just cast to record type, or pointer to record type. - const RecordType *RT = getRecordType(ArgTy); + const auto *RD = getRecordDecl(ArgTy); // Now check if we index into a record type function param. - if(!RT && ParamIdxOk) { + if (!RD && ParamIdxOk) { const auto *FD = dyn_cast<FunctionDecl>(D); const auto *IL = dyn_cast<IntegerLiteral>(ArgExp); if(FD && IL) { @@ -2159,29 +2158,51 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL)); } +static ExprResult sharedGetConstructorDestructorAttrExpr(Sema &S, + const ParsedAttr &AL) { + // If no Expr node exists on the attribute, return a nullptr result (default + // priority to be used). If Expr node exists but is not valid, return an + // invalid result. Otherwise, return the Expr. + Expr *E = nullptr; + if (AL.getNumArgs() == 1) { + E = AL.getArgAsExpr(0); + if (E->isValueDependent()) { + if (!E->isTypeDependent() && !E->getType()->isIntegerType()) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIntegerConstant << E->getSourceRange(); + return ExprError(); + } + } else { + uint32_t priority; + if (!S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) { + return ExprError(); + } + return ConstantExpr::Create(S.Context, E, + APValue(llvm::APSInt::getUnsigned(priority))); + } + } + return E; +} + static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t priority = ConstructorAttr::DefaultPriority; if (S.getLangOpts().HLSL && AL.getNumArgs()) { S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported); return; } - if (AL.getNumArgs() && - !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) + ExprResult E = sharedGetConstructorDestructorAttrExpr(S, AL); + if (E.isInvalid()) return; S.Diag(D->getLocation(), diag::warn_global_constructor) << D->getSourceRange(); - - D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority)); + D->addAttr(ConstructorAttr::Create(S.Context, E.get(), AL)); } static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - uint32_t priority = DestructorAttr::DefaultPriority; - if (AL.getNumArgs() && - !S.checkUInt32Argument(AL, AL.getArgAsExpr(0), priority)) + ExprResult E = sharedGetConstructorDestructorAttrExpr(S, AL); + if (E.isInvalid()) return; S.Diag(D->getLocation(), diag::warn_global_destructor) << D->getSourceRange(); - - D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority)); + D->addAttr(DestructorAttr::Create(S.Context, E.get(), AL)); } template <typename AttrTy> @@ -3639,7 +3660,7 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { QualType T = cast<VarDecl>(D)->getType(); if (S.Context.getAsArrayType(T)) T = S.Context.getBaseElementType(T); - if (!T->getAs<RecordType>()) { + if (!T->isRecordType()) { S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); AL.setInvalid(); return; @@ -4163,10 +4184,7 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { RecordDecl *RD = nullptr; const auto *TD = dyn_cast<TypedefNameDecl>(D); if (TD && TD->getUnderlyingType()->isUnionType()) - RD = TD->getUnderlyingType() - ->getAsUnionType() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + RD = TD->getUnderlyingType()->getAsRecordDecl(); else RD = dyn_cast<RecordDecl>(D); @@ -4739,14 +4757,14 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, // GCC allows 'mode' attribute on enumeration types (even incomplete), except // for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete // type, 'enum { A } __attribute__((mode(V4SI)))' is rejected. - if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) && + if ((isa<EnumDecl>(D) || OldElemTy->isEnumeralType()) && VectorSize.getBoolValue()) { Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange(); return; } bool IntegralOrAnyEnumType = (OldElemTy->isIntegralOrEnumerationType() && !OldElemTy->isBitIntType()) || - OldElemTy->getAs<EnumType>(); + OldElemTy->isEnumeralType(); if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() && !IntegralOrAnyEnumType) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index bb57968830a6..63ce87b9b060 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2187,10 +2187,7 @@ static bool CheckConstexprCtorInitializer(Sema &SemaRef, return false; } } else if (Field->isAnonymousStructOrUnion()) { - const RecordDecl *RD = Field->getType() - ->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + const auto *RD = Field->getType()->castAsRecordDecl(); for (auto *I : RD->fields()) // If an anonymous union contains an anonymous struct of which any member // is initialized, all members must be initialized. @@ -2925,9 +2922,7 @@ NoteIndirectBases(ASTContext &Context, IndirectBaseSet &Set, { // Even though the incoming type is a base, it might not be // a class -- it could be a template parm, for instance. - if (auto Rec = Type->getAs<RecordType>()) { - auto Decl = Rec->getAsCXXRecordDecl(); - + if (const auto *Decl = Type->getAsCXXRecordDecl()) { // Iterate over its bases. for (const auto &BaseSpec : Decl->bases()) { QualType Base = Context.getCanonicalType(BaseSpec.getType()) @@ -2986,9 +2981,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, if (Bases.size() > 1) NoteIndirectBases(Context, IndirectBaseTypes, NewBaseType); - if (const RecordType *Record = NewBaseType->getAs<RecordType>()) { - const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getOriginalDecl()) - ->getDefinitionOrSelf(); + if (const auto *RD = NewBaseType->getAsCXXRecordDecl()) { if (Class->isInterface() && (!RD->isInterfaceLike() || KnownBase->getAccessSpecifier() != AS_public)) { @@ -5479,7 +5472,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, CXXCtorInitializer *Member = Initializers[i]; if (Member->isBaseInitializer()) - Info.AllBaseFields[Member->getBaseClass()->getAs<RecordType>()] = Member; + Info.AllBaseFields[Member->getBaseClass()->getAsCanonical<RecordType>()] = + Member; else { Info.AllBaseFields[Member->getAnyMember()->getCanonicalDecl()] = Member; @@ -5507,8 +5501,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, // Push virtual bases before others. for (auto &VBase : ClassDecl->vbases()) { - if (CXXCtorInitializer *Value - = Info.AllBaseFields.lookup(VBase.getType()->getAs<RecordType>())) { + if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup( + VBase.getType()->getAsCanonical<RecordType>())) { // [class.base.init]p7, per DR257: // A mem-initializer where the mem-initializer-id names a virtual base // class is ignored during execution of a constructor of any class that @@ -5546,8 +5540,8 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, if (Base.isVirtual()) continue; - if (CXXCtorInitializer *Value - = Info.AllBaseFields.lookup(Base.getType()->getAs<RecordType>())) { + if (CXXCtorInitializer *Value = Info.AllBaseFields.lookup( + Base.getType()->getAsCanonical<RecordType>())) { Info.AllToInit.push_back(Value); } else if (!AnyErrors) { CXXCtorInitializer *CXXBaseInit; @@ -5635,7 +5629,7 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, } static void PopulateKeysForFields(FieldDecl *Field, SmallVectorImpl<const void*> &IdealInits) { - if (const RecordType *RT = Field->getType()->getAs<RecordType>()) { + if (const RecordType *RT = Field->getType()->getAsCanonical<RecordType>()) { const RecordDecl *RD = RT->getOriginalDecl(); if (RD->isAnonymousStructOrUnion()) { for (auto *Field : RD->getDefinitionOrSelf()->fields()) @@ -7611,12 +7605,9 @@ static bool defaultedSpecialMemberIsConstexpr( // class is a constexpr function, and if (!S.getLangOpts().CPlusPlus23) { for (const auto &B : ClassDecl->bases()) { - const RecordType *BaseType = B.getType()->getAs<RecordType>(); - if (!BaseType) + auto *BaseClassDecl = B.getType()->getAsCXXRecordDecl(); + if (!BaseClassDecl) continue; - CXXRecordDecl *BaseClassDecl = - cast<CXXRecordDecl>(BaseType->getOriginalDecl()) - ->getDefinitionOrSelf(); if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg, InheritedCtor, Inherited)) return false; @@ -7638,7 +7629,7 @@ static bool defaultedSpecialMemberIsConstexpr( F->hasInClassInitializer()) continue; QualType BaseType = S.Context.getBaseElementType(F->getType()); - if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) { + if (const RecordType *RecordTy = BaseType->getAsCanonical<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getOriginalDecl()) ->getDefinitionOrSelf(); @@ -10478,11 +10469,7 @@ public: /// method overloads virtual methods in a base class without overriding any, /// to be used with CXXRecordDecl::lookupInBases(). bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { - RecordDecl *BaseRecord = Specifier->getType() - ->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); - + auto *BaseRecord = Specifier->getType()->castAsRecordDecl(); DeclarationName Name = Method->getDeclName(); assert(Name.getNameKind() == DeclarationName::Identifier); @@ -10637,7 +10624,8 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { return; } - if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs<RecordType>()) + if (const auto *RT = + FT->getBaseElementTypeUnsafe()->getAsCanonical<RecordType>()) if (!RT->isDependentType() && !cast<CXXRecordDecl>(RT->getOriginalDecl()->getDefinitionOrSelf()) ->canPassInRegisters()) { @@ -12640,16 +12628,17 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation EnumLoc, SourceRange TyLoc, const IdentifierInfo &II, ParsedType Ty, - CXXScopeSpec *SS) { - assert(SS && !SS->isInvalid() && "ScopeSpec is invalid"); + const CXXScopeSpec &SS) { TypeSourceInfo *TSI = nullptr; SourceLocation IdentLoc = TyLoc.getBegin(); QualType EnumTy = GetTypeFromParser(Ty, &TSI); if (EnumTy.isNull()) { - Diag(IdentLoc, isDependentScopeSpecifier(*SS) + Diag(IdentLoc, isDependentScopeSpecifier(SS) ? diag::err_using_enum_is_dependent : diag::err_unknown_typename) - << II.getName() << SourceRange(SS->getBeginLoc(), TyLoc.getEnd()); + << II.getName() + << SourceRange(SS.isValid() ? SS.getBeginLoc() : IdentLoc, + TyLoc.getEnd()); return nullptr; } @@ -12658,15 +12647,12 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS, return nullptr; } - auto *Enum = dyn_cast_if_present<EnumDecl>(EnumTy->getAsTagDecl()); + auto *Enum = EnumTy->getAsEnumDecl(); if (!Enum) { Diag(IdentLoc, diag::err_using_enum_not_enum) << EnumTy; return nullptr; } - if (auto *Def = Enum->getDefinition()) - Enum = Def; - if (TSI == nullptr) TSI = Context.getTrivialTypeSourceInfo(EnumTy, IdentLoc); @@ -13937,12 +13923,10 @@ struct SpecialMemberExceptionSpecInfo } bool SpecialMemberExceptionSpecInfo::visitBase(CXXBaseSpecifier *Base) { - auto *RT = Base->getType()->getAs<RecordType>(); - if (!RT) + auto *BaseClass = Base->getType()->getAsCXXRecordDecl(); + if (!BaseClass) return false; - auto *BaseClass = - cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(); Sema::SpecialMemberOverloadResult SMOR = lookupInheritedCtor(BaseClass); if (auto *BaseCtor = SMOR.getMethod()) { visitSubobjectCall(Base, BaseCtor); @@ -13966,11 +13950,9 @@ bool SpecialMemberExceptionSpecInfo::visitField(FieldDecl *FD) { E = S.BuildCXXDefaultInitExpr(Loc, FD).get(); if (E) ExceptSpec.CalledExpr(E); - } else if (auto *RT = S.Context.getBaseElementType(FD->getType()) - ->getAs<RecordType>()) { - visitClassSubobject( - cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(), FD, - FD->getType().getCVRQualifiers()); + } else if (auto *RD = S.Context.getBaseElementType(FD->getType()) + ->getAsCXXRecordDecl()) { + visitClassSubobject(RD, FD, FD->getType().getCVRQualifiers()); } return false; } @@ -14785,11 +14767,9 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T, S.Context, To, UO_AddrOf, S.Context.getPointerType(To->getType()), VK_PRValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides()); - const Type *E = T->getBaseElementTypeUnsafe(); - bool NeedsCollectableMemCpy = E->isRecordType() && E->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasObjectMember(); + bool NeedsCollectableMemCpy = false; + if (auto *RD = T->getBaseElementTypeUnsafe()->getAsRecordDecl()) + NeedsCollectableMemCpy = RD->hasObjectMember(); // Create a reference to the __builtin_objc_memmove_collectable function StringRef MemCpyName = NeedsCollectableMemCpy ? @@ -14865,10 +14845,7 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, // the class is used (as if by explicit qualification; that is, // ignoring any possible virtual overriding functions in more derived // classes); - if (const RecordType *RecordTy = T->getAs<RecordType>()) { - CXXRecordDecl *ClassDecl = - cast<CXXRecordDecl>(RecordTy->getOriginalDecl())->getDefinitionOrSelf(); - + if (auto *ClassDecl = T->getAsCXXRecordDecl()) { // Look for operator=. DeclarationName Name = S.Context.DeclarationNames.getCXXOperatorName(OO_Equal); @@ -15340,7 +15317,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Check for members of const-qualified, non-class type. QualType BaseType = Context.getBaseElementType(Field->getType()); - if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) { + if (!BaseType->isRecordType() && BaseType.isConstQualified()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getCanonicalTagType(ClassDecl) << 1 << Field->getDeclName(); @@ -15729,7 +15706,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, // Check for members of const-qualified, non-class type. QualType BaseType = Context.getBaseElementType(Field->getType()); - if (!BaseType->getAs<RecordType>() && BaseType.isConstQualified()) { + if (!BaseType->isRecordType() && BaseType.isConstQualified()) { Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign) << Context.getCanonicalTagType(ClassDecl) << 1 << Field->getDeclName(); @@ -16322,15 +16299,14 @@ ExprResult Sema::BuildCXXConstructExpr( Constructor); } -void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { +void Sema::FinalizeVarWithDestructor(VarDecl *VD, CXXRecordDecl *ClassDecl) { if (VD->isInvalidDecl()) return; // If initializing the variable failed, don't also diagnose problems with // the destructor, they're likely related. if (VD->getInit() && VD->getInit()->containsErrors()) return; - CXXRecordDecl *ClassDecl = - cast<CXXRecordDecl>(Record->getOriginalDecl())->getDefinitionOrSelf(); + ClassDecl = ClassDecl->getDefinitionOrSelf(); if (ClassDecl->isInvalidDecl()) return; if (ClassDecl->hasIrrelevantDestructor()) return; if (ClassDecl->isDependentContext()) return; @@ -16988,9 +16964,9 @@ checkLiteralOperatorTemplateParameterList(Sema &SemaRef, // first template parameter as its type. if (PmType && PmArgs && !PmType->isTemplateParameterPack() && PmArgs->isTemplateParameterPack()) { - const TemplateTypeParmType *TArgs = - PmArgs->getType()->getAs<TemplateTypeParmType>(); - if (TArgs && TArgs->getDepth() == PmType->getDepth() && + if (const auto *TArgs = + PmArgs->getType()->getAsCanonical<TemplateTypeParmType>(); + TArgs && TArgs->getDepth() == PmType->getDepth() && TArgs->getIndex() == PmType->getIndex()) { if (!SemaRef.inTemplateInstantiation()) SemaRef.Diag(TpDecl->getLocation(), @@ -17337,7 +17313,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, Invalid = true; if (!Invalid && !ExDeclType->isDependentType()) { - if (const RecordType *recordType = ExDeclType->getAs<RecordType>()) { + if (auto *ClassDecl = ExDeclType->getAsCXXRecordDecl()) { // Insulate this from anything else we might currently be parsing. EnterExpressionEvaluationContext scope( *this, ExpressionEvaluationContext::PotentiallyEvaluated); @@ -17374,7 +17350,7 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, } // And make sure it's destructable. - FinalizeVarWithDestructor(ExDecl, recordType); + FinalizeVarWithDestructor(ExDecl, ClassDecl); } } } @@ -18813,8 +18789,8 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, // that of B::f, the class type in the return type of D::f shall be // complete at the point of declaration of D::f or shall be the class // type D. - if (const RecordType *RT = NewClassTy->getAs<RecordType>()) { - if (!RT->getOriginalDecl()->isEntityBeingDefined() && + if (const auto *RD = NewClassTy->getAsCXXRecordDecl()) { + if (!RD->isBeingDefined() && RequireCompleteType(New->getLocation(), NewClassTy, diag::err_covariant_return_incomplete, New->getDeclName())) @@ -19169,9 +19145,7 @@ void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, return; for (const auto &I : RD->bases()) { - const auto *Base = cast<CXXRecordDecl>( - I.getType()->castAs<RecordType>()->getOriginalDecl()) - ->getDefinitionOrSelf(); + const auto *Base = I.getType()->castAsCXXRecordDecl(); if (Base->getNumVBases() == 0) continue; MarkVirtualMembersReferenced(Loc, Base); diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 88ed83eca243..98eb5afb7c99 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -3848,10 +3848,8 @@ SemaObjC::ObjCContainerKind SemaObjC::getObjCContainerKind() const { static bool IsVariableSizedType(QualType T) { if (T->isIncompleteArrayType()) return true; - const auto *RecordTy = T->getAs<RecordType>(); - return (RecordTy && RecordTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()); + const auto *RD = T->getAsRecordDecl(); + return RD && RD->hasFlexibleArrayMember(); } static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) { @@ -3896,15 +3894,11 @@ static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) { << ivar->getDeclName() << IvarTy << TagTypeKind::Class; // Use "class" for Obj-C. IsInvalidIvar = true; - } else if (const RecordType *RecordTy = IvarTy->getAs<RecordType>()) { - if (RecordTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) { - S.Diag(ivar->getLocation(), - diag::err_objc_variable_sized_type_not_at_end) - << ivar->getDeclName() << IvarTy; - IsInvalidIvar = true; - } + } else if (const auto *RD = IvarTy->getAsRecordDecl(); + RD && RD->hasFlexibleArrayMember()) { + S.Diag(ivar->getLocation(), diag::err_objc_variable_sized_type_not_at_end) + << ivar->getDeclName() << IvarTy; + IsInvalidIvar = true; } if (IsInvalidIvar) { S.Diag(ivar->getNextIvar()->getLocation(), @@ -5541,11 +5535,8 @@ void SemaObjC::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { AllToInit.push_back(Member); // Be sure that the destructor is accessible and is marked as referenced. - if (const RecordType *RecordTy = - Context.getBaseElementType(Field->getType()) - ->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getOriginalDecl()) - ->getDefinitionOrSelf(); + if (auto *RD = Context.getBaseElementType(Field->getType()) + ->getAsCXXRecordDecl()) { if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(RD)) { SemaRef.MarkFunctionReferenced(Field->getLocation(), Destructor); SemaRef.CheckDestructorAccess( diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 94413b5b92d2..552c92996dc2 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -163,9 +163,8 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { DiagID = diag::ext_incomplete_in_exception_spec; ReturnValueOnError = false; } - if (!(PointeeT->isRecordType() && PointeeT->castAs<RecordType>() - ->getOriginalDecl() - ->isEntityBeingDefined()) && + if (auto *RD = PointeeT->getAsRecordDecl(); + !(RD && RD->isBeingDefined()) && RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) return ReturnValueOnError; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index a73093545aa7..aba00dc8ff9b 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -18,6 +18,7 @@ #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/Attrs.inc" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -1528,8 +1529,12 @@ void Sema::checkEnumArithmeticConversions(Expr *LHS, Expr *RHS, // are ill-formed. if (getLangOpts().CPlusPlus26) DiagID = diag::warn_conv_mixed_enum_types_cxx26; - else if (!L->castAs<EnumType>()->getOriginalDecl()->hasNameForLinkage() || - !R->castAs<EnumType>()->getOriginalDecl()->hasNameForLinkage()) { + else if (!L->castAsCanonical<EnumType>() + ->getOriginalDecl() + ->hasNameForLinkage() || + !R->castAsCanonical<EnumType>() + ->getOriginalDecl() + ->hasNameForLinkage()) { // If either enumeration type is unnamed, it's less likely that the // user cares about this, but this situation is still deprecated in // C++2a. Use a different warning group. @@ -6308,30 +6313,38 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, unsigned i = 0; SmallVector<QualType, 8> OverloadParams; - for (QualType ParamType : FT->param_types()) { + { + // The lvalue conversions in this loop are only for type resolution and + // don't actually occur. + EnterExpressionEvaluationContext Unevaluated( + *Sema, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap Trap(*Sema, /*ForValidityCheck=*/true); - // Convert array arguments to pointer to simplify type lookup. - ExprResult ArgRes = - Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]); - if (ArgRes.isInvalid()) - return nullptr; - Expr *Arg = ArgRes.get(); - QualType ArgType = Arg->getType(); - if (!ParamType->isPointerType() || - ParamType->getPointeeType().hasAddressSpace() || - !ArgType->isPointerType() || - !ArgType->getPointeeType().hasAddressSpace() || - isPtrSizeAddressSpace(ArgType->getPointeeType().getAddressSpace())) { - OverloadParams.push_back(ParamType); - continue; - } + for (QualType ParamType : FT->param_types()) { - QualType PointeeType = ParamType->getPointeeType(); - NeedsNewDecl = true; - LangAS AS = ArgType->getPointeeType().getAddressSpace(); + // Convert array arguments to pointer to simplify type lookup. + ExprResult ArgRes = + Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]); + if (ArgRes.isInvalid()) + return nullptr; + Expr *Arg = ArgRes.get(); + QualType ArgType = Arg->getType(); + if (!ParamType->isPointerType() || + ParamType->getPointeeType().hasAddressSpace() || + !ArgType->isPointerType() || + !ArgType->getPointeeType().hasAddressSpace() || + isPtrSizeAddressSpace(ArgType->getPointeeType().getAddressSpace())) { + OverloadParams.push_back(ParamType); + continue; + } - PointeeType = Context.getAddrSpaceQualType(PointeeType, AS); - OverloadParams.push_back(Context.getPointerType(PointeeType)); + QualType PointeeType = ParamType->getPointeeType(); + NeedsNewDecl = true; + LangAS AS = ArgType->getPointeeType().getAddressSpace(); + + PointeeType = Context.getAddrSpaceQualType(PointeeType, AS); + OverloadParams.push_back(Context.getPointerType(PointeeType)); + } } if (!NeedsNewDecl) @@ -7818,6 +7831,41 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, return prepareVectorSplat(DestTy, CastExpr); } +/// Check that a call to alloc_size function specifies sufficient space for the +/// destination type. +static void CheckSufficientAllocSize(Sema &S, QualType DestType, + const Expr *E) { + QualType SourceType = E->getType(); + if (!DestType->isPointerType() || !SourceType->isPointerType() || + DestType == SourceType) + return; + + const auto *CE = dyn_cast<CallExpr>(E->IgnoreParenCasts()); + if (!CE) + return; + + // Find the total size allocated by the function call. + if (!CE->getCalleeAllocSizeAttr()) + return; + std::optional<llvm::APInt> AllocSize = + CE->evaluateBytesReturnedByAllocSizeCall(S.Context); + // Allocations of size zero are permitted as a special case. They are usually + // done intentionally. + if (!AllocSize || AllocSize->isZero()) + return; + auto Size = CharUnits::fromQuantity(AllocSize->getZExtValue()); + + QualType TargetType = DestType->getPointeeType(); + // Find the destination size. As a special case function types have size of + // one byte to match the sizeof operator behavior. + auto LhsSize = TargetType->isFunctionType() + ? CharUnits::One() + : S.Context.getTypeSizeInCharsIfKnown(TargetType); + if (LhsSize && Size < LhsSize) + S.Diag(E->getExprLoc(), diag::warn_alloc_size) + << Size.getQuantity() << TargetType << LhsSize->getQuantity(); +} + ExprResult Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, Declarator &D, ParsedType &Ty, @@ -7883,6 +7931,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, DiscardMisalignedMemberAddress(castType.getTypePtr(), CastExpr); + CheckSufficientAllocSize(*this, castType, CastExpr); + return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr); } @@ -8605,16 +8655,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // If both operands are the same structure or union type, the result is that // type. - if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3 - if (const RecordType *RHSRT = RHSTy->getAs<RecordType>()) - if (declaresSameEntity(LHSRT->getOriginalDecl(), - RHSRT->getOriginalDecl())) - // "If both the operands have structure or union type, the result has - // that type." This implies that CV qualifiers are dropped. - return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(), - RHSTy.getUnqualifiedType()); - // FIXME: Type of conditional expression must be complete in C mode. - } + // FIXME: Type of conditional expression must be complete in C mode. + if (LHSTy->isRecordType() && + Context.hasSameUnqualifiedType(LHSTy, RHSTy)) // C99 6.5.15p3 + return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(), + RHSTy.getUnqualifiedType()); // C99 6.5.15p5: "If both operands have void type, the result has void type." // The following || allows only one side to be void (a GCC-ism). @@ -9893,6 +9938,12 @@ AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType, AssignConvertType result = CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS); + // If assigning a void * created by an allocation function call to some other + // type, check that the allocated size is sufficient for that type. + if (result != AssignConvertType::Incompatible && + RHS.get()->getType()->isVoidPointerType()) + CheckSufficientAllocSize(*this, LHSType, RHS.get()); + // C99 6.5.16.1p2: The value of the right operand is converted to the // type of the assignment expression. // CheckAssignmentConstraints allows the left-hand side to be a reference, @@ -11458,7 +11509,7 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, } static bool isScopedEnumerationType(QualType T) { - if (const EnumType *ET = T->getAs<EnumType>()) + if (const EnumType *ET = T->getAsCanonical<EnumType>()) return ET->getOriginalDecl()->isScoped(); return false; } @@ -12345,10 +12396,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, S.InvalidOperands(Loc, LHS, RHS); return QualType(); } - QualType IntType = LHSStrippedType->castAs<EnumType>() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->getIntegerType(); + QualType IntType = LHSStrippedType->castAsEnumDecl()->getIntegerType(); assert(IntType->isArithmeticType()); // We can't use `CK_IntegralCast` when the underlying type is 'bool', so we @@ -13582,6 +13630,8 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) { VarDecl *Var = dyn_cast<VarDecl>(Value); if (!Var) return NCCK_None; + if (Var->getType()->isReferenceType()) + return NCCK_None; assert(Var->hasLocalStorage() && "capture added 'const' to non-local?"); @@ -13785,7 +13835,7 @@ static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD, // Then we append it to the list to check next in order. FieldTy = FieldTy.getCanonicalType(); - if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) { + if (const auto *FieldRecTy = FieldTy->getAsCanonical<RecordType>()) { if (!llvm::is_contained(RecordTypeList, FieldRecTy)) RecordTypeList.push_back(FieldRecTy); } @@ -13801,7 +13851,7 @@ static void DiagnoseRecursiveConstFields(Sema &S, const Expr *E, QualType Ty = E->getType(); assert(Ty->isRecordType() && "lvalue was not record?"); SourceRange Range = E->getSourceRange(); - const RecordType *RTy = Ty.getCanonicalType()->getAs<RecordType>(); + const auto *RTy = Ty->getAsCanonical<RecordType>(); bool DiagEmitted = false; if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) @@ -16217,11 +16267,10 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, return ExprError(); // Look for the designated field. - const RecordType *RC = CurrentType->getAs<RecordType>(); - if (!RC) + auto *RD = CurrentType->getAsRecordDecl(); + if (!RD) return ExprError(Diag(OC.LocEnd, diag::err_offsetof_record_type) << CurrentType); - RecordDecl *RD = RC->getOriginalDecl()->getDefinitionOrSelf(); // C++ [lib.support.types]p5: // The macro offsetof accepts a restricted set of type arguments in this @@ -16618,8 +16667,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, auto *Var = cast<VarDecl>(Cap.getVariable()); Expr *CopyExpr = nullptr; if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) { - if (const RecordType *Record = - Cap.getCaptureType()->getAs<RecordType>()) { + if (auto *Record = Cap.getCaptureType()->getAsCXXRecordDecl()) { // The capture logic needs the destructor, so make sure we mark it. // Usually this is unnecessary because most local variables have // their destructors marked at declaration time, but parameters are @@ -16847,9 +16895,8 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, // va_arg. Instead, get the underlying type of the enumeration and pass // that. QualType UnderlyingType = TInfo->getType(); - if (const auto *ET = UnderlyingType->getAs<EnumType>()) - UnderlyingType = - ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = UnderlyingType->getAsEnumDecl()) + UnderlyingType = ED->getIntegerType(); if (Context.typesAreCompatible(PromoteType, UnderlyingType, /*CompareUnqualified*/ true)) PromoteType = QualType(); @@ -18846,19 +18893,16 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var, } // Prohibit structs with flexible array members too. // We cannot capture what is in the tail end of the struct. - if (const RecordType *VTTy = Var->getType()->getAs<RecordType>()) { - if (VTTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) { - if (Diagnose) { - if (IsBlock) - S.Diag(Loc, diag::err_ref_flexarray_type); - else - S.Diag(Loc, diag::err_lambda_capture_flexarray_type) << Var; - S.Diag(Var->getLocation(), diag::note_previous_decl) << Var; - } - return false; + if (const auto *VTD = Var->getType()->getAsRecordDecl(); + VTD && VTD->hasFlexibleArrayMember()) { + if (Diagnose) { + if (IsBlock) + S.Diag(Loc, diag::err_ref_flexarray_type); + else + S.Diag(Loc, diag::err_lambda_capture_flexarray_type) << Var; + S.Diag(Var->getLocation(), diag::note_previous_decl) << Var; } + return false; } const bool HasBlocksAttr = Var->hasAttr<BlocksAttr>(); // Lambdas and captured statements are not allowed to capture __block @@ -19938,7 +19982,7 @@ ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) { // C++2a [basic.def.odr]p4: // [...] an expression of non-volatile-qualified non-class type to which // the lvalue-to-rvalue conversion is applied [...] - if (E->getType().isVolatileQualified() || E->getType()->getAs<RecordType>()) + if (E->getType().isVolatileQualified() || E->getType()->isRecordType()) return E; ExprResult Result = @@ -21440,8 +21484,11 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { // Expressions of unknown type. case BuiltinType::ArraySection: - Diag(E->getBeginLoc(), diag::err_array_section_use) - << cast<ArraySectionExpr>(E)->isOMPArraySection(); + // If we've already diagnosed something on the array section type, we + // shouldn't need to do any further diagnostic here. + if (!E->containsErrors()) + Diag(E->getBeginLoc(), diag::err_array_section_use) + << cast<ArraySectionExpr>(E)->isOMPArraySection(); return ExprError(); // Expressions of unknown type. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 2a8284209544..5a9279d92846 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -543,7 +543,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, QualType T = Context.getUnqualifiedArrayType(Operand->getType().getNonReferenceType(), Quals); - if (T->getAs<RecordType>() && + if (T->isRecordType() && RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); @@ -570,9 +570,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, } QualType T = E->getType(); - if (const RecordType *RecordT = T->getAs<RecordType>()) { - CXXRecordDecl *RecordD = cast<CXXRecordDecl>(RecordT->getOriginalDecl()) - ->getDefinitionOrSelf(); + if (auto *RecordD = T->getAsCXXRecordDecl()) { // C++ [expr.typeid]p3: // [...] If the type of the expression is a class type, the class // shall be completely-defined. @@ -1975,8 +1973,8 @@ static UsualDeallocFnInfo resolveDeallocationOverload( static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, TypeAwareAllocationMode PassType, QualType allocType) { - const RecordType *record = - allocType->getBaseElementTypeUnsafe()->getAs<RecordType>(); + const auto *record = + allocType->getBaseElementTypeUnsafe()->getAsCanonical<RecordType>(); if (!record) return false; // Try to find an operator delete[] in class scope. @@ -2297,8 +2295,7 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, ConvertedSize = PerformImplicitConversion( *ArraySize, Context.getSizeType(), AssignmentAction::Converting); - if (!ConvertedSize.isInvalid() && - (*ArraySize)->getType()->getAs<RecordType>()) + if (!ConvertedSize.isInvalid() && (*ArraySize)->getType()->isRecordType()) // Diagnose the compatibility of this conversion. Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion) << (*ArraySize)->getType() << 0 << "'size_t'"; @@ -3055,9 +3052,7 @@ bool Sema::FindAllocationFunctions( LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && DeleteScope != AllocationFunctionScope::Global) { - auto *RD = cast<CXXRecordDecl>( - AllocElemType->castAs<RecordType>()->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *RD = AllocElemType->castAsCXXRecordDecl(); LookupQualifiedName(FoundDelete, RD); } if (FoundDelete.isAmbiguous()) @@ -4070,9 +4065,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, ? diag::err_delete_incomplete : diag::warn_delete_incomplete, Ex.get())) { - if (const RecordType *RT = PointeeElem->getAs<RecordType>()) - PointeeRD = - cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(); + PointeeRD = PointeeElem->getAsCXXRecordDecl(); } } @@ -4840,10 +4833,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, if (FromType->isVectorType() || ToType->isVectorType()) StepTy = adjustVectorType(Context, FromType, ToType, &ElTy); if (ElTy->isBooleanType()) { - assert(FromType->castAs<EnumType>() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->isFixed() && + assert(FromType->castAsEnumDecl()->isFixed() && SCS.Second == ICK_Integral_Promotion && "only enums with fixed underlying type can promote to bool"); From = ImpCastExprToType(From, StepTy, CK_IntegralToBoolean, VK_PRValue, @@ -5529,8 +5519,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // the same or one is a base class of the other: QualType FTy = From->getType(); QualType TTy = To->getType(); - const RecordType *FRec = FTy->getAs<RecordType>(); - const RecordType *TRec = TTy->getAs<RecordType>(); + const RecordType *FRec = FTy->getAsCanonical<RecordType>(); + const RecordType *TRec = TTy->getAsCanonical<RecordType>(); bool FDerivedFromT = FRec && TRec && FRec != TRec && Self.IsDerivedFrom(QuestionLoc, FTy, TTy); if (FRec && TRec && (FRec == TRec || FDerivedFromT || @@ -7528,12 +7518,10 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { } // GCC seems to also exclude expressions of incomplete enum type. - if (const EnumType *T = E->getType()->getAs<EnumType>()) { - if (!T->getOriginalDecl()->getDefinitionOrSelf()->isComplete()) { - // FIXME: stupid workaround for a codegen bug! - E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).get(); - return E; - } + if (const auto *ED = E->getType()->getAsEnumDecl(); ED && !ED->isComplete()) { + // FIXME: stupid workaround for a codegen bug! + E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).get(); + return E; } ExprResult Res = DefaultFunctionArrayLvalueConversion(E); diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 4a31a139eaf4..aedfc5e88b1c 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1126,8 +1126,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, return ExprError(); } - DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc, - MemberNameInfo.getLoc(), *TemplateArgs); + DeclResult VDecl = + CheckVarTemplateId(VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), + *TemplateArgs, /*SetWrittenArgs=*/false); if (VDecl.isInvalid()) return ExprError(); diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 03b5c79cf70e..331f6e585555 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -638,8 +638,7 @@ ExprResult SemaObjC::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { // Look for the appropriate method within NSNumber. BoxingMethod = getNSNumberFactoryMethod(*this, Loc, ValueType); BoxedType = NSNumberPointer; - } else if (const EnumType *ET = ValueType->getAs<EnumType>()) { - const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + } else if (const auto *ED = ValueType->getAsEnumDecl()) { if (!ED->isComplete()) { Diag(Loc, diag::err_objc_incomplete_boxed_expression_type) << ValueType << ValueExpr->getSourceRange(); @@ -3846,7 +3845,7 @@ static inline T *getObjCBridgeAttr(const TypedefType *TD) { QualType QT = TDNDecl->getUnderlyingType(); if (QT->isPointerType()) { QT = QT->getPointeeType(); - if (const RecordType *RT = QT->getAs<RecordType>()) { + if (const RecordType *RT = QT->getAsCanonical<RecordType>()) { for (auto *Redecl : RT->getOriginalDecl()->getMostRecentDecl()->redecls()) { if (auto *attr = Redecl->getAttr<T>()) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f87715950c74..6062f81d0aed 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -236,9 +236,8 @@ static unsigned calculateLegacyCbufferFieldAlign(const ASTContext &Context, static unsigned calculateLegacyCbufferSize(const ASTContext &Context, QualType T) { constexpr unsigned CBufferAlign = 16; - if (const RecordType *RT = T->getAs<RecordType>()) { + if (const auto *RD = T->getAsRecordDecl()) { unsigned Size = 0; - const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf(); for (const FieldDecl *Field : RD->fields()) { QualType Ty = Field->getType(); unsigned FieldSize = calculateLegacyCbufferSize(Context, Ty); @@ -351,8 +350,8 @@ getResourceArrayHandleType(VarDecl *VD) { assert(VD->getType()->isHLSLResourceRecordArray() && "expected array of resource records"); const Type *Ty = VD->getType()->getUnqualifiedDesugaredType(); - while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) - Ty = CAT->getArrayElementTypeNoTypeQual()->getUnqualifiedDesugaredType(); + while (const ArrayType *AT = dyn_cast<ArrayType>(Ty)) + Ty = AT->getArrayElementTypeNoTypeQual()->getUnqualifiedDesugaredType(); return HLSLAttributedResourceType::findHandleTypeOnResource(Ty); } @@ -364,8 +363,8 @@ static bool isInvalidConstantBufferLeafElementType(const Type *Ty) { Ty = Ty->getUnqualifiedDesugaredType(); if (Ty->isHLSLResourceRecord() || Ty->isHLSLResourceRecordArray()) return true; - if (Ty->isRecordType()) - return Ty->getAsCXXRecordDecl()->isEmpty(); + if (const auto *RD = Ty->getAsCXXRecordDecl()) + return RD->isEmpty(); if (Ty->isConstantArrayType() && isZeroSizedArray(cast<ConstantArrayType>(Ty))) return true; @@ -387,14 +386,14 @@ static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) { QualType Ty = Field->getType(); if (isInvalidConstantBufferLeafElementType(Ty.getTypePtr())) return true; - if (Ty->isRecordType() && - requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl())) + if (const auto *RD = Ty->getAsCXXRecordDecl(); + RD && requiresImplicitBufferLayoutStructure(RD)) return true; } // check bases for (const CXXBaseSpecifier &Base : RD->bases()) if (requiresImplicitBufferLayoutStructure( - Base.getType()->getAsCXXRecordDecl())) + Base.getType()->castAsCXXRecordDecl())) return true; return false; } @@ -459,8 +458,7 @@ static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty, if (isInvalidConstantBufferLeafElementType(Ty)) return nullptr; - if (Ty->isRecordType()) { - CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + if (auto *RD = Ty->getAsCXXRecordDecl()) { if (requiresImplicitBufferLayoutStructure(RD)) { RD = createHostLayoutStruct(S, RD); if (!RD) @@ -511,7 +509,7 @@ static CXXRecordDecl *createHostLayoutStruct(Sema &S, assert(NumBases == 1 && "HLSL supports only one base type"); (void)NumBases; CXXBaseSpecifier Base = *StructDecl->bases_begin(); - CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); + CXXRecordDecl *BaseDecl = Base.getType()->castAsCXXRecordDecl(); if (requiresImplicitBufferLayoutStructure(BaseDecl)) { BaseDecl = createHostLayoutStruct(S, BaseDecl); if (BaseDecl) { @@ -729,6 +727,19 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { if (FD->getName() != TargetInfo.getTargetOpts().HLSLEntry) return; + // If we have specified a root signature to override the entry function then + // attach it now + HLSLRootSignatureDecl *SignatureDecl = + lookupRootSignatureOverrideDecl(FD->getDeclContext()); + if (SignatureDecl) { + FD->dropAttr<RootSignatureAttr>(); + // We could look up the SourceRange of the macro here as well + AttributeCommonInfo AL(RootSigOverrideIdent, AttributeScopeInfo(), + SourceRange(), ParsedAttr::Form::Microsoft()); + FD->addAttr(::new (getASTContext()) RootSignatureAttr( + getASTContext(), AL, RootSigOverrideIdent, SignatureDecl)); + } + llvm::Triple::EnvironmentType Env = TargetInfo.getTriple().getEnvironment(); if (HLSLShaderAttr::isValidShaderType(Env) && Env != llvm::Triple::Library) { if (const auto *Shader = FD->getAttr<HLSLShaderAttr>()) { @@ -750,6 +761,8 @@ void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { case llvm::Triple::UnknownEnvironment: case llvm::Triple::Library: break; + case llvm::Triple::RootSignature: + llvm_unreachable("rootsig environment has no functions"); default: llvm_unreachable("Unhandled environment in triple"); } @@ -812,6 +825,8 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { } } break; + case llvm::Triple::RootSignature: + llvm_unreachable("rootsig environment has no function entry point"); default: llvm_unreachable("Unhandled environment in triple"); } @@ -1092,6 +1107,18 @@ void SemaHLSL::ActOnFinishRootSignatureDecl( SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope()); } +HLSLRootSignatureDecl * +SemaHLSL::lookupRootSignatureOverrideDecl(DeclContext *DC) const { + if (RootSigOverrideIdent) { + LookupResult R(SemaRef, RootSigOverrideIdent, SourceLocation(), + Sema::LookupOrdinaryName); + if (SemaRef.LookupQualifiedName(R, DC)) + return dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl()); + } + + return nullptr; +} + namespace { struct PerVisibilityBindingChecker { @@ -1144,15 +1171,14 @@ struct PerVisibilityBindingChecker { bool HadOverlap = false; using llvm::hlsl::BindingInfoBuilder; - auto ReportOverlap = [this, &HadOverlap]( - const BindingInfoBuilder &Builder, - const BindingInfoBuilder::Binding &Reported) { + auto ReportOverlap = [this, + &HadOverlap](const BindingInfoBuilder &Builder, + const llvm::hlsl::Binding &Reported) { HadOverlap = true; const auto *Elem = static_cast<const hlsl::RootSignatureElement *>(Reported.Cookie); - const BindingInfoBuilder::Binding &Previous = - Builder.findOverlapping(Reported); + const llvm::hlsl::Binding &Previous = Builder.findOverlapping(Reported); const auto *PrevElem = static_cast<const hlsl::RootSignatureElement *>(Previous.Cookie); @@ -1269,9 +1295,8 @@ bool SemaHLSL::handleRootSignatureElements( ReportError(Loc, 1, 0xfffffffe); } - if (!llvm::hlsl::rootsig::verifyDescriptorRangeFlag( - Version, llvm::to_underlying(Clause->Type), - llvm::to_underlying(Clause->Flags))) + if (!llvm::hlsl::rootsig::verifyDescriptorRangeFlag(Version, Clause->Type, + Clause->Flags)) ReportFlagError(Loc); } } @@ -1317,12 +1342,48 @@ bool SemaHLSL::handleRootSignatureElements( std::get_if<llvm::hlsl::rootsig::DescriptorTable>(&Elem)) { assert(UnboundClauses.size() == Table->NumClauses && "Number of unbound elements must match the number of clauses"); + bool HasAnySampler = false; + bool HasAnyNonSampler = false; + uint32_t Offset = 0; for (const auto &[Clause, ClauseElem] : UnboundClauses) { - uint32_t LowerBound(Clause->Reg.Number); + SourceLocation Loc = ClauseElem->getLocation(); + if (Clause->Type == llvm::dxil::ResourceClass::Sampler) + HasAnySampler = true; + else + HasAnyNonSampler = true; + + if (HasAnySampler && HasAnyNonSampler) + Diag(Loc, diag::err_hlsl_invalid_mixed_resources); + // Relevant error will have already been reported above and needs to be - // fixed before we can conduct range analysis, so shortcut error return + // fixed before we can conduct further analysis, so shortcut error + // return if (Clause->NumDescriptors == 0) return true; + + if (Clause->Offset != + llvm::hlsl::rootsig::DescriptorTableOffsetAppend) { + // Manually specified the offset + Offset = Clause->Offset; + } + + uint64_t RangeBound = llvm::hlsl::rootsig::computeRangeBound( + Offset, Clause->NumDescriptors); + + if (!llvm::hlsl::rootsig::verifyBoundOffset(Offset)) { + // Trying to append onto unbound offset + Diag(Loc, diag::err_hlsl_appending_onto_unbound); + } else if (!llvm::hlsl::rootsig::verifyNoOverflowedOffset(RangeBound)) { + // Upper bound overflows maximum offset + Diag(Loc, diag::err_hlsl_offset_overflow) << Offset << RangeBound; + } + + Offset = RangeBound == llvm::hlsl::rootsig::NumDescriptorsUnbounded + ? uint32_t(RangeBound) + : uint32_t(RangeBound + 1); + + // Compute the register bounds and track resource binding + uint32_t LowerBound(Clause->Reg.Number); uint32_t UpperBound = Clause->NumDescriptors == ~0u ? ~0u : LowerBound + Clause->NumDescriptors - 1; @@ -2008,9 +2069,11 @@ static bool DiagnoseHLSLRegisterAttribute(Sema &S, SourceLocation &ArgLoc, } void SemaHLSL::handleResourceBindingAttr(Decl *TheDecl, const ParsedAttr &AL) { - if (isa<VarDecl>(TheDecl)) { - if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(), - cast<ValueDecl>(TheDecl)->getType(), + if (VarDecl *VD = dyn_cast<VarDecl>(TheDecl)) { + QualType Ty = VD->getType(); + if (const auto *IAT = dyn_cast<IncompleteArrayType>(Ty)) + Ty = IAT->getElementType(); + if (SemaRef.RequireCompleteType(TheDecl->getBeginLoc(), Ty, diag::err_incomplete_type)) return; } @@ -2838,8 +2901,8 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (SemaRef.checkArgCount(TheCall, 6) || CheckResourceHandle(&SemaRef, TheCall, 0) || CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) || - CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.IntTy) || - CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.UnsignedIntTy) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(2), AST.UnsignedIntTy) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(3), AST.IntTy) || CheckArgTypeMatches(&SemaRef, TheCall->getArg(4), AST.UnsignedIntTy) || CheckArgTypeMatches(&SemaRef, TheCall->getArg(5), AST.getPointerType(AST.CharTy.withConst()))) @@ -3194,10 +3257,7 @@ static void BuildFlattenedTypeList(QualType BaseTy, List.insert(List.end(), VT->getNumElements(), VT->getElementType()); continue; } - if (const auto *RT = dyn_cast<RecordType>(T)) { - const CXXRecordDecl *RD = RT->getAsCXXRecordDecl(); - assert(RD && "HLSL record types should all be CXXRecordDecls!"); - + if (const auto *RD = T->getAsCXXRecordDecl()) { if (RD->isStandardLayout()) RD = RD->getStandardLayoutBaseWithFields(); @@ -3820,9 +3880,9 @@ void SemaHLSL::collectResourceBindingsOnVarDecl(VarDecl *VD) { // Unwrap arrays // FIXME: Calculate array size while unwrapping const Type *Ty = VD->getType()->getUnqualifiedDesugaredType(); - while (Ty->isConstantArrayType()) { - const ConstantArrayType *CAT = cast<ConstantArrayType>(Ty); - Ty = CAT->getElementType()->getUnqualifiedDesugaredType(); + while (Ty->isArrayType()) { + const ArrayType *AT = cast<ArrayType>(Ty); + Ty = AT->getElementType()->getUnqualifiedDesugaredType(); } // Resource (or array of resources) @@ -3967,19 +4027,19 @@ class InitListTransformer { return true; } - if (auto *RTy = Ty->getAs<RecordType>()) { - llvm::SmallVector<const RecordType *> RecordTypes; - RecordTypes.push_back(RTy); - while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) { - CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl(); + if (auto *RD = Ty->getAsCXXRecordDecl()) { + llvm::SmallVector<CXXRecordDecl *> RecordDecls; + RecordDecls.push_back(RD); + while (RecordDecls.back()->getNumBases()) { + CXXRecordDecl *D = RecordDecls.back(); assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance"); - RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>()); + RecordDecls.push_back( + D->bases_begin()->getType()->castAsCXXRecordDecl()); } - while (!RecordTypes.empty()) { - const RecordType *RT = RecordTypes.pop_back_val(); - for (auto *FD : - RT->getOriginalDecl()->getDefinitionOrSelf()->fields()) { + while (!RecordDecls.empty()) { + CXXRecordDecl *RD = RecordDecls.pop_back_val(); + for (auto *FD : RD->fields()) { DeclAccessPair Found = DeclAccessPair::make(FD, FD->getAccess()); DeclarationNameInfo NameInfo(FD->getDeclName(), E->getBeginLoc()); ExprResult Res = S.BuildFieldReferenceExpr( @@ -4016,21 +4076,20 @@ class InitListTransformer { for (uint64_t I = 0; I < Size; ++I) Inits.push_back(generateInitListsImpl(ElTy)); } - if (auto *RTy = Ty->getAs<RecordType>()) { - llvm::SmallVector<const RecordType *> RecordTypes; - RecordTypes.push_back(RTy); - while (RecordTypes.back()->getAsCXXRecordDecl()->getNumBases()) { - CXXRecordDecl *D = RecordTypes.back()->getAsCXXRecordDecl(); + if (auto *RD = Ty->getAsCXXRecordDecl()) { + llvm::SmallVector<CXXRecordDecl *> RecordDecls; + RecordDecls.push_back(RD); + while (RecordDecls.back()->getNumBases()) { + CXXRecordDecl *D = RecordDecls.back(); assert(D->getNumBases() == 1 && "HLSL doesn't support multiple inheritance"); - RecordTypes.push_back(D->bases_begin()->getType()->getAs<RecordType>()); + RecordDecls.push_back( + D->bases_begin()->getType()->castAsCXXRecordDecl()); } - while (!RecordTypes.empty()) { - const RecordType *RT = RecordTypes.pop_back_val(); - for (auto *FD : - RT->getOriginalDecl()->getDefinitionOrSelf()->fields()) { + while (!RecordDecls.empty()) { + CXXRecordDecl *RD = RecordDecls.pop_back_val(); + for (auto *FD : RD->fields()) Inits.push_back(generateInitListsImpl(FD->getType())); - } } } auto *NewInit = new (Ctx) InitListExpr(Ctx, Inits.front()->getBeginLoc(), diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 60f9d449fc03..c97129336736 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -774,7 +774,7 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, = InitializedEntity::InitializeMember(Field, &ParentEntity); if (Init >= NumInits || !ILE->getInit(Init)) { - if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) + if (const RecordType *RType = ILE->getType()->getAsCanonical<RecordType>()) if (!RType->getOriginalDecl()->isUnion()) assert((Init < NumInits || VerifyOnly) && "This ILE should have been expanded"); @@ -921,8 +921,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, if (ILE->isTransparent()) return; - if (const RecordType *RType = ILE->getType()->getAs<RecordType>()) { - const RecordDecl *RDecl = RType->getOriginalDecl()->getDefinitionOrSelf(); + if (const auto *RDecl = ILE->getType()->getAsRecordDecl()) { if (RDecl->isUnion() && ILE->getInitializedFieldInUnion()) { FillInEmptyInitForField(0, ILE->getInitializedFieldInUnion(), Entity, ILE, RequiresSecondPass, FillWithNoInit); @@ -1126,8 +1125,7 @@ int InitListChecker::numArrayElements(QualType DeclType) { } int InitListChecker::numStructUnionElements(QualType DeclType) { - RecordDecl *structDecl = - DeclType->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf(); + auto *structDecl = DeclType->castAsRecordDecl(); int InitializableMembers = 0; if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl)) InitializableMembers += CXXRD->getNumBases(); @@ -1156,22 +1154,14 @@ static bool isIdiomaticBraceElisionEntity(const InitializedEntity &Entity) { // Allows elide brace initialization for aggregates with empty base. if (Entity.getKind() == InitializedEntity::EK_Base) { - auto *ParentRD = Entity.getParent() - ->getType() - ->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *ParentRD = Entity.getParent()->getType()->castAsRecordDecl(); CXXRecordDecl *CXXRD = cast<CXXRecordDecl>(ParentRD); return CXXRD->getNumBases() == 1 && CXXRD->field_empty(); } // Allow brace elision if the only subobject is a field. if (Entity.getKind() == InitializedEntity::EK_Member) { - auto *ParentRD = Entity.getParent() - ->getType() - ->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *ParentRD = Entity.getParent()->getType()->castAsRecordDecl(); if (CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(ParentRD)) { if (CXXRD->getNumBases()) { return false; @@ -2348,7 +2338,9 @@ void InitListChecker::CheckStructUnionTypes( Field != FieldEnd; ++Field) { if (Field->hasInClassInitializer() || (Field->isAnonymousStructOrUnion() && - Field->getType()->getAsCXXRecordDecl()->hasInClassInitializer())) { + Field->getType() + ->castAsCXXRecordDecl() + ->hasInClassInitializer())) { StructuredList->setInitializedFieldInUnion(*Field); // FIXME: Actually build a CXXDefaultInitExpr? return; @@ -4535,11 +4527,7 @@ static void TryConstructorInitialization(Sema &S, } } - const RecordType *DestRecordType = DestType->getAs<RecordType>(); - assert(DestRecordType && "Constructor initialization requires record type"); - auto *DestRecordDecl = cast<CXXRecordDecl>(DestRecordType->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *DestRecordDecl = DestType->castAsCXXRecordDecl(); // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. OverloadCandidateSet &CandidateSet = Sequence.getFailedCandidateSet(); @@ -5026,7 +5014,7 @@ static void TryListInitialization(Sema &S, // class type with a default constructor, the object is // value-initialized. if (InitList->getNumInits() == 0) { - CXXRecordDecl *RD = DestType->getAsCXXRecordDecl(); + CXXRecordDecl *RD = DestType->castAsCXXRecordDecl(); if (S.LookupDefaultConstructor(RD)) { TryValueInitialization(S, Entity, Kind, Sequence, InitList); return; @@ -5057,10 +5045,9 @@ static void TryListInitialization(Sema &S, // is direct-list-initialization, the object is initialized with the // value T(v); if a narrowing conversion is required to convert v to // the underlying type of T, the program is ill-formed. - auto *ET = DestType->getAs<EnumType>(); if (S.getLangOpts().CPlusPlus17 && - Kind.getKind() == InitializationKind::IK_DirectList && ET && - ET->getOriginalDecl()->getDefinitionOrSelf()->isFixed() && + Kind.getKind() == InitializationKind::IK_DirectList && + DestType->isEnumeralType() && DestType->castAsEnumDecl()->isFixed() && !S.Context.hasSameUnqualifiedType(E->getType(), DestType) && (E->getType()->isIntegralOrUnscopedEnumerationType() || E->getType()->isFloatingType())) { @@ -5165,14 +5152,13 @@ static OverloadingResult TryRefInitWithConversionFunction( bool AllowExplicitCtors = false; bool AllowExplicitConvs = Kind.allowExplicitConversionFunctionsInRefBinding(); - const RecordType *T1RecordType = nullptr; - if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) && + if (AllowRValues && T1->isRecordType() && S.isCompleteType(Kind.getLocation(), T1)) { + auto *T1RecordDecl = T1->castAsCXXRecordDecl(); + if (T1RecordDecl->isInvalidDecl()) + return OR_No_Viable_Function; // The type we're converting to is a class type. Enumerate its constructors // to see if there is a suitable conversion. - auto *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getOriginalDecl()) - ->getDefinitionOrSelf(); - for (NamedDecl *D : S.LookupConstructors(T1RecordDecl)) { auto Info = getConstructorInfo(D); if (!Info.Constructor) @@ -5194,18 +5180,13 @@ static OverloadingResult TryRefInitWithConversionFunction( } } } - if (T1RecordType && - T1RecordType->getOriginalDecl()->getDefinitionOrSelf()->isInvalidDecl()) - return OR_No_Viable_Function; - const RecordType *T2RecordType = nullptr; - if ((T2RecordType = T2->getAs<RecordType>()) && - S.isCompleteType(Kind.getLocation(), T2)) { + if (T2->isRecordType() && S.isCompleteType(Kind.getLocation(), T2)) { + const auto *T2RecordDecl = T2->castAsCXXRecordDecl(); + if (T2RecordDecl->isInvalidDecl()) + return OR_No_Viable_Function; // The type we're converting from is a class type, enumerate its conversion // functions. - auto *T2RecordDecl = cast<CXXRecordDecl>(T2RecordType->getOriginalDecl()) - ->getDefinitionOrSelf(); - const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions(); for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { NamedDecl *D = *I; @@ -5240,9 +5221,6 @@ static OverloadingResult TryRefInitWithConversionFunction( } } } - if (T2RecordType && - T2RecordType->getOriginalDecl()->getDefinitionOrSelf()->isInvalidDecl()) - return OR_No_Viable_Function; SourceLocation DeclLoc = Initializer->getBeginLoc(); @@ -5718,64 +5696,60 @@ static void TryValueInitialization(Sema &S, // -- if T is an array type, then each element is value-initialized; T = S.Context.getBaseElementType(T); - if (const RecordType *RT = T->getAs<RecordType>()) { - if (CXXRecordDecl *ClassDecl = - dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) { - ClassDecl = ClassDecl->getDefinitionOrSelf(); - bool NeedZeroInitialization = true; - // C++98: - // -- if T is a class type (clause 9) with a user-declared constructor - // (12.1), then the default constructor for T is called (and the - // initialization is ill-formed if T has no accessible default - // constructor); - // C++11: - // -- if T is a class type (clause 9) with either no default constructor - // (12.1 [class.ctor]) or a default constructor that is user-provided - // or deleted, then the object is default-initialized; - // - // Note that the C++11 rule is the same as the C++98 rule if there are no - // defaulted or deleted constructors, so we just use it unconditionally. - CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl); - if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted()) - NeedZeroInitialization = false; - - // -- if T is a (possibly cv-qualified) non-union class type without a - // user-provided or deleted default constructor, then the object is - // zero-initialized and, if T has a non-trivial default constructor, - // default-initialized; - // The 'non-union' here was removed by DR1502. The 'non-trivial default - // constructor' part was removed by DR1507. - if (NeedZeroInitialization) - Sequence.AddZeroInitializationStep(Entity.getType()); - - // C++03: - // -- if T is a non-union class type without a user-declared constructor, - // then every non-static data member and base class component of T is - // value-initialized; - // [...] A program that calls for [...] value-initialization of an - // entity of reference type is ill-formed. - // - // C++11 doesn't need this handling, because value-initialization does not - // occur recursively there, and the implicit default constructor is - // defined as deleted in the problematic cases. - if (!S.getLangOpts().CPlusPlus11 && - ClassDecl->hasUninitializedReferenceMember()) { - Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForReference); - return; - } - - // If this is list-value-initialization, pass the empty init list on when - // building the constructor call. This affects the semantics of a few - // things (such as whether an explicit default constructor can be called). - Expr *InitListAsExpr = InitList; - MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0); - bool InitListSyntax = InitList; + if (auto *ClassDecl = T->getAsCXXRecordDecl()) { + bool NeedZeroInitialization = true; + // C++98: + // -- if T is a class type (clause 9) with a user-declared constructor + // (12.1), then the default constructor for T is called (and the + // initialization is ill-formed if T has no accessible default + // constructor); + // C++11: + // -- if T is a class type (clause 9) with either no default constructor + // (12.1 [class.ctor]) or a default constructor that is user-provided + // or deleted, then the object is default-initialized; + // + // Note that the C++11 rule is the same as the C++98 rule if there are no + // defaulted or deleted constructors, so we just use it unconditionally. + CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl); + if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted()) + NeedZeroInitialization = false; + + // -- if T is a (possibly cv-qualified) non-union class type without a + // user-provided or deleted default constructor, then the object is + // zero-initialized and, if T has a non-trivial default constructor, + // default-initialized; + // The 'non-union' here was removed by DR1502. The 'non-trivial default + // constructor' part was removed by DR1507. + if (NeedZeroInitialization) + Sequence.AddZeroInitializationStep(Entity.getType()); - // FIXME: Instead of creating a CXXConstructExpr of array type here, - // wrap a class-typed CXXConstructExpr in an ArrayInitLoopExpr. - return TryConstructorInitialization( - S, Entity, Kind, Args, T, Entity.getType(), Sequence, InitListSyntax); + // C++03: + // -- if T is a non-union class type without a user-declared constructor, + // then every non-static data member and base class component of T is + // value-initialized; + // [...] A program that calls for [...] value-initialization of an + // entity of reference type is ill-formed. + // + // C++11 doesn't need this handling, because value-initialization does not + // occur recursively there, and the implicit default constructor is + // defined as deleted in the problematic cases. + if (!S.getLangOpts().CPlusPlus11 && + ClassDecl->hasUninitializedReferenceMember()) { + Sequence.SetFailed(InitializationSequence::FK_TooManyInitsForReference); + return; } + + // If this is list-value-initialization, pass the empty init list on when + // building the constructor call. This affects the semantics of a few + // things (such as whether an explicit default constructor can be called). + Expr *InitListAsExpr = InitList; + MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0); + bool InitListSyntax = InitList; + + // FIXME: Instead of creating a CXXConstructExpr of array type here, + // wrap a class-typed CXXConstructExpr in an ArrayInitLoopExpr. + return TryConstructorInitialization( + S, Entity, Kind, Args, T, Entity.getType(), Sequence, InitListSyntax); } Sequence.AddZeroInitializationStep(Entity.getType()); @@ -5917,10 +5891,8 @@ static void TryOrBuildParenListInitialization( AT->getElementType(), llvm::APInt(/*numBits=*/32, ArrayLength), /*SizeExpr=*/nullptr, ArraySizeModifier::Normal, 0); } - } else if (auto *RT = Entity.getType()->getAs<RecordType>()) { - bool IsUnion = RT->isUnionType(); - const auto *RD = - cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(); + } else if (auto *RD = Entity.getType()->getAsCXXRecordDecl()) { + bool IsUnion = RD->isUnion(); if (RD->isInvalidDecl()) { // Exit early to avoid confusion when processing members. // We do the same for braced list initialization in @@ -6106,15 +6078,12 @@ static void TryUserDefinedConversion(Sema &S, // explicit conversion operators. bool AllowExplicit = Kind.AllowExplicit(); - if (const RecordType *DestRecordType = DestType->getAs<RecordType>()) { + if (DestType->isRecordType()) { // The type we're converting to is a class type. Enumerate its constructors // to see if there is a suitable conversion. - auto *DestRecordDecl = - cast<CXXRecordDecl>(DestRecordType->getOriginalDecl()) - ->getDefinitionOrSelf(); - // Try to complete the type we're converting to. if (S.isCompleteType(Kind.getLocation(), DestType)) { + auto *DestRecordDecl = DestType->castAsCXXRecordDecl(); for (NamedDecl *D : S.LookupConstructors(DestRecordDecl)) { auto Info = getConstructorInfo(D); if (!Info.Constructor) @@ -6140,17 +6109,14 @@ static void TryUserDefinedConversion(Sema &S, SourceLocation DeclLoc = Initializer->getBeginLoc(); - if (const RecordType *SourceRecordType = SourceType->getAs<RecordType>()) { + if (SourceType->isRecordType()) { // The type we're converting from is a class type, enumerate its conversion // functions. // We can only enumerate the conversion functions for a complete type; if // the type isn't complete, simply skip this step. if (S.isCompleteType(DeclLoc, SourceType)) { - auto *SourceRecordDecl = - cast<CXXRecordDecl>(SourceRecordType->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *SourceRecordDecl = SourceType->castAsCXXRecordDecl(); const auto &Conversions = SourceRecordDecl->getVisibleConversionFunctions(); for (auto I = Conversions.begin(), E = Conversions.end(); I != E; ++I) { @@ -6237,7 +6203,7 @@ static void TryUserDefinedConversion(Sema &S, Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType, HadMultipleCandidates); - if (ConvType->getAs<RecordType>()) { + if (ConvType->isRecordType()) { // The call is used to direct-initialize [...] the object that is the // destination of the copy-initialization. // @@ -7180,10 +7146,7 @@ static ExprResult CopyObject(Sema &S, return CurInit; // Determine which class type we're copying to. Expr *CurInitExpr = (Expr *)CurInit.get(); - CXXRecordDecl *Class = nullptr; - if (const RecordType *Record = T->getAs<RecordType>()) - Class = - cast<CXXRecordDecl>(Record->getOriginalDecl())->getDefinitionOrSelf(); + auto *Class = T->getAsCXXRecordDecl(); if (!Class) return CurInit; @@ -7328,7 +7291,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, Expr *CurInitExpr) { assert(S.getLangOpts().CPlusPlus11); - const RecordType *Record = CurInitExpr->getType()->getAs<RecordType>(); + auto *Record = CurInitExpr->getType()->getAsCXXRecordDecl(); if (!Record) return; @@ -7338,8 +7301,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, // Find constructors which would have been considered. OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); - DeclContext::lookup_result Ctors = S.LookupConstructors( - cast<CXXRecordDecl>(Record->getOriginalDecl())->getDefinitionOrSelf()); + DeclContext::lookup_result Ctors = S.LookupConstructors(Record); // Perform overload resolution. OverloadCandidateSet::iterator Best; @@ -7803,7 +7765,7 @@ ExprResult InitializationSequence::Perform(Sema &S, DiagID = diag::ext_default_init_const; S.Diag(Kind.getLocation(), DiagID) - << DestType << (bool)DestType->getAs<RecordType>() + << DestType << DestType->isRecordType() << FixItHint::CreateInsertion(ZeroInitializationFixitLoc, ZeroInitializationFixit); } @@ -8169,10 +8131,8 @@ ExprResult InitializationSequence::Perform(Sema &S, // FIXME: It makes no sense to do this here. This should happen // regardless of how we initialized the entity. QualType T = CurInit.get()->getType(); - if (const RecordType *Record = T->getAs<RecordType>()) { - CXXDestructorDecl *Destructor = - S.LookupDestructor(cast<CXXRecordDecl>(Record->getOriginalDecl()) - ->getDefinitionOrSelf()); + if (auto *Record = T->castAsCXXRecordDecl()) { + CXXDestructorDecl *Destructor = S.LookupDestructor(Record); S.CheckDestructorAccess(CurInit.get()->getBeginLoc(), Destructor, S.PDiag(diag::err_access_dtor_temp) << T); S.MarkFunctionReferenced(CurInit.get()->getBeginLoc(), Destructor); @@ -8560,9 +8520,8 @@ ExprResult InitializationSequence::Perform(Sema &S, S.isStdInitializerList(Step->Type, &ElementType); assert(IsStdInitializerList && "StdInitializerList step to non-std::initializer_list"); - const CXXRecordDecl *Record = - Step->Type->getAsCXXRecordDecl()->getDefinition(); - assert(Record && Record->isCompleteDefinition() && + const auto *Record = Step->Type->castAsCXXRecordDecl(); + assert(Record->isCompleteDefinition() && "std::initializer_list should have already be " "complete/instantiated by this point"); @@ -9225,11 +9184,8 @@ bool InitializationSequence::Diagnose(Sema &S, << S.Context.getCanonicalTagType(Constructor->getParent()) << /*base=*/0 << Entity.getType() << InheritedFrom; - RecordDecl *BaseDecl = Entity.getBaseSpecifier() - ->getType() - ->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf(); + auto *BaseDecl = + Entity.getBaseSpecifier()->getType()->castAsRecordDecl(); S.Diag(BaseDecl->getLocation(), diag::note_previous_decl) << S.Context.getCanonicalTagType(BaseDecl); } else { @@ -9242,8 +9198,7 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Entity.getDecl()->getLocation(), diag::note_member_declared_at); - if (const RecordType *Record - = Entity.getType()->getAs<RecordType>()) + if (const auto *Record = Entity.getType()->getAs<RecordType>()) S.Diag(Record->getOriginalDecl()->getLocation(), diag::note_previous_decl) << S.Context.getCanonicalTagType(Record->getOriginalDecl()); @@ -9326,7 +9281,7 @@ bool InitializationSequence::Diagnose(Sema &S, << VD; } else { S.Diag(Kind.getLocation(), diag::err_default_init_const) - << DestType << (bool)DestType->getAs<RecordType>(); + << DestType << DestType->isRecordType(); } break; @@ -10021,7 +9976,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // dependent. e.g. // using AliasFoo = Foo<bool>; if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>( - RT->getAsCXXRecordDecl())) + RT->getOriginalDecl())) Template = CTSD->getSpecializedTemplate(); } } diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 8a81cbe2623d..fbc2e7eb3067 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -641,9 +641,8 @@ static EnumDecl *findEnumForBlockReturn(Expr *E) { } // - it is an expression of that formal enum type. - if (const EnumType *ET = E->getType()->getAs<EnumType>()) { - return ET->getOriginalDecl()->getDefinitionOrSelf(); - } + if (auto *ED = E->getType()->getAsEnumDecl()) + return ED; // Otherwise, nope. return nullptr; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index e28492b57956..54918c560b65 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2770,10 +2770,7 @@ bool Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) { // members of Class itself. That is, the naming class is Class, and the // access includes the access of the base. for (const auto &BaseSpec : Class->bases()) { - CXXRecordDecl *RD = - cast<CXXRecordDecl>( - BaseSpec.getType()->castAs<RecordType>()->getOriginalDecl()) - ->getDefinitionOrSelf(); + auto *RD = BaseSpec.getType()->castAsCXXRecordDecl(); LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind()); Result.setBaseObjectType(Context.getCanonicalTagType(Class)); LookupQualifiedName(Result, RD); @@ -3114,17 +3111,15 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // Visit the base classes. for (const auto &Base : Class->bases()) { - const RecordType *BaseType = Base.getType()->getAs<RecordType>(); + CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); // In dependent contexts, we do ADL twice, and the first time around, // the base type might be a dependent TemplateSpecializationType, or a // TemplateTypeParmType. If that happens, simply ignore it. // FIXME: If we want to support export, we probably need to add the // namespace of the template in a TemplateSpecializationType, or even // the classes and namespaces of known non-dependent arguments. - if (!BaseType) + if (!BaseDecl) continue; - CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getOriginalDecl()) - ->getDefinitionOrSelf(); if (Result.addClassTransitive(BaseDecl)) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); @@ -3209,8 +3204,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // member’s class; else it has no associated class. case Type::Enum: { // FIXME: This should use the original decl. - EnumDecl *Enum = - cast<EnumType>(T)->getOriginalDecl()->getDefinitionOrSelf(); + auto *Enum = T->castAsEnumDecl(); DeclContext *Ctx = Enum->getDeclContext(); if (CXXRecordDecl *EnclosingClass = dyn_cast<CXXRecordDecl>(Ctx)) @@ -4262,10 +4256,9 @@ private: continue; RD = TD->getTemplatedDecl(); } else { - const auto *Record = BaseType->getAs<RecordType>(); - if (!Record) + RD = BaseType->getAsCXXRecordDecl(); + if (!RD) continue; - RD = Record->getOriginalDecl()->getDefinitionOrSelf(); } // FIXME: It would be nice to be able to determine whether referencing @@ -4460,26 +4453,28 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, H.lookupVisibleDecls(*this, Ctx, Kind, IncludeGlobalScope); } +LabelDecl *Sema::LookupExistingLabel(IdentifierInfo *II, SourceLocation Loc) { + NamedDecl *Res = LookupSingleName(CurScope, II, Loc, LookupLabel, + RedeclarationKind::NotForRedeclaration); + // If we found a label, check to see if it is in the same context as us. + // When in a Block, we don't want to reuse a label in an enclosing function. + if (!Res || Res->getDeclContext() != CurContext) + return nullptr; + return cast<LabelDecl>(Res); +} + LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, SourceLocation GnuLabelLoc) { - // Do a lookup to see if we have a label with this name already. - NamedDecl *Res = nullptr; - if (GnuLabelLoc.isValid()) { // Local label definitions always shadow existing labels. - Res = LabelDecl::Create(Context, CurContext, Loc, II, GnuLabelLoc); + auto *Res = LabelDecl::Create(Context, CurContext, Loc, II, GnuLabelLoc); Scope *S = CurScope; PushOnScopeChains(Res, S, true); return cast<LabelDecl>(Res); } // Not a GNU local label. - Res = LookupSingleName(CurScope, II, Loc, LookupLabel, - RedeclarationKind::NotForRedeclaration); - // If we found a label, check to see if it is in the same context as us. - // When in a Block, we don't want to reuse a label in an enclosing function. - if (Res && Res->getDeclContext() != CurContext) - Res = nullptr; + LabelDecl *Res = LookupExistingLabel(II, Loc); if (!Res) { // If not forward referenced or defined already, create the backing decl. Res = LabelDecl::Create(Context, CurContext, Loc, II); @@ -4487,7 +4482,7 @@ LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, assert(S && "Not in a function?"); PushOnScopeChains(Res, S, true); } - return cast<LabelDecl>(Res); + return Res; } //===----------------------------------------------------------------------===// @@ -4581,7 +4576,7 @@ static void getNestedNameSpecifierIdentifiers( TemplateName Name = cast<TemplateSpecializationType>(T)->getTemplateName(); if (const QualifiedTemplateName *QTN = - Name.getAsAdjustedQualifiedTemplateName()) { + Name.getAsQualifiedTemplateName()) { getNestedNameSpecifierIdentifiers(QTN->getQualifier(), Identifiers); Name = QTN->getUnderlyingTemplate(); } diff --git a/clang/lib/Sema/SemaObjC.cpp b/clang/lib/Sema/SemaObjC.cpp index 8d8d5e87afe7..4f9470a361d2 100644 --- a/clang/lib/Sema/SemaObjC.cpp +++ b/clang/lib/Sema/SemaObjC.cpp @@ -1380,7 +1380,7 @@ SemaObjC::ObjCSubscriptKind SemaObjC::CheckSubscriptingKind(Expr *FromE) { // If we don't have a class type in C++, there's no way we can get an // expression of integral or enumeration type. - const RecordType *RecordTy = T->getAs<RecordType>(); + const RecordType *RecordTy = T->getAsCanonical<RecordType>(); if (!RecordTy && (T->isObjCObjectPointerType() || T->isVoidPointerType())) // All other scalar cases are assumed to be dictionary indexing which // caller handles, with diagnostics if needed. @@ -1507,7 +1507,7 @@ bool SemaObjC::isCFStringType(QualType T) { if (!PT) return false; - const auto *RT = PT->getPointeeType()->getAs<RecordType>(); + const auto *RT = PT->getPointeeType()->getAsCanonical<RecordType>(); if (!RT) return false; diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index bf6c364e40cc..1880cec6ec8e 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1320,10 +1320,8 @@ Decl *SemaObjC::ActOnPropertyImplDecl( CompleteTypeErr = true; } if (!CompleteTypeErr) { - const RecordType *RecordTy = PropertyIvarType->getAs<RecordType>(); - if (RecordTy && RecordTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) { + if (const auto *RD = PropertyIvarType->getAsRecordDecl(); + RD && RD->hasFlexibleArrayMember()) { Diag(PropertyIvarLoc, diag::err_synthesize_variable_sized_ivar) << PropertyIvarType; CompleteTypeErr = true; // suppress later diagnostics about the ivar diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 145752240653..fbd8022cd68b 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -1020,8 +1020,8 @@ ExprResult SemaOpenACC::ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc, // If any part of the expression is dependent, return a dependent sub-array. QualType ArrayExprTy = Context.ArraySectionTy; if (Base->isTypeDependent() || - (LowerBound && LowerBound->isInstantiationDependent()) || - (Length && Length->isInstantiationDependent())) + (LowerBound && LowerBound->isTypeDependent()) || + (Length && Length->isTypeDependent())) ArrayExprTy = Context.DependentTy; return new (Context) @@ -2589,149 +2589,337 @@ SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) { return BuildOpenACCAsteriskSizeExpr(AsteriskLoc); } -std::pair<VarDecl *, VarDecl *> -SemaOpenACC::CreateInitRecipe(OpenACCClauseKind CK, const Expr *VarExpr) { - // Strip off any array subscripts/array section exprs to get to the type of - // the variable. +namespace { +enum class InitKind { Invalid, Zero, One, AllOnes, Least, Largest }; +llvm::APFloat getInitFloatValue(ASTContext &Context, InitKind IK, QualType Ty) { + switch (IK) { + case InitKind::Invalid: + llvm_unreachable("invalid init kind"); + case InitKind::Zero: + return llvm::APFloat::getZero(Context.getFloatTypeSemantics(Ty)); + case InitKind::One: + return llvm::APFloat::getOne(Context.getFloatTypeSemantics(Ty)); + case InitKind::AllOnes: + return llvm::APFloat::getAllOnesValue(Context.getFloatTypeSemantics(Ty)); + case InitKind::Least: + return llvm::APFloat::getLargest(Context.getFloatTypeSemantics(Ty), + /*Negative=*/true); + case InitKind::Largest: + return llvm::APFloat::getLargest(Context.getFloatTypeSemantics(Ty)); + } + llvm_unreachable("unknown init kind"); +} + +llvm::APInt getInitIntValue(ASTContext &Context, InitKind IK, QualType Ty) { + switch (IK) { + case InitKind::Invalid: + llvm_unreachable("invalid init kind"); + case InitKind::Zero: + return llvm::APInt(Context.getIntWidth(Ty), 0); + case InitKind::One: + return llvm::APInt(Context.getIntWidth(Ty), 1); + case InitKind::AllOnes: + return llvm::APInt::getAllOnes(Context.getIntWidth(Ty)); + case InitKind::Least: + if (Ty->isSignedIntegerOrEnumerationType()) + return llvm::APInt::getSignedMinValue(Context.getIntWidth(Ty)); + return llvm::APInt::getMinValue(Context.getIntWidth(Ty)); + case InitKind::Largest: + if (Ty->isSignedIntegerOrEnumerationType()) + return llvm::APInt::getSignedMaxValue(Context.getIntWidth(Ty)); + return llvm::APInt::getMaxValue(Context.getIntWidth(Ty)); + } + llvm_unreachable("unknown init kind"); +} + +/// Loops through a type and generates an appropriate InitListExpr to +/// generate type initialization. +Expr *GenerateReductionInitRecipeExpr(ASTContext &Context, + SourceRange ExprRange, QualType Ty, + InitKind IK) { + if (IK == InitKind::Invalid) + return nullptr; + + if (IK == InitKind::Zero) { + Expr *InitExpr = new (Context) + InitListExpr(Context, ExprRange.getBegin(), {}, ExprRange.getEnd()); + InitExpr->setType(Context.VoidTy); + return InitExpr; + } + + Ty = Ty.getCanonicalType(); + llvm::SmallVector<Expr *> Exprs; + + if (const RecordDecl *RD = Ty->getAsRecordDecl()) { + for (auto *F : RD->fields()) { + if (Expr *NewExpr = GenerateReductionInitRecipeExpr(Context, ExprRange, + F->getType(), IK)) + Exprs.push_back(NewExpr); + else + return nullptr; + } + } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { + for (uint64_t Idx = 0; Idx < AT->getZExtSize(); ++Idx) { + if (Expr *NewExpr = GenerateReductionInitRecipeExpr( + Context, ExprRange, AT->getElementType(), IK)) + Exprs.push_back(NewExpr); + else + return nullptr; + } + + } else if (Ty->isPointerType()) { + // For now, we are going to punt/not initialize pointer types, as + // discussions/designs are ongoing on how to express this behavior, + // particularly since they probably need the 'bounds' passed to them + // correctly. A future patch/patch set will go through all of the pointer + // values for all of the recipes to make sure we have a sane behavior. + + // For now, this will result in a NYI during code generation for + // no-initializer. + return nullptr; + } else { + assert(Ty->isScalarType()); + + if (const auto *Cplx = Ty->getAs<ComplexType>()) { + // we can get here in error cases, so make sure we generate something that + // will work if we find ourselves wanting to enable this, so emit '0,0' + // for both ints and floats. + + QualType EltTy = Cplx->getElementType(); + if (EltTy->isFloatingType()) { + Exprs.push_back(FloatingLiteral::Create( + Context, getInitFloatValue(Context, InitKind::Zero, EltTy), + /*isExact=*/true, EltTy, ExprRange.getBegin())); + Exprs.push_back(FloatingLiteral::Create( + Context, getInitFloatValue(Context, InitKind::Zero, EltTy), + /*isExact=*/true, EltTy, ExprRange.getBegin())); + } else { + Exprs.push_back(IntegerLiteral::Create( + Context, getInitIntValue(Context, InitKind::Zero, EltTy), EltTy, + ExprRange.getBegin())); + Exprs.push_back(IntegerLiteral::Create( + Context, getInitIntValue(Context, InitKind::Zero, EltTy), EltTy, + ExprRange.getBegin())); + } + + } else if (Ty->isFloatingType()) { + Exprs.push_back( + FloatingLiteral::Create(Context, getInitFloatValue(Context, IK, Ty), + /*isExact=*/true, Ty, ExprRange.getBegin())); + } else if (Ty->isBooleanType()) { + Exprs.push_back(CXXBoolLiteralExpr::Create(Context, + (IK == InitKind::One || + IK == InitKind::AllOnes || + IK == InitKind::Largest), + Ty, ExprRange.getBegin())); + } else { + Exprs.push_back(IntegerLiteral::Create( + Context, getInitIntValue(Context, IK, Ty), Ty, ExprRange.getBegin())); + } + } + + Expr *InitExpr = new (Context) + InitListExpr(Context, ExprRange.getBegin(), Exprs, ExprRange.getEnd()); + InitExpr->setType(Ty); + return InitExpr; +} + +const Expr *StripOffBounds(const Expr *VarExpr) { while (isa_and_present<ArraySectionExpr, ArraySubscriptExpr>(VarExpr)) { if (const auto *AS = dyn_cast<ArraySectionExpr>(VarExpr)) VarExpr = AS->getBase()->IgnoreParenImpCasts(); else if (const auto *Sub = dyn_cast<ArraySubscriptExpr>(VarExpr)) VarExpr = Sub->getBase()->IgnoreParenImpCasts(); } + return VarExpr; +} + +VarDecl *CreateAllocaDecl(ASTContext &Ctx, DeclContext *DC, + SourceLocation BeginLoc, IdentifierInfo *VarName, + QualType VarTy) { + return VarDecl::Create(Ctx, DC, BeginLoc, BeginLoc, VarName, VarTy, + Ctx.getTrivialTypeSourceInfo(VarTy), SC_Auto); +} + +ExprResult FinishValueInit(Sema &S, InitializedEntity &Entity, + SourceLocation Loc, QualType VarTy, Expr *InitExpr) { + if (!InitExpr) + return ExprEmpty(); + + InitializationKind Kind = + InitializationKind::CreateForInit(Loc, /*DirectInit=*/true, InitExpr); + InitializationSequence InitSeq(S, Entity, Kind, InitExpr, + /*TopLevelOfInitList=*/false, + /*TreatUnavailableAsInvalid=*/false); + + return InitSeq.Perform(S, Entity, Kind, InitExpr, &VarTy); +} + +} // namespace + +OpenACCPrivateRecipe SemaOpenACC::CreatePrivateInitRecipe(const Expr *VarExpr) { + VarExpr = StripOffBounds(VarExpr); - // If for some reason the expression is invalid, or this is dependent, just - // fill in with nullptr. We'll count on TreeTransform to make this if - // necessary. if (!VarExpr || VarExpr->getType()->isDependentType()) - return {nullptr, nullptr}; + return OpenACCPrivateRecipe::Empty(); QualType VarTy = VarExpr->getType().getNonReferenceType().getUnqualifiedType(); - IdentifierInfo *VarName = [&]() { - switch (CK) { - case OpenACCClauseKind::Private: - return &getASTContext().Idents.get("openacc.private.init"); - case OpenACCClauseKind::FirstPrivate: - return &getASTContext().Idents.get("openacc.firstprivate.init"); - case OpenACCClauseKind::Reduction: - return &getASTContext().Idents.get("openacc.reduction.init"); - default: - llvm_unreachable("Unknown clause kind?"); - } - }(); + // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a + // different initializer, but for now we can go ahead with this. - VarDecl *Recipe = VarDecl::Create( + VarDecl *AllocaDecl = CreateAllocaDecl( getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), - VarExpr->getBeginLoc(), VarName, VarTy, - getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto); - - ExprResult Init; - VarDecl *Temporary = nullptr; - { - // Trap errors so we don't get weird ones here. If we can't init, we'll just - // swallow the errors. - Sema::TentativeAnalysisScope Trap{SemaRef}; - InitializedEntity Entity = InitializedEntity::InitializeVariable(Recipe); - - if (CK == OpenACCClauseKind::Private) { - InitializationKind Kind = - InitializationKind::CreateDefault(Recipe->getLocation()); - - InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {}); - Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {}); - - } else if (CK == OpenACCClauseKind::FirstPrivate) { - // Create a VarDecl to be the 'copied-from' for the copy section of the - // recipe. This allows us to make the association so that we can use the - // standard 'generation' ability of the init. - Temporary = VarDecl::Create( - getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), - VarExpr->getBeginLoc(), &getASTContext().Idents.get("openacc.temp"), - VarTy, getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto); - auto *TemporaryDRE = DeclRefExpr::Create( - getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, - Temporary, - /*ReferstoEnclosingVariableOrCapture=*/false, - DeclarationNameInfo{DeclarationName{Temporary->getDeclName()}, - VarExpr->getBeginLoc()}, - VarTy, clang::VK_LValue, Temporary, nullptr, NOUR_None); - - Expr *InitExpr = nullptr; - - if (const auto *ArrTy = getASTContext().getAsConstantArrayType(VarTy)) { - // Arrays need to have each individual element initialized as there - // isn't a normal 'equals' feature in C/C++. This section sets these up - // as an init list after 'initializing' each individual element. - llvm::SmallVector<Expr *> Args; - - // Decay to pointer for the array subscript expression. - auto *CastToPtr = ImplicitCastExpr::Create( - getASTContext(), - getASTContext().getPointerType(ArrTy->getElementType()), - CK_ArrayToPointerDecay, TemporaryDRE, /*BasePath=*/nullptr, - clang::VK_LValue, FPOptionsOverride{}); - - for (std::size_t I = 0; I < ArrTy->getLimitedSize(); ++I) { - // Each element needs to be some sort of copy initialization from an - // array-index of the original temporary (referenced via a - // DeclRefExpr). - - auto *Idx = IntegerLiteral::Create( - getASTContext(), - llvm::APInt( - getASTContext().getTypeSize(getASTContext().getSizeType()), - I), - getASTContext().getSizeType(), VarExpr->getBeginLoc()); - - Expr *Subscript = new (getASTContext()) ArraySubscriptExpr( - CastToPtr, Idx, ArrTy->getElementType(), clang::VK_LValue, - OK_Ordinary, VarExpr->getBeginLoc()); - - // Generate a simple copy from the result of the subscript. This will - // do a bitwise copy or a copy-constructor, as necessary. - InitializedEntity CopyEntity = - InitializedEntity::InitializeElement(getASTContext(), I, Entity); - InitializationKind CopyKind = - InitializationKind::CreateCopy(VarExpr->getBeginLoc(), {}); - InitializationSequence CopySeq(SemaRef.SemaRef, CopyEntity, CopyKind, - Subscript, - /*TopLevelOfInitList=*/true); - - ExprResult ElemRes = - CopySeq.Perform(SemaRef.SemaRef, CopyEntity, CopyKind, Subscript); - Args.push_back(ElemRes.get()); - } + &getASTContext().Idents.get("openacc.private.init"), VarTy); - InitExpr = new (getASTContext()) - InitListExpr(getASTContext(), VarExpr->getBeginLoc(), Args, - VarExpr->getEndLoc()); - InitExpr->setType(VarTy); + Sema::TentativeAnalysisScope Trap{SemaRef}; + InitializedEntity Entity = InitializedEntity::InitializeVariable(AllocaDecl); + InitializationKind Kind = + InitializationKind::CreateDefault(AllocaDecl->getLocation()); + InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {}); + ExprResult Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {}); - } else { - // If this isn't an array, we can just do normal copy init from a simple - // variable reference, so set that up. - InitExpr = TemporaryDRE; - } + return OpenACCPrivateRecipe(AllocaDecl, Init.get()); +} - InitializationKind Kind = InitializationKind::CreateForInit( - Recipe->getLocation(), /*DirectInit=*/true, InitExpr); - InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, InitExpr, - /*TopLevelOfInitList=*/false, - /*TreatUnavailableAsInvalid=*/false); - Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, InitExpr, &VarTy); - } else if (CK == OpenACCClauseKind::Reduction) { - // TODO: OpenACC: Implement this for whatever reduction needs. - } else { - llvm_unreachable("Unknown clause kind in CreateInitRecipe"); - } - } +OpenACCFirstPrivateRecipe +SemaOpenACC::CreateFirstPrivateInitRecipe(const Expr *VarExpr) { + VarExpr = StripOffBounds(VarExpr); + + if (!VarExpr || VarExpr->getType()->isDependentType()) + return OpenACCFirstPrivateRecipe::Empty(); + + QualType VarTy = + VarExpr->getType().getNonReferenceType().getUnqualifiedType(); + + // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a + // different initializer, but for now we can go ahead with this. + + VarDecl *AllocaDecl = CreateAllocaDecl( + getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), + &getASTContext().Idents.get("openacc.firstprivate.init"), VarTy); - if (Init.get()) { - Recipe->setInit(Init.get()); - Recipe->setInitStyle(VarDecl::CallInit); + VarDecl *Temporary = CreateAllocaDecl( + getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), + &getASTContext().Idents.get("openacc.temp"), VarTy); + + auto *TemporaryDRE = DeclRefExpr::Create( + getASTContext(), NestedNameSpecifierLoc{}, SourceLocation{}, Temporary, + /*ReferstoEnclosingVariableOrCapture=*/false, + DeclarationNameInfo{DeclarationName{Temporary->getDeclName()}, + VarExpr->getBeginLoc()}, + VarTy, clang::VK_LValue, Temporary, nullptr, NOUR_None); + + Sema::TentativeAnalysisScope Trap{SemaRef}; + InitializedEntity Entity = InitializedEntity::InitializeVariable(AllocaDecl); + + const auto *ArrTy = getASTContext().getAsConstantArrayType(VarTy); + if (!ArrTy) { + ExprResult Init = FinishValueInit( + SemaRef.SemaRef, Entity, VarExpr->getBeginLoc(), VarTy, TemporaryDRE); + return OpenACCFirstPrivateRecipe(AllocaDecl, Init.get(), Temporary); + } + + // Arrays need to have each individual element initialized as there + // isn't a normal 'equals' feature in C/C++. This section sets these up + // as an init list after 'initializing' each individual element. + llvm::SmallVector<Expr *> Args; + // Decay to pointer for the array subscript expression. + auto *CastToPtr = ImplicitCastExpr::Create( + getASTContext(), getASTContext().getPointerType(ArrTy->getElementType()), + CK_ArrayToPointerDecay, TemporaryDRE, /*BasePath=*/nullptr, + clang::VK_LValue, FPOptionsOverride{}); + + for (std::size_t I = 0; I < ArrTy->getLimitedSize(); ++I) { + // Each element needs to be some sort of copy initialization from an + // array-index of the original temporary (referenced via a + // DeclRefExpr). + auto *Idx = IntegerLiteral::Create( + getASTContext(), + llvm::APInt(getASTContext().getTypeSize(getASTContext().getSizeType()), + I), + getASTContext().getSizeType(), VarExpr->getBeginLoc()); + + Expr *Subscript = new (getASTContext()) ArraySubscriptExpr( + CastToPtr, Idx, ArrTy->getElementType(), clang::VK_LValue, OK_Ordinary, + VarExpr->getBeginLoc()); + // Generate a simple copy from the result of the subscript. This will + // do a bitwise copy or a copy-constructor, as necessary. + InitializedEntity CopyEntity = + InitializedEntity::InitializeElement(getASTContext(), I, Entity); + InitializationKind CopyKind = + InitializationKind::CreateCopy(VarExpr->getBeginLoc(), {}); + InitializationSequence CopySeq(SemaRef.SemaRef, CopyEntity, CopyKind, + Subscript, + /*TopLevelOfInitList=*/true); + ExprResult ElemRes = + CopySeq.Perform(SemaRef.SemaRef, CopyEntity, CopyKind, Subscript); + Args.push_back(ElemRes.get()); + } + + Expr *InitExpr = new (getASTContext()) InitListExpr( + getASTContext(), VarExpr->getBeginLoc(), Args, VarExpr->getEndLoc()); + InitExpr->setType(VarTy); + + ExprResult Init = FinishValueInit(SemaRef.SemaRef, Entity, + VarExpr->getBeginLoc(), VarTy, InitExpr); + + return OpenACCFirstPrivateRecipe(AllocaDecl, Init.get(), Temporary); +} +OpenACCReductionRecipe SemaOpenACC::CreateReductionInitRecipe( + OpenACCReductionOperator ReductionOperator, const Expr *VarExpr) { + VarExpr = StripOffBounds(VarExpr); + + if (!VarExpr || VarExpr->getType()->isDependentType()) + return OpenACCReductionRecipe::Empty(); + + QualType VarTy = + VarExpr->getType().getNonReferenceType().getUnqualifiedType(); + + // TODO: OpenACC: for arrays/bounds versions, we're going to have to do a + // different initializer, but for now we can go ahead with this. + + VarDecl *AllocaDecl = CreateAllocaDecl( + getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), + &getASTContext().Idents.get("openacc.reduction.init"), VarTy); + + Sema::TentativeAnalysisScope Trap{SemaRef}; + InitializedEntity Entity = InitializedEntity::InitializeVariable(AllocaDecl); + + InitKind IK = InitKind::Invalid; + switch (ReductionOperator) { + case OpenACCReductionOperator::Invalid: + // This can only happen when there is an error, and since these inits + // are used for code generation, we can just ignore/not bother doing any + // initialization here. + IK = InitKind::Invalid; + break; + case OpenACCReductionOperator::Max: + IK = InitKind::Least; + break; + case OpenACCReductionOperator::Min: + IK = InitKind::Largest; + break; + case OpenACCReductionOperator::BitwiseAnd: + IK = InitKind::AllOnes; + break; + case OpenACCReductionOperator::Multiplication: + case OpenACCReductionOperator::And: + IK = InitKind::One; + break; + case OpenACCReductionOperator::Addition: + case OpenACCReductionOperator::BitwiseOr: + case OpenACCReductionOperator::BitwiseXOr: + case OpenACCReductionOperator::Or: + IK = InitKind::Zero; + break; } - return {Recipe, Temporary}; + Expr *InitExpr = GenerateReductionInitRecipeExpr( + getASTContext(), VarExpr->getSourceRange(), VarTy, IK); + + ExprResult Init = FinishValueInit(SemaRef.SemaRef, Entity, + VarExpr->getBeginLoc(), VarTy, InitExpr); + return OpenACCReductionRecipe(AllocaDecl, Init.get()); } diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp index 43ae4f4d3011..b0869293c166 100644 --- a/clang/lib/Sema/SemaOpenACCClause.cpp +++ b/clang/lib/Sema/SemaOpenACCClause.cpp @@ -795,12 +795,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitPrivateClause( // really isn't anything to do here. GCC does some duplicate-finding, though // it isn't apparent in the standard where this is justified. - llvm::SmallVector<VarDecl *> InitRecipes; + llvm::SmallVector<OpenACCPrivateRecipe> InitRecipes; // Assemble the recipes list. for (const Expr *VarExpr : Clause.getVarList()) - InitRecipes.push_back( - SemaRef.CreateInitRecipe(OpenACCClauseKind::Private, VarExpr).first); + InitRecipes.push_back(SemaRef.CreatePrivateInitRecipe(VarExpr)); return OpenACCPrivateClause::Create( Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), @@ -817,8 +816,7 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause( // Assemble the recipes list. for (const Expr *VarExpr : Clause.getVarList()) - InitRecipes.push_back( - SemaRef.CreateInitRecipe(OpenACCClauseKind::FirstPrivate, VarExpr)); + InitRecipes.push_back(SemaRef.CreateFirstPrivateInitRecipe(VarExpr)); return OpenACCFirstPrivateClause::Create( Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), @@ -1783,11 +1781,8 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause( if (Res.isUsable()) { ValidVars.push_back(Res.get()); - VarDecl *InitRecipe = - SemaRef.CreateInitRecipe(OpenACCClauseKind::Reduction, Res.get()) - .first; - // TODO: OpenACC: Create the reduction operation recipe here too. - Recipes.push_back({InitRecipe}); + Recipes.push_back(SemaRef.CreateReductionInitRecipe( + Clause.getReductionOp(), Res.get())); } } @@ -1968,7 +1963,9 @@ ExprResult SemaOpenACC::CheckReductionVar(OpenACCDirectiveKind DirectiveKind, } auto IsValidMemberOfComposite = [](QualType Ty) { - return Ty->isDependentType() || Ty->isScalarType(); + return !Ty->isAnyComplexType() && + (Ty->isDependentType() || + (Ty->isScalarType() && !Ty->isPointerType())); }; auto EmitDiags = [&](SourceLocation Loc, PartialDiagnostic PD) { diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 7d800c446b59..63a56a6583ef 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaOpenMP.h" +#include "clang/AST/ASTConsumer.h" #include "TreeTransform.h" #include "clang/AST/ASTContext.h" @@ -2780,7 +2781,7 @@ void SemaOpenMP::EndOpenMPClause() { static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, SourceRange &ERange, bool AllowArraySection = false, - StringRef DiagType = ""); + bool AllowAssumedSizeArray = false, StringRef DiagType = ""); /// Check consistency of the reduction clauses. static void checkReductionClauses(Sema &S, DSAStackTy *Stack, @@ -4145,7 +4146,8 @@ public: VisitSubCaptures(S); } - void VisitOMPLoopTransformationDirective(OMPLoopTransformationDirective *S) { + void VisitOMPCanonicalLoopNestTransformationDirective( + OMPCanonicalLoopNestTransformationDirective *S) { // Loop transformation directives do not introduce data sharing VisitStmt(S); } @@ -5148,11 +5150,10 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, return ErrorFound; } -static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, - SourceLocation &ELoc, - SourceRange &ERange, - bool AllowArraySection, - StringRef DiagType) { +static std::pair<ValueDecl *, bool> +getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, + SourceRange &ERange, bool AllowArraySection, + bool AllowAssumedSizeArray, StringRef DiagType) { if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || RefExpr->containsUnexpandedParameterPack()) return std::make_pair(nullptr, true); @@ -5162,6 +5163,20 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, // OpenMP [2.9.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. + // + // OpenMP [6.0] + // 5.2.5 Array Sections, p. 166, L28-29 + // When the length is absent and the size of the dimension is not known, + // the array section is an assumed-size array. + // 2 Glossary, p. 23, L4-6 + // assumed-size array + // For C/C++, an array section for which the length is absent and the + // size of the dimensions is not known. + // 5.2.5 Array Sections, p. 168, L11 + // An assumed-size array can appear only in clauses for which it is + // explicitly allowed. + // 7.4 List Item Privatization, Restrictions, p. 222, L15 + // Assumed-size arrays must not be privatized. RefExpr = RefExpr->IgnoreParens(); enum { NoArrayExpr = -1, @@ -5177,6 +5192,17 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, IsArrayExpr = ArraySubscript; } else if (auto *OASE = dyn_cast_or_null<ArraySectionExpr>(RefExpr)) { Expr *Base = OASE->getBase()->IgnoreParenImpCasts(); + if (S.getLangOpts().OpenMP >= 60 && !AllowAssumedSizeArray && + OASE->getColonLocFirst().isValid() && !OASE->getLength()) { + QualType BaseType = ArraySectionExpr::getBaseOriginalType(Base); + if (BaseType.isNull() || (!BaseType->isConstantArrayType() && + !BaseType->isVariableArrayType())) { + S.Diag(OASE->getColonLocFirst(), + diag::err_omp_section_length_undefined) + << (!BaseType.isNull() && BaseType->isArrayType()); + return std::make_pair(nullptr, false); + } + } while (auto *TempOASE = dyn_cast<ArraySectionExpr>(Base)) Base = TempOASE->getBase()->IgnoreParenImpCasts(); while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) @@ -9748,7 +9774,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } return false; }, - [&SemaRef, &Captures](OMPLoopTransformationDirective *Transform) { + [&SemaRef, + &Captures](OMPCanonicalLoopNestTransformationDirective *Transform) { Stmt *DependentPreInits = Transform->getPreInits(); if (!DependentPreInits) return; @@ -11097,22 +11124,27 @@ StmtResult SemaOpenMP::ActOnOpenMPErrorDirective(ArrayRef<OMPClause *> Clauses, return StmtError(); } - const OMPSeverityClause *SeverityC = - OMPExecutableDirective::getSingleClause<OMPSeverityClause>(Clauses); - const OMPMessageClause *MessageC = - OMPExecutableDirective::getSingleClause<OMPMessageClause>(Clauses); - Expr *ME = MessageC ? MessageC->getMessageString() : nullptr; - if (!AtC || AtC->getAtKind() == OMPC_AT_compilation) { + const OMPSeverityClause *SeverityC = + OMPExecutableDirective::getSingleClause<OMPSeverityClause>(Clauses); + const OMPMessageClause *MessageC = + OMPExecutableDirective::getSingleClause<OMPMessageClause>(Clauses); + std::optional<std::string> SL = + MessageC ? MessageC->tryEvaluateString(getASTContext()) : std::nullopt; + + if (MessageC && !SL) + Diag(MessageC->getMessageString()->getBeginLoc(), + diag::warn_clause_expected_string) + << getOpenMPClauseNameForDiag(OMPC_message) << 1; if (SeverityC && SeverityC->getSeverityKind() == OMPC_SEVERITY_warning) Diag(SeverityC->getSeverityKindKwLoc(), diag::warn_diagnose_if_succeeded) - << (ME ? cast<StringLiteral>(ME)->getString() : "WARNING"); + << SL.value_or("WARNING"); else - Diag(StartLoc, diag::err_diagnose_if_succeeded) - << (ME ? cast<StringLiteral>(ME)->getString() : "ERROR"); + Diag(StartLoc, diag::err_diagnose_if_succeeded) << SL.value_or("ERROR"); if (!SeverityC || SeverityC->getSeverityKind() != OMPC_SEVERITY_warning) return StmtError(); } + return OMPErrorDirective::Create(getASTContext(), StartLoc, EndLoc, Clauses); } @@ -16464,13 +16496,36 @@ OMPClause *SemaOpenMP::ActOnOpenMPMessageClause(Expr *ME, SourceLocation LParenLoc, SourceLocation EndLoc) { assert(ME && "NULL expr in Message clause"); - if (!isa<StringLiteral>(ME)) { + QualType Type = ME->getType(); + if ((!Type->isPointerType() && !Type->isArrayType()) || + !Type->getPointeeOrArrayElementType()->isAnyCharacterType()) { Diag(ME->getBeginLoc(), diag::warn_clause_expected_string) - << getOpenMPClauseNameForDiag(OMPC_message); + << getOpenMPClauseNameForDiag(OMPC_message) << 0; return nullptr; } - return new (getASTContext()) - OMPMessageClause(ME, StartLoc, LParenLoc, EndLoc); + + Stmt *HelperValStmt = nullptr; + + // Depending on whether this clause appears in an executable context or not, + // we may or may not build a capture. + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + OpenMPDirectiveKind CaptureRegion = + DKind == OMPD_unknown ? OMPD_unknown + : getOpenMPCaptureRegionForClause( + DKind, OMPC_message, getLangOpts().OpenMP); + if (CaptureRegion != OMPD_unknown && + !SemaRef.CurContext->isDependentContext()) { + ME = SemaRef.MakeFullExpr(ME).get(); + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; + ME = tryBuildCapture(SemaRef, ME, Captures).get(); + HelperValStmt = buildPreInits(getASTContext(), Captures); + } + + // Convert array type to pointer type if needed. + ME = SemaRef.DefaultFunctionArrayLvalueConversion(ME).get(); + + return new (getASTContext()) OMPMessageClause( + ME, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc); } OMPClause *SemaOpenMP::ActOnOpenMPOrderClause( @@ -17296,9 +17351,10 @@ static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr, SourceLocation ELoc; SourceRange ERange; Expr *RefExpr = InteropVarExpr; - auto Res = - getPrivateItem(SemaRef, RefExpr, ELoc, ERange, - /*AllowArraySection=*/false, /*DiagType=*/"omp_interop_t"); + auto Res = getPrivateItem(SemaRef, RefExpr, ELoc, ERange, + /*AllowArraySection=*/false, + /*AllowAssumedSizeArray=*/false, + /*DiagType=*/"omp_interop_t"); if (Res.second) { // It will be analyzed later. @@ -18628,12 +18684,12 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, // the set of member candidates is empty. LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName); Lookup.suppressDiagnostics(); - if (const auto *TyRec = Ty->getAs<RecordType>()) { + if (Ty->isRecordType()) { // Complete the type if it can be completed. // If the type is neither complete nor being defined, bail out now. bool IsComplete = SemaRef.isCompleteType(Loc, Ty); - RecordDecl *RD = TyRec->getOriginalDecl()->getDefinition(); - if (IsComplete || RD) { + auto *RD = Ty->castAsRecordDecl(); + if (IsComplete || RD->isBeingDefined()) { Lookup.clear(); SemaRef.LookupQualifiedName(Lookup, RD); if (Lookup.empty()) { @@ -22594,8 +22650,16 @@ ExprResult SemaOpenMP::ActOnOpenMPDeclareMapperDirectiveVarDecl( } void SemaOpenMP::ActOnOpenMPIteratorVarDecl(VarDecl *VD) { - if (DSAStack->getDeclareMapperVarRef()) + bool IsGlobalVar = + !VD->isLocalVarDecl() && VD->getDeclContext()->isTranslationUnit(); + if (DSAStack->getDeclareMapperVarRef()) { + if (IsGlobalVar) + SemaRef.Consumer.HandleTopLevelDecl(DeclGroupRef(VD)); DSAStack->addIteratorVarDecl(VD); + } else { + // Currently, only declare mapper handles global-scope iterator vars. + assert(!IsGlobalVar && "Only declare mapper handles TU-scope iterators."); + } } bool SemaOpenMP::isOpenMPDeclareMapperVarDeclAllowed(const VarDecl *VD) const { @@ -23482,7 +23546,8 @@ SemaOpenMP::ActOnOpenMPUseDeviceAddrClause(ArrayRef<Expr *> VarList, SourceRange ERange; Expr *SimpleRefExpr = RefExpr; auto Res = getPrivateItem(SemaRef, SimpleRefExpr, ELoc, ERange, - /*AllowArraySection=*/true); + /*AllowArraySection=*/true, + /*AllowAssumedSizeArray=*/true); if (Res.second) { // It will be analyzed later. MVLI.ProcessedVarList.push_back(RefExpr); @@ -24810,12 +24875,12 @@ ExprResult SemaOpenMP::ActOnOMPIteratorExpr(Scope *S, /// Check if \p AssumptionStr is a known assumption and warn if not. static void checkOMPAssumeAttr(Sema &S, SourceLocation Loc, StringRef AssumptionStr) { - if (llvm::KnownAssumptionStrings.count(AssumptionStr)) + if (llvm::getKnownAssumptionStrings().count(AssumptionStr)) return; unsigned BestEditDistance = 3; StringRef Suggestion; - for (const auto &KnownAssumptionIt : llvm::KnownAssumptionStrings) { + for (const auto &KnownAssumptionIt : llvm::getKnownAssumptionStrings()) { unsigned EditDistance = AssumptionStr.edit_distance(KnownAssumptionIt.getKey()); if (EditDistance < BestEditDistance) { diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 7c4405b414c4..941542247e24 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -369,8 +369,8 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( // A conversion to an enumeration type is narrowing if the conversion to // the underlying type is narrowing. This only arises for expressions of // the form 'Enum{init}'. - if (auto *ET = ToType->getAs<EnumType>()) - ToType = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = ToType->getAsEnumDecl()) + ToType = ED->getIntegerType(); switch (Second) { // 'bool' is an integral type; dispatch to the right place to handle it. @@ -412,10 +412,12 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( // And back. llvm::APSInt ConvertedValue = *IntConstantValue; bool ignored; - Result.convertToInteger(ConvertedValue, - llvm::APFloat::rmTowardZero, &ignored); - // If the resulting value is different, this was a narrowing conversion. - if (*IntConstantValue != ConvertedValue) { + llvm::APFloat::opStatus Status = Result.convertToInteger( + ConvertedValue, llvm::APFloat::rmTowardZero, &ignored); + // If the converted-back integer has unspecified value, or if the + // resulting value is different, this was a narrowing conversion. + if (Status == llvm::APFloat::opInvalidOp || + *IntConstantValue != ConvertedValue) { ConstantValue = APValue(*IntConstantValue); ConstantType = Initializer->getType(); return NK_Constant_Narrowing; @@ -1058,13 +1060,12 @@ static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc, if (isa<CXXMethodDecl>(EqFD)) { // If F is a class member, search scope is class type of first operand. QualType RHS = FirstOperand->getType(); - auto *RHSRec = RHS->getAs<RecordType>(); + auto *RHSRec = RHS->getAsCXXRecordDecl(); if (!RHSRec) return true; LookupResult Members(S, NotEqOp, OpLoc, Sema::LookupNameKind::LookupMemberName); - S.LookupQualifiedName(Members, - RHSRec->getOriginalDecl()->getDefinitionOrSelf()); + S.LookupQualifiedName(Members, RHSRec); Members.suppressAccessDiagnostics(); for (NamedDecl *Op : Members) if (FunctionsCorrespond(S.Context, EqFD, Op->getAsFunction())) @@ -1802,7 +1803,7 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType, // constructor (i.e., a user-defined conversion function) is // called for those cases. QualType FromType = From->getType(); - if (ToType->getAs<RecordType>() && FromType->getAs<RecordType>() && + if (ToType->isRecordType() && (S.Context.hasSameUnqualifiedType(FromType, ToType) || S.IsDerivedFrom(From->getBeginLoc(), FromType, ToType))) { ICS.setStandard(); @@ -2662,11 +2663,9 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // integral promotion can be applied to its underlying type, a prvalue of an // unscoped enumeration type whose underlying type is fixed can also be // converted to a prvalue of the promoted underlying type. - if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) { + if (const auto *FromED = FromType->getAsEnumDecl()) { // C++0x 7.2p9: Note that this implicit enum to int conversion is not // provided for a scoped enumeration. - const EnumDecl *FromED = - FromEnumType->getOriginalDecl()->getDefinitionOrSelf(); if (FromED->isScoped()) return false; @@ -3969,7 +3968,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // If the type we are conversion to is a class type, enumerate its // constructors. - if (const RecordType *ToRecordType = ToType->getAs<RecordType>()) { + if (const RecordType *ToRecordType = ToType->getAsCanonical<RecordType>()) { // C++ [over.match.ctor]p1: // When objects of class type are direct-initialized (8.5), or // copy-initialized from an expression of the same or a @@ -3979,7 +3978,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // that class. The argument list is the expression-list within // the parentheses of the initializer. if (S.Context.hasSameUnqualifiedType(ToType, From->getType()) || - (From->getType()->getAs<RecordType>() && + (From->getType()->isRecordType() && S.IsDerivedFrom(From->getBeginLoc(), From->getType(), ToType))) ConstructorsOnly = true; @@ -4059,7 +4058,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, } else if (!S.isCompleteType(From->getBeginLoc(), From->getType())) { // No conversion functions from incomplete types. } else if (const RecordType *FromRecordType = - From->getType()->getAs<RecordType>()) { + From->getType()->getAsCanonical<RecordType>()) { if (auto *FromRecordDecl = dyn_cast<CXXRecordDecl>(FromRecordType->getOriginalDecl())) { FromRecordDecl = FromRecordDecl->getDefinitionOrSelf(); @@ -4509,12 +4508,10 @@ getFixedEnumPromtion(Sema &S, const StandardConversionSequence &SCS) { if (SCS.Second != ICK_Integral_Promotion) return FixedEnumPromotion::None; - QualType FromType = SCS.getFromType(); - if (!FromType->isEnumeralType()) + const auto *Enum = SCS.getFromType()->getAsEnumDecl(); + if (!Enum) return FixedEnumPromotion::None; - EnumDecl *Enum = - FromType->castAs<EnumType>()->getOriginalDecl()->getDefinitionOrSelf(); if (!Enum->isFixed()) return FixedEnumPromotion::None; @@ -5150,10 +5147,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, Expr *Init, QualType T2, bool AllowRvalues, bool AllowExplicit) { assert(T2->isRecordType() && "Can only find conversions of record types."); - auto *T2RecordDecl = - cast<CXXRecordDecl>(T2->castAs<RecordType>()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + auto *T2RecordDecl = T2->castAsCXXRecordDecl(); OverloadCandidateSet CandidateSet( DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion); const auto &Conversions = T2RecordDecl->getVisibleConversionFunctions(); @@ -6821,7 +6815,7 @@ ExprResult Sema::PerformContextualImplicitConversion( // We can only perform contextual implicit conversions on objects of class // type. - const RecordType *RecordTy = T->getAs<RecordType>(); + const RecordType *RecordTy = T->getAsCanonical<RecordType>(); if (!RecordTy || !getLangOpts().CPlusPlus) { if (!Converter.Suppress) Converter.diagnoseNoMatch(*this, Loc, T) << From->getSourceRange(); @@ -8341,10 +8335,7 @@ void Sema::AddConversionCandidate( QualType ObjectType = From->getType(); if (const auto *FromPtrType = ObjectType->getAs<PointerType>()) ObjectType = FromPtrType->getPointeeType(); - const auto *ConversionContext = - cast<CXXRecordDecl>(ObjectType->castAs<RecordType>()->getOriginalDecl()) - ->getDefinitionOrSelf(); - + const auto *ConversionContext = ObjectType->castAsCXXRecordDecl(); // C++23 [over.best.ics.general] // However, if the target is [...] // - the object parameter of a user-defined conversion function @@ -8742,10 +8733,9 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, // defined, the set of member candidates is the result of the // qualified lookup of T1::operator@ (13.3.1.1.1); otherwise, // the set of member candidates is empty. - if (const RecordType *T1Rec = T1->getAs<RecordType>()) { + if (T1->isRecordType()) { bool IsComplete = isCompleteType(OpLoc, T1); - CXXRecordDecl *T1RD = - cast<CXXRecordDecl>(T1Rec->getOriginalDecl())->getDefinition(); + auto *T1RD = T1->getAsCXXRecordDecl(); // Complete the type if it can be completed. // If the type is neither complete nor being defined, bail out now. if (!T1RD || (!IsComplete && !T1RD->isBeingDefined())) @@ -9054,8 +9044,8 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, Ty = Ty.getLocalUnqualifiedType(); // Flag if we ever add a non-record type. - const RecordType *TyRec = Ty->getAs<RecordType>(); - HasNonRecordTypes = HasNonRecordTypes || !TyRec; + bool TyIsRec = Ty->isRecordType(); + HasNonRecordTypes = HasNonRecordTypes || !TyIsRec; // Flag if we encounter an arithmetic type. HasArithmeticOrEnumeralTypes = @@ -9090,13 +9080,12 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, MatrixTypes.insert(Ty); } else if (Ty->isNullPtrType()) { HasNullPtrType = true; - } else if (AllowUserConversions && TyRec) { + } else if (AllowUserConversions && TyIsRec) { // No conversion functions in incomplete types. if (!SemaRef.isCompleteType(Loc, Ty)) return; - auto *ClassDecl = - cast<CXXRecordDecl>(TyRec->getOriginalDecl())->getDefinitionOrSelf(); + auto *ClassDecl = Ty->castAsCXXRecordDecl(); for (NamedDecl *D : ClassDecl->getVisibleConversionFunctions()) { if (isa<UsingShadowDecl>(D)) D = cast<UsingShadowDecl>(D)->getTargetDecl(); @@ -10155,7 +10144,7 @@ public: continue; for (QualType MemPtrTy : CandidateTypes[1].member_pointer_types()) { const MemberPointerType *mptr = cast<MemberPointerType>(MemPtrTy); - CXXRecordDecl *D1 = C1->getAsCXXRecordDecl(), + CXXRecordDecl *D1 = C1->castAsCXXRecordDecl(), *D2 = mptr->getMostRecentCXXRecordDecl(); if (!declaresSameEntity(D1, D2) && !S.IsDerivedFrom(CandidateSet.getLocation(), D1, D2)) @@ -10208,7 +10197,9 @@ public: if (S.getLangOpts().CPlusPlus11) { for (QualType EnumTy : CandidateTypes[ArgIdx].enumeration_types()) { - if (!EnumTy->castAs<EnumType>()->getOriginalDecl()->isScoped()) + if (!EnumTy->castAsCanonical<EnumType>() + ->getOriginalDecl() + ->isScoped()) continue; if (!AddedTypes.insert(S.Context.getCanonicalType(EnumTy)).second) @@ -16353,9 +16344,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, diag::err_incomplete_object_call, Object.get())) return true; - const auto *Record = Object.get()->getType()->castAs<RecordType>(); + auto *Record = Object.get()->getType()->castAsCXXRecordDecl(); LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName); - LookupQualifiedName(R, Record->getOriginalDecl()->getDefinitionOrSelf()); + LookupQualifiedName(R, Record); R.suppressAccessDiagnostics(); for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); @@ -16374,8 +16365,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // we filter them out to produce better error diagnostics, ie to avoid // showing 2 failed overloads instead of one. bool IgnoreSurrogateFunctions = false; - if (CandidateSet.nonDeferredCandidatesCount() == 1 && - Record->getAsCXXRecordDecl()->isLambda()) { + if (CandidateSet.nonDeferredCandidatesCount() == 1 && Record->isLambda()) { const OverloadCandidate &Candidate = *CandidateSet.begin(); if (!Candidate.Viable && Candidate.FailureKind == ovl_fail_constraints_not_satisfied) @@ -16399,9 +16389,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // functions for each conversion function declared in an // accessible base class provided the function is not hidden // within T by another intervening declaration. - const auto &Conversions = cast<CXXRecordDecl>(Record->getOriginalDecl()) - ->getDefinitionOrSelf() - ->getVisibleConversionFunctions(); + const auto &Conversions = Record->getVisibleConversionFunctions(); for (auto I = Conversions.begin(), E = Conversions.end(); !IgnoreSurrogateFunctions && I != E; ++I) { NamedDecl *D = *I; @@ -16622,10 +16610,7 @@ ExprResult Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, return ExprError(); LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName); - LookupQualifiedName(R, Base->getType() - ->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf()); + LookupQualifiedName(R, Base->getType()->castAsRecordDecl()); R.suppressAccessDiagnostics(); for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index 46d7372dd056..bfa458d207b4 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -41,10 +41,7 @@ void SemaPPC::checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg) { return; QualType ArgType = Arg->getType(); - for (const FieldDecl *FD : ArgType->castAs<RecordType>() - ->getOriginalDecl() - ->getDefinitionOrSelf() - ->fields()) { + for (const FieldDecl *FD : ArgType->castAsRecordDecl()->fields()) { if (const auto *AA = FD->getAttr<AlignedAttr>()) { CharUnits Alignment = getASTContext().toCharUnitsFromBits( AA->getAlignment(getASTContext())); diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index 7b16d080603b..3ba93ff98898 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -1000,6 +1000,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm: + case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm: return SemaRef.BuiltinConstantArgRange(TheCall, 1, 0, 4); case RISCVVector::BI__builtin_rvv_vfadd_vv_rm: case RISCVVector::BI__builtin_rvv_vfadd_vf_rm: @@ -1038,6 +1039,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tu: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tu: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tu: + case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm_tu: case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_m: case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_m: case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_m: @@ -1051,6 +1053,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_m: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_m: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_m: + case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm_m: return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 4); case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tu: case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tu: @@ -1100,6 +1103,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm: case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm: case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm: case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_tu: case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_tu: case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_tu: @@ -1124,6 +1129,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tu: case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tu: case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm_tu: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm_tu: case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_m: case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_m: case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_m: @@ -1161,6 +1168,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tum: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tum: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tum: + case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm_tum: case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_tumu: case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_tumu: case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_tumu: @@ -1174,6 +1182,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_tumu: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_tumu: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm_tumu: case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm_mu: case RISCVVector::BI__builtin_rvv_vfrec7_v_rm_mu: case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm_mu: @@ -1187,6 +1196,7 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_mu: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_mu: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_mu: + case RISCVVector::BI__builtin_rvv_vfncvtbf16_f_f_w_rm_mu: return SemaRef.BuiltinConstantArgRange(TheCall, 3, 0, 4); case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_m: case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_m: @@ -1212,6 +1222,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_m: case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_m: case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm_m: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm_m: case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tum: case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tum: case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tum: @@ -1256,6 +1268,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tum: case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tum: case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm_tum: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm_tum: case RISCVVector::BI__builtin_rvv_vfredosum_vs_rm_tum: case RISCVVector::BI__builtin_rvv_vfredusum_vs_rm_tum: case RISCVVector::BI__builtin_rvv_vfwredosum_vs_rm_tum: @@ -1304,6 +1318,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_tumu: case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_tumu: case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm_tumu: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm_tumu: case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_mu: case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_mu: case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_mu: @@ -1348,6 +1364,8 @@ bool SemaRISCV::CheckBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_mu: case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_mu: case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vv_rm_mu: + case RISCVVector::BI__builtin_rvv_vfwmaccbf16_vf_rm_mu: return SemaRef.BuiltinConstantArgRange(TheCall, 4, 0, 4); case RISCV::BI__builtin_riscv_ntl_load: case RISCV::BI__builtin_riscv_ntl_store: diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index bc1ddb80961a..ae0bb616beb8 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -1271,8 +1271,8 @@ static void checkEnumTypesInSwitchStmt(Sema &S, const Expr *Cond, QualType CondType = Cond->getType(); QualType CaseType = Case->getType(); - const EnumType *CondEnumType = CondType->getAs<EnumType>(); - const EnumType *CaseEnumType = CaseType->getAs<EnumType>(); + const EnumType *CondEnumType = CondType->getAsCanonical<EnumType>(); + const EnumType *CaseEnumType = CaseType->getAsCanonical<EnumType>(); if (!CondEnumType || !CaseEnumType) return; @@ -1590,12 +1590,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // we still do the analysis to preserve this information in the AST // (which can be used by flow-based analyes). // - const EnumType *ET = CondTypeBeforePromotion->getAs<EnumType>(); - // If switch has default case, then ignore it. if (!CaseListIsErroneous && !CaseListIsIncomplete && !HasConstantCond && - ET) { - const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + CondTypeBeforePromotion->isEnumeralType()) { + const auto *ED = CondTypeBeforePromotion->castAsEnumDecl(); if (!ED->isCompleteDefinition() || ED->enumerators().empty()) goto enum_out; @@ -1730,8 +1728,7 @@ void Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, Expr *SrcExpr) { - const auto *ET = DstType->getAs<EnumType>(); - if (!ET) + if (!DstType->isEnumeralType()) return; if (!SrcType->isIntegerType() || @@ -1741,7 +1738,7 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, if (SrcExpr->isTypeDependent() || SrcExpr->isValueDependent()) return; - const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf(); + const auto *ED = DstType->castAsEnumDecl(); if (!ED->isClosed()) return; @@ -2125,12 +2122,12 @@ namespace { typedef ConstEvaluatedExprVisitor<BreakContinueFinder> Inherited; void VisitContinueStmt(const ContinueStmt* E) { - ContinueLoc = E->getContinueLoc(); + ContinueLoc = E->getKwLoc(); } void VisitBreakStmt(const BreakStmt* E) { if (!InSwitch) - BreakLoc = E->getBreakLoc(); + BreakLoc = E->getKwLoc(); } void VisitSwitchStmt(const SwitchStmt* S) { @@ -3278,9 +3275,55 @@ static void CheckJumpOutOfSEHFinally(Sema &S, SourceLocation Loc, } } -StmtResult -Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) { - Scope *S = CurScope->getContinueParent(); +static Scope *FindLabeledBreakContinueScope(Sema &S, Scope *CurScope, + SourceLocation KWLoc, + LabelDecl *Target, + SourceLocation LabelLoc, + bool IsContinue) { + assert(Target && "not a named break/continue?"); + Scope *Found = nullptr; + for (Scope *Scope = CurScope; Scope; Scope = Scope->getParent()) { + if (Scope->isFunctionScope()) + break; + + if (Scope->isOpenACCComputeConstructScope()) { + S.Diag(KWLoc, diag::err_acc_branch_in_out_compute_construct) + << /*branch*/ 0 << /*out of*/ 0; + return nullptr; + } + + if (Scope->isBreakOrContinueScope() && + Scope->getPrecedingLabel() == Target) { + Found = Scope; + break; + } + } + + if (Found) { + if (IsContinue && !Found->isContinueScope()) { + S.Diag(LabelLoc, diag::err_continue_switch); + return nullptr; + } + return Found; + } + + S.Diag(LabelLoc, diag::err_break_continue_label_not_found) << IsContinue; + return nullptr; +} + +StmtResult Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope, + LabelDecl *Target, SourceLocation LabelLoc) { + Scope *S; + if (Target) { + S = FindLabeledBreakContinueScope(*this, CurScope, ContinueLoc, Target, + LabelLoc, + /*IsContinue=*/true); + if (!S) + return StmtError(); + } else { + S = CurScope->getContinueParent(); + } + if (!S) { // C99 6.8.6.2p1: A break shall appear only in or as a loop body. return StmtError(Diag(ContinueLoc, diag::err_continue_not_in_loop)); @@ -3302,16 +3345,27 @@ Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) { CheckJumpOutOfSEHFinally(*this, ContinueLoc, *S); - return new (Context) ContinueStmt(ContinueLoc); + return new (Context) ContinueStmt(ContinueLoc, LabelLoc, Target); } -StmtResult -Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { - Scope *S = CurScope->getBreakParent(); +StmtResult Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope, + LabelDecl *Target, SourceLocation LabelLoc) { + Scope *S; + if (Target) { + S = FindLabeledBreakContinueScope(*this, CurScope, BreakLoc, Target, + LabelLoc, + /*IsContinue=*/false); + if (!S) + return StmtError(); + } else { + S = CurScope->getBreakParent(); + } + if (!S) { // C99 6.8.6.3p1: A break shall appear only in or as a switch/loop body. return StmtError(Diag(BreakLoc, diag::err_break_not_in_loop_or_switch)); } + if (S->isOpenMPLoopScope()) return StmtError(Diag(BreakLoc, diag::err_omp_loop_cannot_use_stmt) << "break"); @@ -3332,7 +3386,7 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { CheckJumpOutOfSEHFinally(*this, BreakLoc, *S); - return new (Context) BreakStmt(BreakLoc); + return new (Context) BreakStmt(BreakLoc, LabelLoc, Target); } Sema::NamedReturnInfo Sema::getNamedReturnInfo(Expr *&E, diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index cd8b98c7444e..0438af752a69 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -885,18 +885,19 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, for (StringRef NextMember : Members) { const RecordType *RT = nullptr; if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) - RT = VD->getType()->getAs<RecordType>(); + RT = VD->getType()->getAsCanonical<RecordType>(); else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) { MarkAnyDeclReferenced(TD->getLocation(), TD, /*OdrUse=*/false); // MS InlineAsm often uses struct pointer aliases as a base QualType QT = TD->getUnderlyingType(); if (const auto *PT = QT->getAs<PointerType>()) QT = PT->getPointeeType(); - RT = QT->getAs<RecordType>(); + RT = QT->getAsCanonical<RecordType>(); } else if (TypeDecl *TD = dyn_cast<TypeDecl>(FoundDecl)) - RT = Context.getTypeDeclType(TD)->getAs<RecordType>(); + RT = QualType(Context.getCanonicalTypeDeclType(TD)) + ->getAsCanonical<RecordType>(); else if (FieldDecl *TD = dyn_cast<FieldDecl>(FoundDecl)) - RT = TD->getType()->getAs<RecordType>(); + RT = TD->getType()->getAsCanonical<RecordType>(); if (!RT) return true; @@ -944,16 +945,15 @@ Sema::LookupInlineAsmVarDeclField(Expr *E, StringRef Member, /*FirstQualifierFoundInScope=*/nullptr, NameInfo, /*TemplateArgs=*/nullptr); } - const RecordType *RT = T->getAs<RecordType>(); + auto *RD = T->getAsRecordDecl(); // FIXME: Diagnose this as field access into a scalar type. - if (!RT) + if (!RD) return ExprResult(); LookupResult FieldResult(*this, &Context.Idents.get(Member), AsmLoc, LookupMemberName); - if (!LookupQualifiedName(FieldResult, - RT->getOriginalDecl()->getDefinitionOrSelf())) + if (!LookupQualifiedName(FieldResult, RD)) return ExprResult(); // Only normal and indirect field results will work. diff --git a/clang/lib/Sema/SemaSwift.cpp b/clang/lib/Sema/SemaSwift.cpp index a99222c5ed55..f0c9cc8620af 100644 --- a/clang/lib/Sema/SemaSwift.cpp +++ b/clang/lib/Sema/SemaSwift.cpp @@ -129,9 +129,9 @@ static bool isErrorParameter(Sema &S, QualType QT) { // Check for CFError**. if (const auto *PT = Pointee->getAs<PointerType>()) - if (const auto *RT = PT->getPointeeType()->getAs<RecordType>()) - if (S.ObjC().isCFError(RT->getOriginalDecl()->getDefinitionOrSelf())) - return true; + if (auto *RD = PT->getPointeeType()->getAsRecordDecl(); + RD && S.ObjC().isCFError(RD)) + return true; return false; } @@ -271,12 +271,10 @@ static void checkSwiftAsyncErrorBlock(Sema &S, Decl *D, } // Check for CFError *. if (const auto *PtrTy = Param->getAs<PointerType>()) { - if (const auto *RT = PtrTy->getPointeeType()->getAs<RecordType>()) { - if (S.ObjC().isCFError( - RT->getOriginalDecl()->getDefinitionOrSelf())) { - AnyErrorParams = true; - break; - } + if (auto *RD = PtrTy->getPointeeType()->getAsRecordDecl(); + RD && S.ObjC().isCFError(RD)) { + AnyErrorParams = true; + break; } } } @@ -354,7 +352,7 @@ static bool validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, else if (Name.consume_front("setter:")) IsSetter = true; - if (Name.back() != ')') { + if (Name.empty() || Name.back() != ')') { S.Diag(Loc, diag::warn_attr_swift_name_function) << AL; return false; } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 36bffc5e5e3c..58dae32569bc 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1716,79 +1716,98 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter( namespace { class ConstraintRefersToContainingTemplateChecker - : public TreeTransform<ConstraintRefersToContainingTemplateChecker> { + : public ConstDynamicRecursiveASTVisitor { + using inherited = ConstDynamicRecursiveASTVisitor; bool Result = false; const FunctionDecl *Friend = nullptr; unsigned TemplateDepth = 0; // Check a record-decl that we've seen to see if it is a lexical parent of the // Friend, likely because it was referred to without its template arguments. - void CheckIfContainingRecord(const CXXRecordDecl *CheckingRD) { + bool CheckIfContainingRecord(const CXXRecordDecl *CheckingRD) { CheckingRD = CheckingRD->getMostRecentDecl(); if (!CheckingRD->isTemplated()) - return; + return true; for (const DeclContext *DC = Friend->getLexicalDeclContext(); DC && !DC->isFileContext(); DC = DC->getParent()) if (const auto *RD = dyn_cast<CXXRecordDecl>(DC)) - if (CheckingRD == RD->getMostRecentDecl()) + if (CheckingRD == RD->getMostRecentDecl()) { Result = true; + return false; + } + + return true; } - void CheckNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + bool CheckNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { if (D->getDepth() < TemplateDepth) Result = true; // Necessary because the type of the NTTP might be what refers to the parent // constriant. - TransformType(D->getType()); + return TraverseType(D->getType()); } public: - using inherited = TreeTransform<ConstraintRefersToContainingTemplateChecker>; - - ConstraintRefersToContainingTemplateChecker(Sema &SemaRef, - const FunctionDecl *Friend, + ConstraintRefersToContainingTemplateChecker(const FunctionDecl *Friend, unsigned TemplateDepth) - : inherited(SemaRef), Friend(Friend), TemplateDepth(TemplateDepth) {} + : Friend(Friend), TemplateDepth(TemplateDepth) {} + bool getResult() const { return Result; } // This should be the only template parm type that we have to deal with. - // SubstTempalteTypeParmPack, SubstNonTypeTemplateParmPack, and + // SubstTemplateTypeParmPack, SubstNonTypeTemplateParmPack, and // FunctionParmPackExpr are all partially substituted, which cannot happen // with concepts at this point in translation. - using inherited::TransformTemplateTypeParmType; - QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL, bool) { - if (TL.getDecl()->getDepth() < TemplateDepth) + bool VisitTemplateTypeParmType(const TemplateTypeParmType *Type) override { + if (Type->getDecl()->getDepth() < TemplateDepth) { Result = true; - return inherited::TransformTemplateTypeParmType( - TLB, TL, - /*SuppressObjCLifetime=*/false); + return false; + } + return true; } - Decl *TransformDecl(SourceLocation Loc, Decl *D) { - if (!D) - return D; + bool TraverseDeclRefExpr(const DeclRefExpr *E) override { + return TraverseDecl(E->getDecl()); + } + + bool TraverseTypedefType(const TypedefType *TT, + bool /*TraverseQualifier*/) override { + return TraverseType(TT->desugar()); + } + + bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier) override { + // We don't care about TypeLocs. So traverse Types instead. + return TraverseType(TL.getType(), TraverseQualifier); + } + + bool VisitTagType(const TagType *T) override { + return TraverseDecl(T->getOriginalDecl()); + } + + bool TraverseDecl(const Decl *D) override { + assert(D); // FIXME : This is possibly an incomplete list, but it is unclear what other // Decl kinds could be used to refer to the template parameters. This is a // best guess so far based on examples currently available, but the // unreachable should catch future instances/cases. if (auto *TD = dyn_cast<TypedefNameDecl>(D)) - TransformType(TD->getUnderlyingType()); - else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(D)) - CheckNonTypeTemplateParmDecl(NTTPD); - else if (auto *VD = dyn_cast<ValueDecl>(D)) - TransformType(VD->getType()); - else if (auto *TD = dyn_cast<TemplateDecl>(D)) - TransformTemplateParameterList(TD->getTemplateParameters()); - else if (auto *RD = dyn_cast<CXXRecordDecl>(D)) - CheckIfContainingRecord(RD); - else if (isa<NamedDecl>(D)) { + return TraverseType(TD->getUnderlyingType()); + if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(D)) + return CheckNonTypeTemplateParmDecl(NTTPD); + if (auto *VD = dyn_cast<ValueDecl>(D)) + return TraverseType(VD->getType()); + if (isa<TemplateDecl>(D)) + return true; + if (auto *RD = dyn_cast<CXXRecordDecl>(D)) + return CheckIfContainingRecord(RD); + + if (isa<NamedDecl, RequiresExprBodyDecl>(D)) { // No direct types to visit here I believe. } else llvm_unreachable("Don't know how to handle this declaration type yet"); - return D; + return true; } }; } // namespace @@ -1797,9 +1816,8 @@ bool Sema::ConstraintExpressionDependsOnEnclosingTemplate( const FunctionDecl *Friend, unsigned TemplateDepth, const Expr *Constraint) { assert(Friend->getFriendObjectKind() && "Only works on a friend"); - ConstraintRefersToContainingTemplateChecker Checker(*this, Friend, - TemplateDepth); - Checker.TransformExpr(const_cast<Expr *>(Constraint)); + ConstraintRefersToContainingTemplateChecker Checker(Friend, TemplateDepth); + Checker.TraverseStmt(Constraint); return Checker.getResult(); } @@ -2859,14 +2877,14 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( } // Retrieve the parent of an enumeration type. - if (const EnumType *EnumT = T->getAs<EnumType>()) { + if (const EnumType *EnumT = T->getAsCanonical<EnumType>()) { // FIXME: Forward-declared enums require a TSK_ExplicitSpecialization // check here. EnumDecl *Enum = EnumT->getOriginalDecl(); // Get to the parent type. if (TypeDecl *Parent = dyn_cast<TypeDecl>(Enum->getParent())) - T = Context.getTypeDeclType(Parent); + T = Context.getCanonicalTypeDeclType(Parent); else T = QualType(); continue; @@ -3313,7 +3331,7 @@ static bool isInVkNamespace(const RecordType *RT) { static SpirvOperand checkHLSLSpirvTypeOperand(Sema &SemaRef, QualType OperandArg, SourceLocation Loc) { - if (auto *RT = OperandArg->getAs<RecordType>()) { + if (auto *RT = OperandArg->getAsCanonical<RecordType>()) { bool Literal = false; SourceLocation LiteralLoc; if (isInVkNamespace(RT) && RT->getOriginalDecl()->getName() == "Literal") { @@ -3323,7 +3341,7 @@ static SpirvOperand checkHLSLSpirvTypeOperand(Sema &SemaRef, const TemplateArgumentList &LiteralArgs = SpecDecl->getTemplateArgs(); QualType ConstantType = LiteralArgs[0].getAsType(); - RT = ConstantType->getAs<RecordType>(); + RT = ConstantType->getAsCanonical<RecordType>(); Literal = true; LiteralLoc = SpecDecl->getSourceRange().getBegin(); } @@ -4087,7 +4105,7 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, // Check the tag kind if (const RecordType *RT = Result->getAs<RecordType>()) { - RecordDecl *D = RT->getOriginalDecl()->getDefinitionOrSelf(); + RecordDecl *D = RT->getOriginalDecl(); IdentifierInfo *Id = D->getIdentifier(); assert(Id && "templated class must have an identifier"); @@ -4132,7 +4150,7 @@ static bool isTemplateArgumentTemplateParameter(const TemplateArgument &Arg, case TemplateArgument::Type: { QualType Type = Arg.getAsType(); const TemplateTypeParmType *TPT = - Arg.getAsType()->getAs<TemplateTypeParmType>(); + Arg.getAsType()->getAsCanonical<TemplateTypeParmType>(); return TPT && !Type.hasQualifiers() && TPT->getDepth() == Depth && TPT->getIndex() == Index; } @@ -4542,7 +4560,8 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) { DeclResult Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation TemplateNameLoc, - const TemplateArgumentListInfo &TemplateArgs) { + const TemplateArgumentListInfo &TemplateArgs, + bool SetWrittenArgs) { assert(Template && "A variable template id without template?"); // Check that the template argument list is well-formed for this template. @@ -4725,10 +4744,12 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, // in DoMarkVarDeclReferenced(). // FIXME: LateAttrs et al.? VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation( - Template, InstantiationPattern, PartialSpecArgs, TemplateArgs, - CTAI.CanonicalConverted, TemplateNameLoc /*, LateAttrs, StartingScope*/); + Template, InstantiationPattern, PartialSpecArgs, CTAI.CanonicalConverted, + TemplateNameLoc /*, LateAttrs, StartingScope*/); if (!Decl) return true; + if (SetWrittenArgs) + Decl->setTemplateArgsAsWritten(TemplateArgs); if (AmbiguousPartialSpec) { // Partial ordering did not produce a clear winner. Complain. @@ -4760,7 +4781,7 @@ ExprResult Sema::CheckVarTemplateId( const TemplateArgumentListInfo *TemplateArgs) { DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(), - *TemplateArgs); + *TemplateArgs, /*SetWrittenArgs=*/false); if (Decl.isInvalid()) return ExprError(); @@ -7411,9 +7432,8 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType, // always a no-op, except when the parameter type is bool. In // that case, this may extend the argument from 1 bit to 8 bits. QualType IntegerType = ParamType; - if (const EnumType *Enum = IntegerType->getAs<EnumType>()) - IntegerType = - Enum->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = IntegerType->getAsEnumDecl()) + IntegerType = ED->getIntegerType(); Value = Value.extOrTrunc(IntegerType->isBitIntType() ? Context.getIntWidth(IntegerType) : Context.getTypeSize(IntegerType)); @@ -7510,9 +7530,8 @@ ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType, } QualType IntegerType = ParamType; - if (const EnumType *Enum = IntegerType->getAs<EnumType>()) { - IntegerType = - Enum->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = IntegerType->getAsEnumDecl()) { + IntegerType = ED->getIntegerType(); } if (ParamType->isBooleanType()) { @@ -8028,8 +8047,8 @@ static Expr *BuildExpressionFromIntegralTemplateArgumentValue( // any integral type with C++11 enum classes, make sure we create the right // type of literal for it. QualType T = OrigT; - if (const EnumType *ET = OrigT->getAs<EnumType>()) - T = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType(); + if (const auto *ED = OrigT->getAsEnumDecl()) + T = ED->getIntegerType(); Expr *E; if (T->isAnyCharacterType()) { @@ -10709,8 +10728,9 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateArgumentListInfo TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId); - DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc, - D.getIdentifierLoc(), TemplateArgs); + DeclResult Res = + CheckVarTemplateId(PrevTemplate, TemplateLoc, D.getIdentifierLoc(), + TemplateArgs, /*SetWrittenArgs=*/true); if (Res.isInvalid()) return true; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 93983bf6d160..cce40c0c91f9 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -698,9 +698,8 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, TNP = TP->getTemplateName(); // FIXME: To preserve sugar, the TST needs to carry sugared resolved // arguments. - PResolved = TP->getCanonicalTypeInternal() - ->castAs<TemplateSpecializationType>() - ->template_arguments(); + PResolved = + TP->castAsCanonical<TemplateSpecializationType>()->template_arguments(); } else { const auto *TT = P->castAs<InjectedClassNameType>(); TNP = TT->getTemplateName(S.Context); @@ -1437,7 +1436,8 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) { if (auto *ParamRef = Param->getAs<RValueReferenceType>()) { if (ParamRef->getPointeeType().getQualifiers()) return false; - auto *TypeParm = ParamRef->getPointeeType()->getAs<TemplateTypeParmType>(); + auto *TypeParm = + ParamRef->getPointeeType()->getAsCanonical<TemplateTypeParmType>(); return TypeParm && TypeParm->getIndex() >= FirstInnerIndex; } return false; @@ -1702,7 +1702,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // // T // cv-list T - if (const auto *TTP = P->getAs<TemplateTypeParmType>()) { + if (const auto *TTP = P->getAsCanonical<TemplateTypeParmType>()) { // Just skip any attempts to deduce from a placeholder type or a parameter // at a different depth. if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth()) @@ -3559,7 +3559,7 @@ static bool isSimpleTemplateIdType(QualType T) { // // This only arises during class template argument deduction for a copy // deduction candidate, where it permits slicing. - if (T->getAs<InjectedClassNameType>()) + if (isa<InjectedClassNameType>(T.getCanonicalType())) return true; return false; @@ -5596,7 +5596,7 @@ static TemplateDeductionResult CheckDeductionConsistency( // so let it transform their specializations instead. bool IsDeductionGuide = isa<CXXDeductionGuideDecl>(FTD->getTemplatedDecl()); if (IsDeductionGuide) { - if (auto *Injected = P->getAs<InjectedClassNameType>()) + if (auto *Injected = P->getAsCanonical<InjectedClassNameType>()) P = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType( S.Context); } @@ -5617,10 +5617,10 @@ static TemplateDeductionResult CheckDeductionConsistency( auto T1 = S.Context.getUnqualifiedArrayType(InstP.getNonReferenceType()); auto T2 = S.Context.getUnqualifiedArrayType(A.getNonReferenceType()); if (IsDeductionGuide) { - if (auto *Injected = T1->getAs<InjectedClassNameType>()) + if (auto *Injected = T1->getAsCanonical<InjectedClassNameType>()) T1 = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType( S.Context); - if (auto *Injected = T2->getAs<InjectedClassNameType>()) + if (auto *Injected = T2->getAsCanonical<InjectedClassNameType>()) T2 = Injected->getOriginalDecl()->getCanonicalTemplateSpecializationType( S.Context); } diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 604591408728..3d54d1eb4373 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -995,8 +995,8 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) { // Cases where template arguments in the RHS of the alias are not // dependent. e.g. // using AliasFoo = Foo<bool>; - if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>( - RT->getAsCXXRecordDecl())) { + if (const auto *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(RT->getOriginalDecl())) { Template = CTSD->getSpecializedTemplate(); AliasRhsTemplateArgs = CTSD->getTemplateArgs().asArray(); } @@ -1056,7 +1056,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, // The (trailing) return type of the deduction guide. const TemplateSpecializationType *FReturnType = RType->getAs<TemplateSpecializationType>(); - if (const auto *ICNT = RType->getAs<InjectedClassNameType>()) + if (const auto *ICNT = RType->getAsCanonical<InjectedClassNameType>()) // implicitly-generated deduction guide. FReturnType = cast<TemplateSpecializationType>( ICNT->getOriginalDecl()->getCanonicalTemplateSpecializationType( diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index fe1c5faba9e4..a72c95d6d77c 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2124,9 +2124,11 @@ TemplateName TemplateInstantiator::TransformTemplateName( NestedNameSpecifierLoc &QualifierLoc, SourceLocation TemplateKWLoc, TemplateName Name, SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) { - if (TemplateTemplateParmDecl *TTP - = dyn_cast_or_null<TemplateTemplateParmDecl>(Name.getAsTemplateDecl())) { - if (TTP->getDepth() < TemplateArgs.getNumLevels()) { + if (Name.getKind() == TemplateName::Template) { + assert(!QualifierLoc && "Unexpected qualifier"); + if (auto *TTP = + dyn_cast<TemplateTemplateParmDecl>(Name.getAsTemplateDecl()); + TTP && TTP->getDepth() < TemplateArgs.getNumLevels()) { // If the corresponding template argument is NULL or non-existent, it's // because we are performing instantiation from explicitly-specified // template arguments in a function template, but there were some @@ -2169,13 +2171,6 @@ TemplateName TemplateInstantiator::TransformTemplateName( TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && "Null template template argument"); - - if (NestedNameSpecifier Qualifier = Template.getQualifier()) { - NestedNameSpecifierLocBuilder Builder; - Builder.MakeTrivial(SemaRef.Context, Qualifier, NameLoc); - QualifierLoc = Builder.getWithLocInContext(SemaRef.Context); - } - return getSema().Context.getSubstTemplateTemplateParm( Template, AssociatedDecl, TTP->getIndex(), PackIndex, Final); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 681ee796440f..b3cbd7f8c1ef 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -234,6 +234,32 @@ static void instantiateDependentAnnotationAttr( } } +template <typename Attr> +static void sharedInstantiateConstructorDestructorAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const Attr *A, + Decl *New, ASTContext &C) { + Expr *tempInstPriority = nullptr; + { + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::Unevaluated); + ExprResult Result = S.SubstExpr(A->getPriority(), TemplateArgs); + if (Result.isInvalid()) + return; + tempInstPriority = Result.get(); + if (std::optional<llvm::APSInt> CE = + tempInstPriority->getIntegerConstantExpr(C)) { + // Consistent with non-templated priority arguments, which must fit in a + // 32-bit unsigned integer. + if (!CE->isIntN(32)) { + S.Diag(tempInstPriority->getExprLoc(), diag::err_ice_too_large) + << toString(*CE, 10, false) << /*Size=*/32 << /*Unsigned=*/1; + return; + } + } + } + New->addAttr(Attr::Create(C, tempInstPriority, *A)); +} + static Expr *instantiateDependentFunctionAttrCondition( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const Attr *A, Expr *OldCond, const Decl *Tmpl, FunctionDecl *New) { @@ -825,6 +851,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (auto *Constructor = dyn_cast<ConstructorAttr>(TmplAttr)) { + sharedInstantiateConstructorDestructorAttr(*this, TemplateArgs, + Constructor, New, Context); + continue; + } + + if (auto *Destructor = dyn_cast<DestructorAttr>(TmplAttr)) { + sharedInstantiateConstructorDestructorAttr(*this, TemplateArgs, + Destructor, New, Context); + continue; + } + if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) { instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl, cast<FunctionDecl>(New)); @@ -4542,14 +4580,17 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( PrevDecl->getPointOfInstantiation(), Ignored)) return nullptr; - return VisitVarTemplateSpecializationDecl(InstVarTemplate, D, - VarTemplateArgsInfo, - CTAI.CanonicalConverted, PrevDecl); + if (VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl( + InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl)) { + VTSD->setTemplateArgsAsWritten(VarTemplateArgsInfo); + return VTSD; + } + return nullptr; } -Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( +VarTemplateSpecializationDecl * +TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( VarTemplateDecl *VarTemplate, VarDecl *D, - const TemplateArgumentListInfo &TemplateArgsInfo, ArrayRef<TemplateArgument> Converted, VarTemplateSpecializationDecl *PrevDecl) { @@ -4570,7 +4611,6 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create( SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted); - Var->setTemplateArgsAsWritten(TemplateArgsInfo); if (!PrevDecl) { void *InsertPos = nullptr; VarTemplate->findSpecialization(Converted, InsertPos); @@ -5880,7 +5920,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( VarTemplateDecl *VarTemplate, VarDecl *FromVar, const TemplateArgumentList *PartialSpecArgs, - const TemplateArgumentListInfo &TemplateArgsInfo, SmallVectorImpl<TemplateArgument> &Converted, SourceLocation PointOfInstantiation, LateInstantiatedAttrVec *LateAttrs, LocalInstantiationScope *StartingScope) { @@ -5922,9 +5961,8 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( // TODO: Set LateAttrs and StartingScope ... - return cast_or_null<VarTemplateSpecializationDecl>( - Instantiator.VisitVarTemplateSpecializationDecl( - VarTemplate, FromVar, TemplateArgsInfo, Converted)); + return Instantiator.VisitVarTemplateSpecializationDecl(VarTemplate, FromVar, + Converted); } VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( @@ -6340,10 +6378,15 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, TemplateArgInfo.addArgument(Arg); } - Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl( - VarSpec->getSpecializedTemplate(), Def, TemplateArgInfo, - VarSpec->getTemplateArgs().asArray(), VarSpec)); + VarTemplateSpecializationDecl *VTSD = + Instantiator.VisitVarTemplateSpecializationDecl( + VarSpec->getSpecializedTemplate(), Def, + VarSpec->getTemplateArgs().asArray(), VarSpec); + Var = VTSD; + if (Var) { + VTSD->setTemplateArgsAsWritten(TemplateArgInfo); + llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> PatternPtr = VarSpec->getSpecializedTemplateOrPartial(); @@ -6973,19 +7016,15 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // If our context used to be dependent, we may need to instantiate // it before performing lookup into that context. bool IsBeingInstantiated = false; - if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) { + if (auto *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) { if (!Spec->isDependentContext()) { - CanQualType T = Context.getCanonicalTagType(Spec); - const RecordType *Tag = T->getAs<RecordType>(); - assert(Tag && "type of non-dependent record is not a RecordType"); - auto *TagDecl = - cast<CXXRecordDecl>(Tag->getOriginalDecl())->getDefinitionOrSelf(); - if (TagDecl->isBeingDefined()) + if (Spec->isEntityBeingDefined()) IsBeingInstantiated = true; - else if (RequireCompleteType(Loc, T, diag::err_incomplete_type)) + else if (RequireCompleteType(Loc, Context.getCanonicalTagType(Spec), + diag::err_incomplete_type)) return nullptr; - ParentDC = TagDecl; + ParentDC = Spec->getDefinitionOrSelf(); } } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index d745cdbf0526..0f655d7f684a 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2115,12 +2115,10 @@ QualType Sema::BuildArrayType(QualType T, ArraySizeModifier ASM, return QualType(); } - if (const RecordType *EltTy = T->getAs<RecordType>()) { + if (const auto *RD = T->getAsRecordDecl()) { // If the element type is a struct or union that contains a variadic // array, accept it as a GNU extension: C99 6.7.2.1p2. - if (EltTy->getOriginalDecl() - ->getDefinitionOrSelf() - ->hasFlexibleArrayMember()) + if (RD->hasFlexibleArrayMember()) Diag(Loc, diag::ext_flexible_array_in_array) << T; } else if (T->isObjCObjectType()) { Diag(Loc, diag::err_objc_array_of_interfaces) << T; @@ -3975,10 +3973,7 @@ classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator, if (numNormalPointers == 0) return PointerDeclaratorKind::NonPointer; - if (auto recordType = type->getAs<RecordType>()) { - RecordDecl *recordDecl = - recordType->getOriginalDecl()->getDefinitionOrSelf(); - + if (auto *recordDecl = type->getAsRecordDecl()) { // If this is CFErrorRef*, report it as such. if (numNormalPointers == 2 && numTypeSpecifierPointers < 2 && S.ObjC().isCFError(recordDecl)) { @@ -9622,19 +9617,16 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, if (T->isVariableArrayType()) return true; - const RecordType *RT = ElemType->getAs<RecordType>(); - if (!RT) + if (!ElemType->isRecordType()) return true; - const CXXRecordDecl *RD = - cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(); - // A partially-defined class type can't be a literal type, because a literal // class type must have a trivial destructor (which can't be checked until // the class definition is complete). if (RequireCompleteType(Loc, ElemType, diag::note_non_literal_incomplete, T)) return true; + const auto *RD = ElemType->castAsCXXRecordDecl(); // [expr.prim.lambda]p3: // This class type is [not] a literal type. if (RD->isLambda() && !getLangOpts().CPlusPlus17) { @@ -9886,7 +9878,14 @@ static QualType GetEnumUnderlyingType(Sema &S, QualType BaseType, S.DiagnoseUseOfDecl(ED, Loc); QualType Underlying = ED->getIntegerType(); - assert(!Underlying.isNull()); + if (Underlying.isNull()) { + // This is an enum without a fixed underlying type which we skipped parsing + // the body because we saw its definition previously in another module. + // Use the definition's integer type in that case. + assert(ED->isThisDeclarationADemotedDefinition()); + Underlying = ED->getDefinition()->getIntegerType(); + assert(!Underlying.isNull()); + } return Underlying; } diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index 0b4d5916f8dc..1ca769ebb50f 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/DiagnosticParse.h" #include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/Specifiers.h" #include "clang/Basic/TypeTraits.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Initialization.h" @@ -23,6 +24,7 @@ #include "clang/Sema/Overload.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaHLSL.h" +#include "llvm/ADT/STLExtras.h" using namespace clang; @@ -556,13 +558,11 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, } } -static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, +static bool HasNoThrowOperator(CXXRecordDecl *RD, OverloadedOperatorKind Op, Sema &Self, SourceLocation KeyLoc, ASTContext &C, bool (CXXRecordDecl::*HasTrivial)() const, bool (CXXRecordDecl::*HasNonTrivial)() const, bool (CXXMethodDecl::*IsDesiredOp)() const) { - CXXRecordDecl *RD = - cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(); if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)()) return true; @@ -1007,8 +1007,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, if (T.isPODType(C) || T->isObjCLifetimeType()) return true; - if (const RecordType *RT = T->getAs<RecordType>()) - return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, + if (auto *RD = T->getAsCXXRecordDecl()) + return HasNoThrowOperator(RD, OO_Equal, Self, KeyLoc, C, &CXXRecordDecl::hasTrivialCopyAssignment, &CXXRecordDecl::hasNonTrivialCopyAssignment, &CXXMethodDecl::isCopyAssignmentOperator); @@ -1020,8 +1020,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, if (T.isPODType(C)) return true; - if (const RecordType *RT = C.getBaseElementType(T)->getAs<RecordType>()) - return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, + if (auto *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) + return HasNoThrowOperator(RD, OO_Equal, Self, KeyLoc, C, &CXXRecordDecl::hasTrivialMoveAssignment, &CXXRecordDecl::hasNonTrivialMoveAssignment, &CXXMethodDecl::isMoveAssignmentOperator); @@ -1585,8 +1585,8 @@ bool Sema::BuiltinIsBaseOf(SourceLocation RhsTLoc, QualType LhsT, // Base and Derived are not unions and name the same class type without // regard to cv-qualifiers. - const RecordType *lhsRecord = LhsT->getAs<RecordType>(); - const RecordType *rhsRecord = RhsT->getAs<RecordType>(); + const RecordType *lhsRecord = LhsT->getAsCanonical<RecordType>(); + const RecordType *rhsRecord = RhsT->getAsCanonical<RecordType>(); if (!rhsRecord || !lhsRecord) { const ObjCObjectType *LHSObjTy = LhsT->getAs<ObjCObjectType>(); const ObjCObjectType *RHSObjTy = RhsT->getAs<ObjCObjectType>(); @@ -1645,8 +1645,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, return Self.BuiltinIsBaseOf(Rhs->getTypeLoc().getBeginLoc(), LhsT, RhsT); case BTT_IsVirtualBaseOf: { - const RecordType *BaseRecord = LhsT->getAs<RecordType>(); - const RecordType *DerivedRecord = RhsT->getAs<RecordType>(); + const RecordType *BaseRecord = LhsT->getAsCanonical<RecordType>(); + const RecordType *DerivedRecord = RhsT->getAsCanonical<RecordType>(); if (!BaseRecord || !DerivedRecord) { DiagnoseVLAInCXXTypeTrait(Self, Lhs, @@ -1766,7 +1766,10 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, // Objective-C lifetime, this is a non-trivial assignment. if (LhsT.getNonReferenceType().hasNonTrivialObjCLifetime()) return false; - + const ASTContext &Context = Self.getASTContext(); + if (Context.containsAddressDiscriminatedPointerAuth(LhsT) || + Context.containsAddressDiscriminatedPointerAuth(RhsT)) + return false; return !Result.get()->hasNonTrivialCall(Self.Context); } @@ -1824,6 +1827,51 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, return Self.HLSL().IsScalarizedLayoutCompatible(LhsT, RhsT); } + case BTT_LtSynthesisesFromSpaceship: + case BTT_LeSynthesisesFromSpaceship: + case BTT_GtSynthesisesFromSpaceship: + case BTT_GeSynthesisesFromSpaceship: { + EnterExpressionEvaluationContext UnevaluatedContext( + Self, Sema::ExpressionEvaluationContext::Unevaluated); + Sema::SFINAETrap SFINAE(Self, /*ForValidityCheck=*/true); + Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); + + OpaqueValueExpr LHS(KeyLoc, LhsT.getNonReferenceType(), + LhsT->isLValueReferenceType() ? ExprValueKind::VK_LValue + : LhsT->isRValueReferenceType() + ? ExprValueKind::VK_XValue + : ExprValueKind::VK_PRValue); + OpaqueValueExpr RHS(KeyLoc, RhsT.getNonReferenceType(), + RhsT->isLValueReferenceType() ? ExprValueKind::VK_LValue + : RhsT->isRValueReferenceType() + ? ExprValueKind::VK_XValue + : ExprValueKind::VK_PRValue); + + auto OpKind = [&] { + switch (BTT) { + case BTT_LtSynthesisesFromSpaceship: + return BinaryOperatorKind::BO_LT; + case BTT_LeSynthesisesFromSpaceship: + return BinaryOperatorKind::BO_LE; + case BTT_GtSynthesisesFromSpaceship: + return BinaryOperatorKind::BO_GT; + case BTT_GeSynthesisesFromSpaceship: + return BinaryOperatorKind::BO_GE; + default: + llvm_unreachable("Trying to Synthesize non-comparison operator?"); + } + }(); + + UnresolvedSet<16> Functions; + Self.LookupBinOp(Self.TUScope, KeyLoc, OpKind, Functions); + + ExprResult Result = + Self.CreateOverloadedBinOp(KeyLoc, OpKind, Functions, &LHS, &RHS); + if (Result.isInvalid() || SFINAE.hasErrorOccurred()) + return false; + + return isa<CXXRewrittenBinaryOperator>(Result.get()); + } default: llvm_unreachable("not a BTT"); } @@ -1963,6 +2011,7 @@ static std::optional<TypeTrait> StdNameToTypeTrait(StringRef Name) { .Case("is_assignable", TypeTrait::BTT_IsAssignable) .Case("is_empty", TypeTrait::UTT_IsEmpty) .Case("is_standard_layout", TypeTrait::UTT_IsStandardLayout) + .Case("is_aggregate", TypeTrait::UTT_IsAggregate) .Case("is_constructible", TypeTrait::TT_IsConstructible) .Case("is_final", TypeTrait::UTT_IsFinal) .Default(std::nullopt); @@ -2639,6 +2688,92 @@ static void DiagnoseNonStandardLayoutReason(Sema &SemaRef, SourceLocation Loc, SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D; } +static void DiagnoseNonAggregateReason(Sema &SemaRef, SourceLocation Loc, + const CXXRecordDecl *D) { + for (const CXXConstructorDecl *Ctor : D->ctors()) { + if (Ctor->isUserProvided()) + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::UserDeclaredCtr; + if (Ctor->isInheritingConstructor()) + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::InheritedCtr; + } + + if (llvm::any_of(D->decls(), [](auto const *Sub) { + return isa<ConstructorUsingShadowDecl>(Sub); + })) { + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::InheritedCtr; + } + + if (D->isPolymorphic()) + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::PolymorphicType + << D->getSourceRange(); + + for (const CXXBaseSpecifier &B : D->bases()) { + if (B.isVirtual()) { + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::VBase << B.getType() + << B.getSourceRange(); + continue; + } + auto AccessSpecifier = B.getAccessSpecifier(); + switch (AccessSpecifier) { + case AS_private: + case AS_protected: + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::PrivateProtectedDirectBase + << (AccessSpecifier == AS_protected); + break; + default: + break; + } + } + + for (const CXXMethodDecl *Method : D->methods()) { + if (Method->isVirtual()) { + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::VirtualFunction << Method + << Method->getSourceRange(); + } + } + + for (const FieldDecl *Field : D->fields()) { + auto AccessSpecifier = Field->getAccess(); + switch (AccessSpecifier) { + case AS_private: + case AS_protected: + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::PrivateProtectedDirectDataMember + << (AccessSpecifier == AS_protected); + break; + default: + break; + } + } + + SemaRef.Diag(D->getLocation(), diag::note_defined_here) << D; +} + +static void DiagnoseNonAggregateReason(Sema &SemaRef, SourceLocation Loc, + QualType T) { + SemaRef.Diag(Loc, diag::note_unsatisfied_trait) + << T << diag::TraitName::Aggregate; + + if (T->isVoidType()) + SemaRef.Diag(Loc, diag::note_unsatisfied_trait_reason) + << diag::TraitNotSatisfiedReason::CVVoidType; + + T = T.getNonReferenceType(); + const CXXRecordDecl *D = T->getAsCXXRecordDecl(); + if (!D || D->isInvalidDecl()) + return; + + if (D->hasDefinition()) + DiagnoseNonAggregateReason(SemaRef, Loc, D); +} + void Sema::DiagnoseTypeTraitDetails(const Expr *E) { E = E->IgnoreParenImpCasts(); if (E->containsErrors()) @@ -2671,6 +2806,9 @@ void Sema::DiagnoseTypeTraitDetails(const Expr *E) { case TT_IsConstructible: DiagnoseNonConstructibleReason(*this, E->getBeginLoc(), Args); break; + case UTT_IsAggregate: + DiagnoseNonAggregateReason(*this, E->getBeginLoc(), Args[0]); + break; case UTT_IsFinal: { QualType QT = Args[0]; if (QT->isDependentType()) diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 1d14ead77844..0587a7decbd8 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -744,11 +744,6 @@ public: StmtResult TransformSEHHandler(Stmt *Handler); - QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL, - TemplateName Template, - CXXScopeSpec &SS); - QualType TransformDependentTemplateSpecializationType( TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, QualType ObjectType, NamedDecl *UnqualLookup, @@ -1315,9 +1310,8 @@ public: /// /// By default, builds the new template name directly. Subclasses may override /// this routine to provide different behavior. - TemplateName RebuildTemplateName(CXXScopeSpec &SS, - bool TemplateKW, - TemplateDecl *Template); + TemplateName RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW, + TemplateName Name); /// Build a new template name given a nested name specifier and the /// name that is referred to as a template. @@ -4822,9 +4816,7 @@ TemplateName TreeTransform<Derived>::TransformTemplateName( TemplateName Name, SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) { if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { - // FIXME: Preserve UsingTemplateName. - TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl(); - assert(Template && "qualified template name must refer to a template"); + TemplateName UnderlyingName = QTN->getUnderlyingTemplate(); if (QualifierLoc) { QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( @@ -4833,20 +4825,22 @@ TemplateName TreeTransform<Derived>::TransformTemplateName( return TemplateName(); } - TemplateDecl *TransTemplate - = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc, - Template)); - if (!TransTemplate) + NestedNameSpecifierLoc UnderlyingQualifier; + TemplateName NewUnderlyingName = getDerived().TransformTemplateName( + UnderlyingQualifier, TemplateKWLoc, UnderlyingName, NameLoc, ObjectType, + FirstQualifierInScope, AllowInjectedClassName); + if (NewUnderlyingName.isNull()) return TemplateName(); + assert(!UnderlyingQualifier && "unexpected qualifier"); if (!getDerived().AlwaysRebuild() && QualifierLoc.getNestedNameSpecifier() == QTN->getQualifier() && - TransTemplate == Template) + NewUnderlyingName == UnderlyingName) return Name; CXXScopeSpec SS; SS.Adopt(QualifierLoc); return getDerived().RebuildTemplateName(SS, QTN->hasTemplateKeyword(), - TransTemplate); + NewUnderlyingName); } if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { @@ -4874,9 +4868,19 @@ TemplateName TreeTransform<Derived>::TransformTemplateName( if (SubstTemplateTemplateParmStorage *S = Name.getAsSubstTemplateTemplateParm()) { + assert(!QualifierLoc && "Unexpected qualified SubstTemplateTemplateParm"); + + NestedNameSpecifierLoc ReplacementQualifierLoc; + TemplateName ReplacementName = S->getReplacement(); + if (NestedNameSpecifier Qualifier = ReplacementName.getQualifier()) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(SemaRef.Context, Qualifier, NameLoc); + ReplacementQualifierLoc = Builder.getWithLocInContext(SemaRef.Context); + } + TemplateName NewName = getDerived().TransformTemplateName( - QualifierLoc, TemplateKWLoc, S->getReplacement(), NameLoc, ObjectType, - FirstQualifierInScope, AllowInjectedClassName); + ReplacementQualifierLoc, TemplateKWLoc, ReplacementName, NameLoc, + ObjectType, FirstQualifierInScope, AllowInjectedClassName); if (NewName.isNull()) return TemplateName(); Decl *AssociatedDecl = @@ -4892,21 +4896,17 @@ TemplateName TreeTransform<Derived>::TransformTemplateName( assert(!Name.getAsDeducedTemplateName() && "DeducedTemplateName should not escape partial ordering"); - if (TemplateDecl *Template = Name.getAsTemplateDecl()) { - assert(!QualifierLoc && "missed a Qualified Template"); - TemplateDecl *TransTemplate - = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc, - Template)); - if (!TransTemplate) - return TemplateName(); - - CXXScopeSpec SS; - return getDerived().RebuildTemplateName(SS, /*TemplateKeyword=*/false, - TransTemplate); + // FIXME: Preserve UsingTemplateName. + if (auto *Template = Name.getAsTemplateDecl()) { + assert(!QualifierLoc && "Unexpected qualifier"); + return TemplateName(cast_or_null<TemplateDecl>( + getDerived().TransformDecl(NameLoc, Template))); } if (SubstTemplateTemplateParmPackStorage *SubstPack = Name.getAsSubstTemplateTemplateParmPack()) { + assert(!QualifierLoc && + "Unexpected qualified SubstTemplateTemplateParmPack"); return getDerived().RebuildTemplateName( SubstPack->getArgumentPack(), SubstPack->getAssociatedDecl(), SubstPack->getIndex(), SubstPack->getFinal()); @@ -5539,21 +5539,10 @@ QualType TreeTransform<Derived>::TransformTypeInObjectScope( TLB, TL.castAs<DependentNameTypeLoc>(), /*DeducedTSTContext=*/false, ObjectType, UnqualLookup); } - case TypeLoc::Typedef: - case TypeLoc::TemplateSpecialization: - case TypeLoc::SubstTemplateTypeParm: - case TypeLoc::SubstTemplateTypeParmPack: - case TypeLoc::PackIndexing: - case TypeLoc::Enum: - case TypeLoc::Record: - case TypeLoc::InjectedClassName: - case TypeLoc::TemplateTypeParm: - case TypeLoc::Decltype: - case TypeLoc::UnresolvedUsing: - case TypeLoc::Using: - return getDerived().TransformType(TLB, TL); default: - llvm_unreachable("unexpected type class"); + // Any dependent canonical type can appear here, through type alias + // templates. + return getDerived().TransformType(TLB, TL); } } @@ -8559,13 +8548,31 @@ TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) { template<typename Derived> StmtResult TreeTransform<Derived>::TransformContinueStmt(ContinueStmt *S) { - return S; + if (!S->hasLabelTarget()) + return S; + + Decl *LD = getDerived().TransformDecl(S->getLabelDecl()->getLocation(), + S->getLabelDecl()); + if (!LD) + return StmtError(); + + return new (SemaRef.Context) + ContinueStmt(S->getKwLoc(), S->getLabelLoc(), cast<LabelDecl>(LD)); } template<typename Derived> StmtResult TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) { - return S; + if (!S->hasLabelTarget()) + return S; + + Decl *LD = getDerived().TransformDecl(S->getLabelDecl()->getLocation(), + S->getLabelDecl()); + if (!LD) + return StmtError(); + + return new (SemaRef.Context) + BreakStmt(S->getKwLoc(), S->getLabelLoc(), cast<LabelDecl>(LD)); } template<typename Derived> @@ -10964,8 +10971,7 @@ TreeTransform<Derived>::TransformOMPMessageClause(OMPMessageClause *C) { if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPMessageClause( - C->getMessageString(), C->getBeginLoc(), C->getLParenLoc(), - C->getEndLoc()); + E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } template <typename Derived> @@ -11897,7 +11903,7 @@ template <typename Derived> void OpenACCClauseTransform<Derived>::VisitPrivateClause( const OpenACCPrivateClause &C) { llvm::SmallVector<Expr *> InstantiatedVarList; - llvm::SmallVector<VarDecl *> InitRecipes; + llvm::SmallVector<OpenACCPrivateRecipe> InitRecipes; for (const auto [RefExpr, InitRecipe] : llvm::zip(C.getVarList(), C.getInitRecipes())) { @@ -11908,14 +11914,11 @@ void OpenACCClauseTransform<Derived>::VisitPrivateClause( // We only have to create a new one if it is dependent, and Sema won't // make one of these unless the type is non-dependent. - if (InitRecipe) + if (InitRecipe.isSet()) InitRecipes.push_back(InitRecipe); else InitRecipes.push_back( - Self.getSema() - .OpenACC() - .CreateInitRecipe(OpenACCClauseKind::Private, VarRef.get()) - .first); + Self.getSema().OpenACC().CreatePrivateInitRecipe(VarRef.get())); } } ParsedClause.setVarListDetails(InstantiatedVarList, @@ -11966,11 +11969,12 @@ void OpenACCClauseTransform<Derived>::VisitFirstPrivateClause( // We only have to create a new one if it is dependent, and Sema won't // make one of these unless the type is non-dependent. - if (InitRecipe.RecipeDecl) + if (InitRecipe.isSet()) InitRecipes.push_back(InitRecipe); else - InitRecipes.push_back(Self.getSema().OpenACC().CreateInitRecipe( - OpenACCClauseKind::FirstPrivate, VarRef.get())); + InitRecipes.push_back( + Self.getSema().OpenACC().CreateFirstPrivateInitRecipe( + VarRef.get())); } } ParsedClause.setVarListDetails(InstantiatedVarList, @@ -12428,27 +12432,18 @@ void OpenACCClauseTransform<Derived>::VisitReductionClause( SmallVector<Expr *> ValidVars; llvm::SmallVector<OpenACCReductionRecipe> Recipes; - for (const auto [Var, OrigRecipes] : + for (const auto [Var, OrigRecipe] : llvm::zip(TransformedVars, C.getRecipes())) { ExprResult Res = Self.getSema().OpenACC().CheckReductionVar( ParsedClause.getDirectiveKind(), C.getReductionOp(), Var); if (Res.isUsable()) { ValidVars.push_back(Res.get()); - // TODO OpenACC: When the recipe changes, make sure we get these right - // too. We probably need something similar for the operation. - static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int*)); - VarDecl *InitRecipe = nullptr; - if (OrigRecipes.RecipeDecl) - InitRecipe = OrigRecipes.RecipeDecl; - else - InitRecipe = - Self.getSema() - .OpenACC() - .CreateInitRecipe(OpenACCClauseKind::Reduction, Res.get()) - .first; - - Recipes.push_back({InitRecipe}); + if (OrigRecipe.isSet()) + Recipes.push_back(OrigRecipe); + else + Recipes.push_back(Self.getSema().OpenACC().CreateReductionInitRecipe( + C.getReductionOp(), Res.get())); } } @@ -14380,9 +14375,9 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { Expr *Op = E->getExprOperand(); auto EvalCtx = Sema::ExpressionEvaluationContext::Unevaluated; if (E->isGLValue()) - if (auto *RecordT = Op->getType()->getAs<RecordType>()) - if (cast<CXXRecordDecl>(RecordT->getOriginalDecl())->isPolymorphic()) - EvalCtx = SemaRef.ExprEvalContexts.back().Context; + if (auto *RD = Op->getType()->getAsCXXRecordDecl(); + RD && RD->isPolymorphic()) + EvalCtx = SemaRef.ExprEvalContexts.back().Context; EnterExpressionEvaluationContext Unevaluated(SemaRef, EvalCtx, Sema::ReuseLambdaContextDecl); @@ -14623,12 +14618,9 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { if (E->isArray() && !E->getAllocatedType()->isDependentType()) { QualType ElementType = SemaRef.Context.getBaseElementType(E->getAllocatedType()); - if (const RecordType *RecordT = ElementType->getAs<RecordType>()) { - CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordT->getOriginalDecl()) - ->getDefinitionOrSelf(); - if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) { + if (CXXRecordDecl *Record = ElementType->getAsCXXRecordDecl()) { + if (CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(Record)) SemaRef.MarkFunctionReferenced(E->getBeginLoc(), Destructor); - } } } @@ -14694,13 +14686,9 @@ TreeTransform<Derived>::TransformCXXDeleteExpr(CXXDeleteExpr *E) { if (!E->getArgument()->isTypeDependent()) { QualType Destroyed = SemaRef.Context.getBaseElementType( E->getDestroyedType()); - if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) { - CXXRecordDecl *Record = - cast<CXXRecordDecl>(DestroyedRec->getOriginalDecl()) - ->getDefinitionOrSelf(); + if (auto *Record = Destroyed->getAsCXXRecordDecl()) SemaRef.MarkFunctionReferenced(E->getBeginLoc(), SemaRef.LookupDestructor(Record)); - } } return E; @@ -17515,13 +17503,12 @@ QualType TreeTransform<Derived>::RebuildDependentBitIntType( return SemaRef.BuildBitIntType(IsUnsigned, NumBitsExpr, Loc); } -template<typename Derived> -TemplateName -TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, - bool TemplateKW, - TemplateDecl *Template) { +template <typename Derived> +TemplateName TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, + bool TemplateKW, + TemplateName Name) { return SemaRef.Context.getQualifiedTemplateName(SS.getScopeRep(), TemplateKW, - TemplateName(Template)); + Name); } template <typename Derived> @@ -17650,12 +17637,13 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage Destroyed) { - QualType BaseType = Base->getType(); + QualType CanonicalBaseType = Base->getType().getCanonicalType(); if (Base->isTypeDependent() || Destroyed.getIdentifier() || - (!isArrow && !BaseType->getAs<RecordType>()) || - (isArrow && BaseType->getAs<PointerType>() && - !BaseType->castAs<PointerType>()->getPointeeType() - ->template getAs<RecordType>())){ + (!isArrow && !isa<RecordType>(CanonicalBaseType)) || + (isArrow && isa<PointerType>(CanonicalBaseType) && + !cast<PointerType>(CanonicalBaseType) + ->getPointeeType() + ->getAsCanonical<RecordType>())) { // This pseudo-destructor expression is still a pseudo-destructor. return SemaRef.BuildPseudoDestructorExpr( Base, OperatorLoc, isArrow ? tok::arrow : tok::period, SS, ScopeType, @@ -17682,13 +17670,11 @@ TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base, } SourceLocation TemplateKWLoc; // FIXME: retrieve it from caller. - return getSema().BuildMemberReferenceExpr(Base, BaseType, - OperatorLoc, isArrow, - SS, TemplateKWLoc, - /*FIXME: FirstQualifier*/ nullptr, - NameInfo, - /*TemplateArgs*/ nullptr, - /*S*/nullptr); + return getSema().BuildMemberReferenceExpr( + Base, Base->getType(), OperatorLoc, isArrow, SS, TemplateKWLoc, + /*FIXME: FirstQualifier*/ nullptr, NameInfo, + /*TemplateArgs*/ nullptr, + /*S*/ nullptr); } template<typename Derived> diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h index ad475ab0f42a..546b3a9e66e2 100644 --- a/clang/lib/Sema/UsedDeclVisitor.h +++ b/clang/lib/Sema/UsedDeclVisitor.h @@ -70,12 +70,10 @@ public: QualType DestroyedOrNull = E->getDestroyedType(); if (!DestroyedOrNull.isNull()) { QualType Destroyed = S.Context.getBaseElementType(DestroyedOrNull); - if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) { - CXXRecordDecl *Record = - cast<CXXRecordDecl>(DestroyedRec->getOriginalDecl()); - if (auto *Def = Record->getDefinition()) - asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Def)); - } + if (auto *Record = Destroyed->getAsCXXRecordDecl(); + Record && + (Record->isBeingDefined() || Record->isCompleteDefinition())) + asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Record)); } Inherited::VisitCXXDeleteExpr(E); |
