diff options
Diffstat (limited to 'clang/lib/Sema')
55 files changed, 10603 insertions, 5038 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 9780a0aba749..4530154ac944 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -16,8 +16,10 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/OperationKinds.h" #include "clang/AST/ParentMap.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtCXX.h" @@ -29,6 +31,7 @@ #include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/ThreadSafety.h" #include "clang/Analysis/Analyses/UninitializedValues.h" +#include "clang/Analysis/Analyses/UnsafeBufferUsage.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CFGStmtMap.h" @@ -47,6 +50,7 @@ #include <algorithm> #include <deque> #include <iterator> +#include <optional> using namespace clang; @@ -326,7 +330,7 @@ static void visitReachableThrows( if (!Reachable[B->getBlockID()]) continue; for (CFGElement &E : *B) { - Optional<CFGStmt> S = E.getAs<CFGStmt>(); + std::optional<CFGStmt> S = E.getAs<CFGStmt>(); if (!S) continue; if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt())) @@ -1113,19 +1117,19 @@ namespace { if (!ReachableBlocks.count(P)) { for (const CFGElement &Elem : llvm::reverse(*P)) { - if (Optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) { - if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) { - // Don't issue a warning for an unreachable fallthrough - // attribute in template instantiations as it may not be - // unreachable in all instantiations of the template. - if (!IsTemplateInstantiation) - S.Diag(AS->getBeginLoc(), - diag::warn_unreachable_fallthrough_attr); - markFallthroughVisited(AS); - ++AnnotatedCnt; - break; - } - // Don't care about other unreachable statements. + if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) { + if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) { + // Don't issue a warning for an unreachable fallthrough + // attribute in template instantiations as it may not be + // unreachable in all instantiations of the template. + if (!IsTemplateInstantiation) + S.Diag(AS->getBeginLoc(), + diag::warn_unreachable_fallthrough_attr); + markFallthroughVisited(AS); + ++AnnotatedCnt; + break; + } + // Don't care about other unreachable statements. } } // If there are no unreachable statements, this may be a special @@ -1198,7 +1202,7 @@ namespace { if (const Stmt *Term = B.getTerminatorStmt()) return Term; for (const CFGElement &Elem : llvm::reverse(B)) - if (Optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) + if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) return CS->getStmt(); // Workaround to detect a statement thrown out by CFGBuilder: // case X: {} case Y: @@ -2139,6 +2143,71 @@ public: } // namespace clang //===----------------------------------------------------------------------===// +// Unsafe buffer usage analysis. +//===----------------------------------------------------------------------===// + +namespace { +class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler { + Sema &S; + +public: + UnsafeBufferUsageReporter(Sema &S) : S(S) {} + + void handleUnsafeOperation(const Stmt *Operation, + bool IsRelatedToDecl) override { + SourceLocation Loc; + SourceRange Range; + unsigned MsgParam = 0; + if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(Operation)) { + Loc = ASE->getBase()->getExprLoc(); + Range = ASE->getBase()->getSourceRange(); + MsgParam = 2; + } else if (const auto *BO = dyn_cast<BinaryOperator>(Operation)) { + BinaryOperator::Opcode Op = BO->getOpcode(); + if (Op == BO_Add || Op == BO_AddAssign || Op == BO_Sub || + Op == BO_SubAssign) { + if (BO->getRHS()->getType()->isIntegerType()) { + Loc = BO->getLHS()->getExprLoc(); + Range = BO->getLHS()->getSourceRange(); + } else { + Loc = BO->getRHS()->getExprLoc(); + Range = BO->getRHS()->getSourceRange(); + } + MsgParam = 1; + } + } else if (const auto *UO = dyn_cast<UnaryOperator>(Operation)) { + UnaryOperator::Opcode Op = UO->getOpcode(); + if (Op == UO_PreInc || Op == UO_PreDec || Op == UO_PostInc || + Op == UO_PostDec) { + Loc = UO->getSubExpr()->getExprLoc(); + Range = UO->getSubExpr()->getSourceRange(); + MsgParam = 1; + } + } else { + Loc = Operation->getBeginLoc(); + Range = Operation->getSourceRange(); + } + if (IsRelatedToDecl) + S.Diag(Loc, diag::note_unsafe_buffer_operation) << MsgParam << Range; + else + S.Diag(Loc, diag::warn_unsafe_buffer_operation) << MsgParam << Range; + } + + // FIXME: rename to handleUnsafeVariable + void handleFixableVariable(const VarDecl *Variable, + FixItList &&Fixes) override { + const auto &D = + S.Diag(Variable->getLocation(), diag::warn_unsafe_buffer_variable); + D << Variable; + D << (Variable->getType()->isPointerType() ? 0 : 1); + D << Variable->getSourceRange(); + for (const auto &F : Fixes) + D << F; + } +}; +} // namespace + +//===----------------------------------------------------------------------===// // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based // warnings on a function, method, or block. //===----------------------------------------------------------------------===// @@ -2269,7 +2338,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( } // Install the logical handler. - llvm::Optional<LogicalErrorHandler> LEH; + std::optional<LogicalErrorHandler> LEH; if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { LEH.emplace(S); AC.getCFGBuildOptions().Observer = &*LEH; @@ -2430,6 +2499,13 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( if (S.getLangOpts().CPlusPlus && isNoexcept(FD)) checkThrowInNonThrowingFunc(S, FD, AC); + // Emit unsafe buffer usage warnings and fixits. + if (!Diags.isIgnored(diag::warn_unsafe_buffer_operation, D->getBeginLoc()) || + !Diags.isIgnored(diag::warn_unsafe_buffer_variable, D->getBeginLoc())) { + UnsafeBufferUsageReporter R(S); + checkUnsafeBufferUsage(D, R); + } + // If none of the previous checks caused a CFG build, trigger one here // for the logical error handler. if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index e93be3e04dfe..b91291cfea0b 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -776,7 +776,7 @@ void CodeCompletionResult::computeCursorKindAndAvailability(bool Accessible) { // Do nothing: Patterns can come with cursor kinds! break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case RK_Declaration: { // Set the availability based on attributes. diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index d4dc790c008a..d59778b5b614 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -18,6 +18,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Sema.h" @@ -238,7 +239,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, // is already used (consider a function returning a function pointer) or too // small (function with too many parameters), go to the heap. if (!TheDeclarator.InlineStorageUsed && - NumParams <= llvm::array_lengthof(TheDeclarator.InlineParams)) { + NumParams <= std::size(TheDeclarator.InlineParams)) { I.Fun.Params = TheDeclarator.InlineParams; new (I.Fun.Params) ParamInfo[NumParams]; I.Fun.DeleteParams = false; @@ -307,8 +308,7 @@ void Declarator::setDecompositionBindings( // Allocate storage for bindings and stash them away. if (Bindings.size()) { - if (!InlineStorageUsed && - Bindings.size() <= llvm::array_lengthof(InlineBindings)) { + if (!InlineStorageUsed && Bindings.size() <= std::size(InlineBindings)) { BindingGroup.Bindings = InlineBindings; BindingGroup.DeleteBindings = false; InlineStorageUsed = true; @@ -384,13 +384,16 @@ bool Declarator::isDeclarationOfFunction() const { return false; case TST_decltype: + case TST_typeof_unqualExpr: case TST_typeofExpr: if (Expr *E = DS.getRepAsExpr()) return E->getType()->isFunctionType(); return false; - case TST_underlyingType: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait: +#include "clang/Basic/TransformTypeTraits.def" case TST_typename: + case TST_typeof_unqualType: case TST_typeofType: { QualType QT = DS.getRepAsType().get(); if (QT.isNull()) @@ -412,7 +415,7 @@ bool Declarator::isDeclarationOfFunction() const { bool Declarator::isStaticMember() { assert(getContext() == DeclaratorContext::Member); return getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static || - (getName().Kind == UnqualifiedIdKind::IK_OperatorFunctionId && + (getName().getKind() == UnqualifiedIdKind::IK_OperatorFunctionId && CXXMethodDecl::isStaticOverloadedOperator( getName().OperatorFunctionId.Operator)); } @@ -572,11 +575,16 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T, case DeclSpec::TST_typename: return "type-name"; case DeclSpec::TST_typeofType: case DeclSpec::TST_typeofExpr: return "typeof"; + case DeclSpec::TST_typeof_unqualType: + case DeclSpec::TST_typeof_unqualExpr: return "typeof_unqual"; case DeclSpec::TST_auto: return "auto"; case DeclSpec::TST_auto_type: return "__auto_type"; case DeclSpec::TST_decltype: return "(decltype)"; case DeclSpec::TST_decltype_auto: return "decltype(auto)"; - case DeclSpec::TST_underlyingType: return "__underlying_type"; +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \ + case DeclSpec::TST_##Trait: \ + return "__" #Trait; +#include "clang/Basic/TransformTypeTraits.def" case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_atomic: return "_Atomic"; case DeclSpec::TST_BFloat16: return "__bf16"; @@ -1109,9 +1117,8 @@ void DeclSpec::SaveWrittenBuiltinSpecs() { } /// Finish - This does final analysis of the declspec, rejecting things like -/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or -/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, -/// DeclSpec is guaranteed self-consistent, even if an error occurred. +/// "_Imaginary" (lacking an FP type). After calling this method, DeclSpec is +/// guaranteed to be self-consistent, even if an error occurred. void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 56c2dd40bd9a..3ff4e75b5694 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -11,24 +11,391 @@ #include "clang/Sema/HLSLExternalSemaSource.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/Basic/AttrKinds.h" +#include "clang/Basic/HLSLRuntime.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" +#include "llvm/Frontend/HLSL/HLSLResource.h" + +#include <functional> using namespace clang; +using namespace llvm::hlsl; + +namespace { + +struct TemplateParameterListBuilder; + +struct BuiltinTypeDeclBuilder { + CXXRecordDecl *Record = nullptr; + ClassTemplateDecl *Template = nullptr; + ClassTemplateDecl *PrevTemplate = nullptr; + NamespaceDecl *HLSLNamespace = nullptr; + llvm::StringMap<FieldDecl *> Fields; + + BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) { + Record->startDefinition(); + Template = Record->getDescribedClassTemplate(); + } + + BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name) + : HLSLNamespace(Namespace) { + ASTContext &AST = S.getASTContext(); + IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); + + LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName); + CXXRecordDecl *PrevDecl = nullptr; + if (S.LookupQualifiedName(Result, HLSLNamespace)) { + NamedDecl *Found = Result.getFoundDecl(); + if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) { + PrevDecl = TD->getTemplatedDecl(); + PrevTemplate = TD; + } else + PrevDecl = dyn_cast<CXXRecordDecl>(Found); + assert(PrevDecl && "Unexpected lookup result type."); + } + + if (PrevDecl && PrevDecl->isCompleteDefinition()) { + Record = PrevDecl; + return; + } + + Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::TTK_Class, + HLSLNamespace, SourceLocation(), + SourceLocation(), &II, PrevDecl, true); + Record->setImplicit(true); + Record->setLexicalDeclContext(HLSLNamespace); + Record->setHasExternalLexicalStorage(); + + // Don't let anyone derive from built-in types. + Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(), + AttributeCommonInfo::AS_Keyword, + FinalAttr::Keyword_final)); + } + + ~BuiltinTypeDeclBuilder() { + if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace) + HLSLNamespace->addDecl(Record); + } + + BuiltinTypeDeclBuilder & + addMemberVariable(StringRef Name, QualType Type, + AccessSpecifier Access = AccessSpecifier::AS_private) { + if (Record->isCompleteDefinition()) + return *this; + assert(Record->isBeingDefined() && + "Definition must be started before adding members!"); + ASTContext &AST = Record->getASTContext(); + + IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); + TypeSourceInfo *MemTySource = + AST.getTrivialTypeSourceInfo(Type, SourceLocation()); + auto *Field = FieldDecl::Create( + AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource, + nullptr, false, InClassInitStyle::ICIS_NoInit); + Field->setAccess(Access); + Field->setImplicit(true); + Record->addDecl(Field); + Fields[Name] = Field; + return *this; + } + + BuiltinTypeDeclBuilder & + addHandleMember(AccessSpecifier Access = AccessSpecifier::AS_private) { + if (Record->isCompleteDefinition()) + return *this; + QualType Ty = Record->getASTContext().VoidPtrTy; + if (Template) { + if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>( + Template->getTemplateParameters()->getParam(0))) + Ty = Record->getASTContext().getPointerType( + QualType(TTD->getTypeForDecl(), 0)); + } + return addMemberVariable("h", Ty, Access); + } + + BuiltinTypeDeclBuilder & + annotateResourceClass(HLSLResourceAttr::ResourceClass RC, + HLSLResourceAttr::ResourceKind RK) { + if (Record->isCompleteDefinition()) + return *this; + Record->addAttr( + HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RC, RK)); + return *this; + } + + static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S, + StringRef Name) { + CXXScopeSpec SS; + IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); + DeclarationNameInfo NameInfo = + DeclarationNameInfo(DeclarationName(&II), SourceLocation()); + LookupResult R(S, NameInfo, Sema::LookupOrdinaryName); + S.LookupParsedName(R, S.getCurScope(), &SS, false); + assert(R.isSingleResult() && + "Since this is a builtin it should always resolve!"); + auto *VD = cast<ValueDecl>(R.getFoundDecl()); + QualType Ty = VD->getType(); + return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(), + VD, false, NameInfo, Ty, VK_PRValue); + } + + static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) { + return IntegerLiteral::Create( + AST, + llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy), + static_cast<uint8_t>(RC)), + AST.UnsignedCharTy, SourceLocation()); + } + + BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S, + ResourceClass RC) { + if (Record->isCompleteDefinition()) + return *this; + ASTContext &AST = Record->getASTContext(); + + QualType ConstructorType = + AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo()); + + CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified(); + DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy); + CXXConstructorDecl *Constructor = CXXConstructorDecl::Create( + AST, Record, SourceLocation(), + DeclarationNameInfo(Name, SourceLocation()), ConstructorType, + AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()), + ExplicitSpecifier(), false, true, false, + ConstexprSpecKind::Unspecified); + + DeclRefExpr *Fn = + lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle"); + + Expr *RCExpr = emitResourceClassExpr(AST, RC); + Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue, + SourceLocation(), FPOptionsOverride()); + + CXXThisExpr *This = new (AST) CXXThisExpr( + SourceLocation(), + Constructor->getThisType().getTypePtr()->getPointeeType(), true); + This->setValueKind(ExprValueKind::VK_LValue); + Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"], + Fields["h"]->getType(), VK_LValue, + OK_Ordinary); + + // If the handle isn't a void pointer, cast the builtin result to the + // correct type. + if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) { + Call = CXXStaticCastExpr::Create( + AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr, + AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()), + FPOptionsOverride(), SourceLocation(), SourceLocation(), + SourceRange()); + } + + BinaryOperator *Assign = BinaryOperator::Create( + AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary, + SourceLocation(), FPOptionsOverride()); + + Constructor->setBody( + CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(), + SourceLocation(), SourceLocation())); + Constructor->setAccess(AccessSpecifier::AS_public); + Record->addDecl(Constructor); + return *this; + } + + BuiltinTypeDeclBuilder &addArraySubscriptOperators() { + if (Record->isCompleteDefinition()) + return *this; + addArraySubscriptOperator(true); + addArraySubscriptOperator(false); + return *this; + } + + BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) { + if (Record->isCompleteDefinition()) + return *this; + assert(Fields.count("h") > 0 && + "Subscript operator must be added after the handle."); + + FieldDecl *Handle = Fields["h"]; + ASTContext &AST = Record->getASTContext(); + + assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy && + "Not yet supported for void pointer handles."); + + QualType ElemTy = + QualType(Handle->getType()->getPointeeOrArrayElementType(), 0); + QualType ReturnTy = ElemTy; + + FunctionProtoType::ExtProtoInfo ExtInfo; + + // Subscript operators return references to elements, const makes the + // reference and method const so that the underlying data is not mutable. + ReturnTy = AST.getLValueReferenceType(ReturnTy); + if (IsConst) { + ExtInfo.TypeQuals.addConst(); + ReturnTy.addConst(); + } + + QualType MethodTy = + AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo); + auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation()); + auto *MethodDecl = CXXMethodDecl::Create( + AST, Record, SourceLocation(), + DeclarationNameInfo( + AST.DeclarationNames.getCXXOperatorName(OO_Subscript), + SourceLocation()), + MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified, + SourceLocation()); + + IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier); + auto *IdxParam = ParmVarDecl::Create( + AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(), + &II, AST.UnsignedIntTy, + AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()), + SC_None, nullptr); + MethodDecl->setParams({IdxParam}); + + // Also add the parameter to the function prototype. + auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>(); + FnProtoLoc.setParam(0, IdxParam); + + auto *This = new (AST) CXXThisExpr( + SourceLocation(), + MethodDecl->getThisType().getTypePtr()->getPointeeType(), true); + This->setValueKind(ExprValueKind::VK_LValue); + auto *HandleAccess = MemberExpr::CreateImplicit( + AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary); + + auto *IndexExpr = DeclRefExpr::Create( + AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false, + DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()), + AST.UnsignedIntTy, VK_PRValue); + + auto *Array = + new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue, + OK_Ordinary, SourceLocation()); + + auto *Return = ReturnStmt::Create(AST, SourceLocation(), Array, nullptr); + + MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(), + SourceLocation(), + SourceLocation())); + MethodDecl->setLexicalDeclContext(Record); + MethodDecl->setAccess(AccessSpecifier::AS_public); + MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit( + AST, SourceRange(), AttributeCommonInfo::AS_Keyword, + AlwaysInlineAttr::CXX11_clang_always_inline)); + Record->addDecl(MethodDecl); + + return *this; + } + + BuiltinTypeDeclBuilder &startDefinition() { + if (Record->isCompleteDefinition()) + return *this; + Record->startDefinition(); + return *this; + } + + BuiltinTypeDeclBuilder &completeDefinition() { + if (Record->isCompleteDefinition()) + return *this; + assert(Record->isBeingDefined() && + "Definition must be started before completing it."); + + Record->completeDefinition(); + return *this; + } + + TemplateParameterListBuilder addTemplateArgumentList(); +}; + +struct TemplateParameterListBuilder { + BuiltinTypeDeclBuilder &Builder; + ASTContext &AST; + llvm::SmallVector<NamedDecl *> Params; + + TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB) + : Builder(RB), AST(RB.Record->getASTContext()) {} + + ~TemplateParameterListBuilder() { finalizeTemplateArgs(); } + + TemplateParameterListBuilder & + addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) { + if (Builder.Record->isCompleteDefinition()) + return *this; + unsigned Position = static_cast<unsigned>(Params.size()); + auto *Decl = TemplateTypeParmDecl::Create( + AST, Builder.Record->getDeclContext(), SourceLocation(), + SourceLocation(), /* TemplateDepth */ 0, Position, + &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ false, + /* ParameterPack */ false); + if (!DefaultValue.isNull()) + Decl->setDefaultArgument(AST.getTrivialTypeSourceInfo(DefaultValue)); + + Params.emplace_back(Decl); + return *this; + } + + BuiltinTypeDeclBuilder &finalizeTemplateArgs() { + if (Params.empty()) + return Builder; + auto *ParamList = + TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(), + Params, SourceLocation(), nullptr); + Builder.Template = ClassTemplateDecl::Create( + AST, Builder.Record->getDeclContext(), SourceLocation(), + DeclarationName(Builder.Record->getIdentifier()), ParamList, + Builder.Record); + Builder.Record->setDescribedClassTemplate(Builder.Template); + Builder.Template->setImplicit(true); + Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext()); + // NOTE: setPreviousDecl before addDecl so new decl replace old decl when + // make visible. + Builder.Template->setPreviousDecl(Builder.PrevTemplate); + Builder.Record->getDeclContext()->addDecl(Builder.Template); + Params.clear(); + + QualType T = Builder.Template->getInjectedClassNameSpecialization(); + T = AST.getInjectedClassNameType(Builder.Record, T); + + return Builder; + } +}; + +TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() { + return TemplateParameterListBuilder(*this); +} +} // namespace HLSLExternalSemaSource::~HLSLExternalSemaSource() {} void HLSLExternalSemaSource::InitializeSema(Sema &S) { SemaPtr = &S; ASTContext &AST = SemaPtr->getASTContext(); + // If the translation unit has external storage force external decls to load. + if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage()) + (void)AST.getTranslationUnitDecl()->decls_begin(); + IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier); - HLSLNamespace = - NamespaceDecl::Create(AST, AST.getTranslationUnitDecl(), false, - SourceLocation(), SourceLocation(), &HLSL, nullptr); + LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName); + NamespaceDecl *PrevDecl = nullptr; + if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl())) + PrevDecl = Result.getAsSingle<NamespaceDecl>(); + HLSLNamespace = NamespaceDecl::Create( + AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(), + SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false); HLSLNamespace->setImplicit(true); + HLSLNamespace->setHasExternalLexicalStorage(); AST.getTranslationUnitDecl()->addDecl(HLSLNamespace); - defineHLSLVectorAlias(); + + // Force external decls in the HLSL namespace to load from the PCH. + (void)HLSLNamespace->getCanonicalDecl()->decls_begin(); + defineTrivialHLSLTypes(); + forwardDeclareHLSLTypes(); // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's // built in types inside a namespace, but we are planning to change that in @@ -94,3 +461,53 @@ void HLSLExternalSemaSource::defineHLSLVectorAlias() { Template->setLexicalDeclContext(Record->getDeclContext()); HLSLNamespace->addDecl(Template); } + +void HLSLExternalSemaSource::defineTrivialHLSLTypes() { + defineHLSLVectorAlias(); + + ResourceDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Resource") + .startDefinition() + .addHandleMember(AccessSpecifier::AS_public) + .completeDefinition() + .Record; +} + +void HLSLExternalSemaSource::forwardDeclareHLSLTypes() { + CXXRecordDecl *Decl; + Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer") + .addTemplateArgumentList() + .addTypeParameter("element_type", SemaPtr->getASTContext().FloatTy) + .finalizeTemplateArgs() + .Record; + if (!Decl->isCompleteDefinition()) + Completions.insert( + std::make_pair(Decl->getCanonicalDecl(), + std::bind(&HLSLExternalSemaSource::completeBufferType, + this, std::placeholders::_1))); +} + +void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) { + if (!isa<CXXRecordDecl>(Tag)) + return; + auto Record = cast<CXXRecordDecl>(Tag); + + // If this is a specialization, we need to get the underlying templated + // declaration and complete that. + if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record)) + Record = TDecl->getSpecializedTemplate()->getTemplatedDecl(); + Record = Record->getCanonicalDecl(); + auto It = Completions.find(Record); + if (It == Completions.end()) + return; + It->second(Record); +} + +void HLSLExternalSemaSource::completeBufferType(CXXRecordDecl *Record) { + BuiltinTypeDeclBuilder(Record) + .addHandleMember() + .addDefaultHandleConstructor(*SemaPtr, ResourceClass::UAV) + .addArraySubscriptOperators() + .annotateResourceClass(HLSLResourceAttr::UAV, + HLSLResourceAttr::TypedBuffer) + .completeDefinition(); +} diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp index 9081714c893f..607dc3111e9d 100644 --- a/clang/lib/Sema/IdentifierResolver.cpp +++ b/clang/lib/Sema/IdentifierResolver.cpp @@ -99,7 +99,11 @@ IdentifierResolver::~IdentifierResolver() { bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S, bool AllowInlineNamespace) const { Ctx = Ctx->getRedeclContext(); - + // The names for HLSL cbuffer/tbuffers only used by the CPU-side + // reflection API which supports querying bindings. It will not have name + // conflict with other Decls. + if (LangOpt.HLSL && isa<HLSLBufferDecl>(D)) + return false; if (Ctx->isFunctionOrMethod() || (S && S->isFunctionPrototypeScope())) { // Ignore the scopes associated within transparent declaration contexts. while (S->getEntity() && S->getEntity()->isTransparentContext()) @@ -287,7 +291,7 @@ static DeclMatchKind compareDeclarations(NamedDecl *Existing, NamedDecl *New) { // If the existing declaration is somewhere in the previous declaration // chain of the new declaration, then prefer the new declaration. - for (auto RD : New->redecls()) { + for (auto *RD : New->redecls()) { if (RD == Existing) return DMK_Replace; diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index 94f39e1eea6e..bd2ce9a93e7e 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -354,7 +354,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, BuildScopeInformation(Var, ParentScope); ++StmtsToSkip; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Stmt::GotoStmtClass: // Remember both what scope a goto is in as well as the fact that we have diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 072775642d75..55e015487f3b 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -16,24 +16,30 @@ using namespace clang; char MultiplexExternalSemaSource::ID; -///Constructs a new multiplexing external sema source and appends the +/// Constructs a new multiplexing external sema source and appends the /// given element to it. /// -MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1, - ExternalSemaSource &s2){ - Sources.push_back(&s1); - Sources.push_back(&s2); +MultiplexExternalSemaSource::MultiplexExternalSemaSource( + ExternalSemaSource *S1, ExternalSemaSource *S2) { + S1->Retain(); + S2->Retain(); + Sources.push_back(S1); + Sources.push_back(S2); } // pin the vtable here. -MultiplexExternalSemaSource::~MultiplexExternalSemaSource() {} +MultiplexExternalSemaSource::~MultiplexExternalSemaSource() { + for (auto *S : Sources) + S->Release(); +} -///Appends new source to the source list. +/// Appends new source to the source list. /// ///\param[in] source - An ExternalSemaSource. /// -void MultiplexExternalSemaSource::addSource(ExternalSemaSource &source) { - Sources.push_back(&source); +void MultiplexExternalSemaSource::AddSource(ExternalSemaSource *Source) { + Source->Retain(); + Sources.push_back(Source); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td index dc158454556a..0cceba090bd8 100644 --- a/clang/lib/Sema/OpenCLBuiltins.td +++ b/clang/lib/Sema/OpenCLBuiltins.td @@ -246,6 +246,7 @@ class ImageType<Type _Ty, string _AccessQualifier> : let Extension = !cond( !and(!eq(_Ty.Name, "image3d_t"), !eq(_AccessQualifier, "WO")) : TypeExtension<"cl_khr_3d_image_writes">, !and(!eq(_Ty.Name, "image3d_t"), !eq(_AccessQualifier, "RW")) : TypeExtension<"cl_khr_3d_image_writes __opencl_c_read_write_images">, + !or(!eq(_Ty.Name, "image2d_depth_t"), !eq(_Ty.Name, "image2d_array_depth_t")) : TypeExtension<"cl_khr_depth_images">, !eq(_AccessQualifier, "RW") : TypeExtension<"__opencl_c_read_write_images">, true : _Ty.Extension); } diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index 4b9a694270c5..c1e39acb14ec 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -111,7 +111,7 @@ namespace { const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { // If we have a ParsedAttrInfo for this ParsedAttr then return that. - if ((size_t)A.getParsedKind() < llvm::array_lengthof(AttrInfoMap)) + if ((size_t)A.getParsedKind() < std::size(AttrInfoMap)) return *AttrInfoMap[A.getParsedKind()]; // If this is an ignored attribute then return an appropriate ParsedAttrInfo. @@ -146,7 +146,7 @@ const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { } ArrayRef<const ParsedAttrInfo *> ParsedAttrInfo::getAllBuiltin() { - return llvm::makeArrayRef(AttrInfoMap); + return llvm::ArrayRef(AttrInfoMap); } unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp index 98260226dfd3..c995c7e65f4b 100644 --- a/clang/lib/Sema/Scope.cpp +++ b/clang/lib/Sema/Scope.cpp @@ -43,6 +43,9 @@ void Scope::setFlags(Scope *parent, unsigned flags) { FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) == 0) Flags |= parent->getFlags() & OpenMPSimdDirectiveScope; + // transmit the parent's 'order' flag, if exists + if (parent->getFlags() & OpenMPOrderClauseScope) + Flags |= OpenMPOrderClauseScope; } else { Depth = 0; PrototypeDepth = 0; @@ -91,7 +94,7 @@ void Scope::Init(Scope *parent, unsigned flags) { UsingDirectives.clear(); Entity = nullptr; ErrorTrap.reset(); - NRVO = None; + NRVO = std::nullopt; } bool Scope::containedInPrototypeScope() const { @@ -156,11 +159,11 @@ void Scope::updateNRVOCandidate(VarDecl *VD) { void Scope::applyNRVO() { // There is no NRVO candidate in the current scope. - if (!NRVO.hasValue()) + if (!NRVO.has_value()) return; if (*NRVO && isDeclScope(*NRVO)) - NRVO.getValue()->setNRVOVariable(true); + (*NRVO)->setNRVOVariable(true); // It's necessary to propagate NRVO candidate to the parent scope for cases // when the parent scope doesn't contain a return statement. diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp index cc7de16de2fd..e313052b3ab3 100644 --- a/clang/lib/Sema/ScopeInfo.cpp +++ b/clang/lib/Sema/ScopeInfo.cpp @@ -56,6 +56,7 @@ void FunctionScopeInfo::Clear() { ModifiedNonNullParams.clear(); Blocks.clear(); ByrefBlockVars.clear(); + AddrLabels.clear(); } static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) { @@ -231,14 +232,14 @@ bool CapturingScopeInfo::isVLATypeCaptured(const VariableArrayType *VAT) const { } void LambdaScopeInfo::visitPotentialCaptures( - llvm::function_ref<void(VarDecl *, Expr *)> Callback) const { + llvm::function_ref<void(ValueDecl *, Expr *)> Callback) const { for (Expr *E : PotentiallyCapturingExprs) { if (auto *DRE = dyn_cast<DeclRefExpr>(E)) { - Callback(cast<VarDecl>(DRE->getFoundDecl()), E); + Callback(cast<ValueDecl>(DRE->getFoundDecl()), E); } else if (auto *ME = dyn_cast<MemberExpr>(E)) { - Callback(cast<VarDecl>(ME->getMemberDecl()), E); + Callback(cast<ValueDecl>(ME->getMemberDecl()), E); } else if (auto *FP = dyn_cast<FunctionParmPackExpr>(E)) { - for (VarDecl *VD : *FP) + for (ValueDecl *VD : *FP) Callback(VD, E); } else { llvm_unreachable("unexpected expression in potential captures list"); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 08957ce9fada..0f0305422454 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -46,8 +46,10 @@ #include "clang/Sema/TemplateInstCallback.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/TimeProfiler.h" +#include <optional> using namespace clang; using namespace sema; @@ -185,20 +187,19 @@ const uint64_t Sema::MaximumAlignment; Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) - : ExternalSource(nullptr), isMultiplexExternalSource(false), - CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), - Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), - SourceMgr(PP.getSourceManager()), CollectStats(false), - CodeCompleter(CodeCompleter), CurContext(nullptr), + : ExternalSource(nullptr), CurFPFeatures(pp.getLangOpts()), + LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer), + Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), + CollectStats(false), CodeCompleter(CodeCompleter), CurContext(nullptr), OriginalLexicalContext(nullptr), MSStructPragmaOn(false), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), VtorDispStack(LangOpts.getVtorDispMode()), AlignPackStack(AlignPackInfo(getLangOpts().XLPragmaPack)), DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr), - CodeSegStack(nullptr), FpPragmaStack(FPOptionsOverride()), - CurInitSeg(nullptr), VisContext(nullptr), - PragmaAttributeCurrentTargetDecl(nullptr), + CodeSegStack(nullptr), StrictGuardStackCheckStack(false), + FpPragmaStack(FPOptionsOverride()), CurInitSeg(nullptr), + VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr), IsBuildingRecoveryCallExpr(false), LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr), @@ -473,10 +474,6 @@ Sema::~Sema() { = dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource())) ExternalSema->ForgetSema(); - // If Sema's ExternalSource is the multiplexer - we own it. - if (isMultiplexExternalSource) - delete ExternalSource; - // Delete cached satisfactions. std::vector<ConstraintSatisfaction *> Satisfactions; Satisfactions.reserve(Satisfactions.size()); @@ -550,12 +547,10 @@ void Sema::addExternalSource(ExternalSemaSource *E) { return; } - if (isMultiplexExternalSource) - static_cast<MultiplexExternalSemaSource*>(ExternalSource)->addSource(*E); - else { - ExternalSource = new MultiplexExternalSemaSource(*ExternalSource, *E); - isMultiplexExternalSource = true; - } + if (auto *Ex = dyn_cast<MultiplexExternalSemaSource>(ExternalSource)) + Ex->AddSource(E); + else + ExternalSource = new MultiplexExternalSemaSource(ExternalSource.get(), E); } /// Print out statistics about the semantic analysis. @@ -570,22 +565,19 @@ void Sema::PrintStats() const { void Sema::diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, SourceLocation Loc) { - Optional<NullabilityKind> ExprNullability = SrcType->getNullability(Context); + std::optional<NullabilityKind> ExprNullability = SrcType->getNullability(); if (!ExprNullability || (*ExprNullability != NullabilityKind::Nullable && *ExprNullability != NullabilityKind::NullableResult)) return; - Optional<NullabilityKind> TypeNullability = DstType->getNullability(Context); + std::optional<NullabilityKind> TypeNullability = DstType->getNullability(); if (!TypeNullability || *TypeNullability != NullabilityKind::NonNull) return; Diag(Loc, diag::warn_nullability_lost) << SrcType << DstType; } -void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) { - if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant, - E->getBeginLoc())) - return; +void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr *E) { // nullptr only exists from C++11 on, so don't warn on its absence earlier. if (!getLangOpts().CPlusPlus11) return; @@ -595,6 +587,10 @@ void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) { if (E->IgnoreParenImpCasts()->getType()->isNullPtrType()) return; + if (Diags.isIgnored(diag::warn_zero_as_null_pointer_constant, + E->getBeginLoc())) + return; + // Don't diagnose the conversion from a 0 literal to a null pointer argument // in a synthesized call to operator<=>. if (!CodeSynthesisContexts.empty() && @@ -602,6 +598,12 @@ void Sema::diagnoseZeroToNullptrConversion(CastKind Kind, const Expr* E) { CodeSynthesisContext::RewritingOperatorAsSpaceship) return; + // Ignore null pointers in defaulted comparison operators. + FunctionDecl *FD = getCurFunctionDecl(); + if (FD && FD->isDefaulted()) { + return; + } + // If it is a macro from system header, and if the macro name is not "NULL", // do not warn. SourceLocation MaybeMacroLoc = E->getBeginLoc(); @@ -1216,9 +1218,7 @@ void Sema::ActOnEndOfTranslationUnit() { // module declaration by now. if (getLangOpts().getCompilingModule() == LangOptions::CMK_ModuleInterface && - (ModuleScopes.empty() || - !ModuleScopes.back().Module->isModulePurview()) && - !DiagnosedMissingModuleDeclaration) { + !isCurrentModulePurview() && !DiagnosedMissingModuleDeclaration) { // FIXME: Make a better guess as to where to put the module declaration. Diag(getSourceManager().getLocForStartOfFile( getSourceManager().getMainFileID()), @@ -1253,6 +1253,33 @@ void Sema::ActOnEndOfTranslationUnit() { emitAndClearUnusedLocalTypedefWarnings(); } + // C++ standard modules. Diagnose cases where a function is declared inline + // in the module purview but has no definition before the end of the TU or + // the start of a Private Module Fragment (if one is present). + if (!PendingInlineFuncDecls.empty()) { + for (auto *D : PendingInlineFuncDecls) { + if (auto *FD = dyn_cast<FunctionDecl>(D)) { + bool DefInPMF = false; + if (auto *FDD = FD->getDefinition()) { + assert(FDD->getOwningModule() && + FDD->getOwningModule()->isModulePurview()); + DefInPMF = FDD->getOwningModule()->isPrivateModule(); + if (!DefInPMF) + continue; + } + Diag(FD->getLocation(), diag::err_export_inline_not_defined) + << DefInPMF; + // If we have a PMF it should be at the end of the ModuleScopes. + if (DefInPMF && + ModuleScopes.back().Module->Kind == Module::PrivateModuleFragment) { + Diag(ModuleScopes.back().BeginLoc, + diag::note_private_module_fragment); + } + } + } + PendingInlineFuncDecls.clear(); + } + // C99 6.9.2p2: // A declaration of an identifier for an object that has file // scope without an initializer, and without a storage-class @@ -1266,8 +1293,8 @@ void Sema::ActOnEndOfTranslationUnit() { // translation unit, with an initializer equal to 0. llvm::SmallSet<VarDecl *, 32> Seen; for (TentativeDefinitionsType::iterator - T = TentativeDefinitions.begin(ExternalSource), - TEnd = TentativeDefinitions.end(); + T = TentativeDefinitions.begin(ExternalSource.get()), + TEnd = TentativeDefinitions.end(); T != TEnd; ++T) { VarDecl *VD = (*T)->getActingDefinition(); @@ -1297,7 +1324,7 @@ void Sema::ActOnEndOfTranslationUnit() { Consumer.CompleteTentativeDefinition(VD); } - for (auto D : ExternalDeclarations) { + for (auto *D : ExternalDeclarations) { if (!D || D->isInvalidDecl() || D->getPreviousDecl() || !D->isUsed()) continue; @@ -1311,8 +1338,9 @@ void Sema::ActOnEndOfTranslationUnit() { if (!Diags.hasErrorOccurred() && TUKind != TU_Module) { // Output warning for unused file scoped decls. for (UnusedFileScopedDeclsType::iterator - I = UnusedFileScopedDecls.begin(ExternalSource), - E = UnusedFileScopedDecls.end(); I != E; ++I) { + I = UnusedFileScopedDecls.begin(ExternalSource.get()), + E = UnusedFileScopedDecls.end(); + I != E; ++I) { if (ShouldRemoveFromUnused(this, *I)) continue; @@ -1470,7 +1498,7 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { // eliminated. If it truly cannot be (for example, there is some reentrancy // issue I am not seeing yet), then there should at least be a clarifying // comment somewhere. - if (Optional<TemplateDeductionInfo*> Info = isSFINAEContext()) { + if (std::optional<TemplateDeductionInfo *> Info = isSFINAEContext()) { switch (DiagnosticIDs::getDiagnosticSFINAEResponse( Diags.getCurrentDiagID())) { case DiagnosticIDs::SFINAE_Report: @@ -1765,7 +1793,7 @@ void Sema::emitDeferredDiags() { return; DeferredDiagnosticsEmitter DDE(*this); - for (auto D : DeclsToCheckForDeferredDiags) + for (auto *D : DeclsToCheckForDeferredDiags) DDE.checkRecordedDecl(D); } @@ -2008,6 +2036,15 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { if (D) targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; } + + // Don't allow SVE types in functions without a SVE target. + if (Ty->isSVESizelessBuiltinType() && FD && FD->hasBody()) { + llvm::StringMap<bool> CallerFeatureMap; + Context.getFunctionFeatureMap(CallerFeatureMap, FD); + if (!Builtin::evaluateRequiredTargetFeatures( + "sve", CallerFeatureMap)) + Diag(D->getLocation(), diag::err_sve_vector_in_non_sve_target) << Ty; + } }; CheckType(Ty); @@ -2448,7 +2485,7 @@ bool Sema::tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, if (IsMemExpr && !E.isTypeDependent()) { Sema::TentativeAnalysisScope Trap(*this); ExprResult R = BuildCallToMemberFunction(nullptr, &E, SourceLocation(), - None, SourceLocation()); + std::nullopt, SourceLocation()); if (R.isUsable()) { ZeroArgCallReturnTy = R.get()->getType(); return true; @@ -2512,6 +2549,9 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads, if (FD->isMultiVersion() && FD->hasAttr<TargetAttr>() && !FD->getAttr<TargetAttr>()->isDefaultVersion()) continue; + if (FD->isMultiVersion() && FD->hasAttr<TargetVersionAttr>() && + !FD->getAttr<TargetVersionAttr>()->isDefaultVersion()) + continue; } S.Diag(Fn->getLocation(), diag::note_possible_target_of_call); ++ShownOverloads; @@ -2598,7 +2638,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, // FIXME: Try this before emitting the fixit, and suppress diagnostics // while doing so. - E = BuildCallExpr(nullptr, E.get(), Range.getEnd(), None, + E = BuildCallExpr(nullptr, E.get(), Range.getEnd(), std::nullopt, Range.getEnd().getLocWithOffset(1)); return true; } @@ -2659,3 +2699,26 @@ Sema::FPFeaturesStateRAII::~FPFeaturesStateRAII() { S.FpPragmaStack.CurrentValue = OldOverrides; S.PP.setCurrentFPEvalMethod(OldFPPragmaLocation, OldEvalMethod); } + +bool Sema::isDeclaratorFunctionLike(Declarator &D) { + assert(D.getCXXScopeSpec().isSet() && + "can only be called for qualified names"); + + auto LR = LookupResult(*this, D.getIdentifier(), D.getBeginLoc(), + LookupOrdinaryName, forRedeclarationInCurContext()); + DeclContext *DC = computeDeclContext(D.getCXXScopeSpec(), + !D.getDeclSpec().isFriendSpecified()); + if (!DC) + return false; + + LookupQualifiedName(LR, DC); + bool Result = std::all_of(LR.begin(), LR.end(), [](Decl *Dcl) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(Dcl)) { + ND = ND->getUnderlyingDecl(); + return isa<FunctionDecl>(ND) || isa<FunctionTemplateDecl>(ND) || + isa<UsingDecl>(ND); + } + return false; + }); + return Result; +} diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index 00d3efd19d7a..cbda62497e6a 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -1493,6 +1493,8 @@ void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *D) { } else if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) { if (isa<DeclContext>(TD->getTemplatedDecl())) DC = cast<DeclContext>(TD->getTemplatedDecl()); + } else if (auto *RD = dyn_cast<RequiresExprBodyDecl>(D)) { + DC = RD; } EffectiveContext EC(DC); diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index c997d018a406..42f582724564 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -18,6 +18,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/SemaInternal.h" +#include <optional> using namespace clang; //===----------------------------------------------------------------------===// @@ -34,6 +35,7 @@ Sema::PragmaStackSentinelRAII::PragmaStackSentinelRAII(Sema &S, S.BSSSegStack.SentinelAction(PSK_Push, SlotLabel); S.ConstSegStack.SentinelAction(PSK_Push, SlotLabel); S.CodeSegStack.SentinelAction(PSK_Push, SlotLabel); + S.StrictGuardStackCheckStack.SentinelAction(PSK_Push, SlotLabel); } } @@ -44,6 +46,7 @@ Sema::PragmaStackSentinelRAII::~PragmaStackSentinelRAII() { S.BSSSegStack.SentinelAction(PSK_Pop, SlotLabel); S.ConstSegStack.SentinelAction(PSK_Pop, SlotLabel); S.CodeSegStack.SentinelAction(PSK_Pop, SlotLabel); + S.StrictGuardStackCheckStack.SentinelAction(PSK_Pop, SlotLabel); } } @@ -335,7 +338,7 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, AlignPackInfo::Mode ModeVal = CurVal.getAlignMode(); if (Alignment) { - Optional<llvm::APSInt> Val; + std::optional<llvm::APSInt> Val; Val = Alignment->getIntegerConstantExpr(Context); // pack(0) is like pack(), which just works out since that is what @@ -774,6 +777,17 @@ void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation, Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName); } +/// Called on well formed \#pragma strict_gs_check(). +void Sema::ActOnPragmaMSStrictGuardStackCheck(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + bool Value) { + if (Action & PSK_Pop && StrictGuardStackCheckStack.Stack.empty()) + Diag(PragmaLocation, diag::warn_pragma_pop_failed) << "strict_gs_check" + << "stack empty"; + + StrictGuardStackCheckStack.Act(PragmaLocation, Action, StringRef(), Value); +} + /// Called on well formed \#pragma bss_seg(). void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation, int SectionFlags, StringLiteral *SegmentName) { @@ -872,12 +886,12 @@ void Sema::AddCFAuditedAttribute(Decl *D) { namespace { -Optional<attr::SubjectMatchRule> +std::optional<attr::SubjectMatchRule> getParentAttrMatcherRule(attr::SubjectMatchRule Rule) { using namespace attr; switch (Rule) { default: - return None; + return std::nullopt; #define ATTR_MATCH_RULE(Value, Spelling, IsAbstract) #define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \ case Value: \ @@ -947,7 +961,7 @@ void Sema::ActOnPragmaAttributeAttribute( RulesToFirstSpecifiedNegatedSubRule; for (const auto &Rule : Rules) { attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first); - Optional<attr::SubjectMatchRule> ParentRule = + std::optional<attr::SubjectMatchRule> ParentRule = getParentAttrMatcherRule(MatchRule); if (!ParentRule) continue; @@ -971,7 +985,7 @@ void Sema::ActOnPragmaAttributeAttribute( bool IgnoreNegatedSubRules = false; for (const auto &Rule : Rules) { attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first); - Optional<attr::SubjectMatchRule> ParentRule = + std::optional<attr::SubjectMatchRule> ParentRule = getParentAttrMatcherRule(MatchRule); if (!ParentRule) continue; diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index bf4a226668f7..05ad42780e50 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -19,6 +19,7 @@ #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" +#include <optional> using namespace clang; using namespace sema; @@ -192,6 +193,9 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context, case llvm::Triple::MacOSX: ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13); break; + case llvm::Triple::ShaderModel: + // Always enable availability diagnostics for shader models. + return true; default: // New targets should always warn about availability. return Triple.getVendor() == llvm::Triple::Apple; @@ -241,16 +245,16 @@ struct AttributeInsertion { /// attribute argument. /// \param SlotNames The vector that will be populated with slot names. In case /// of unsuccessful parsing can contain invalid data. -/// \returns A number of method parameters if parsing was successful, None -/// otherwise. -static Optional<unsigned> +/// \returns A number of method parameters if parsing was successful, +/// std::nullopt otherwise. +static std::optional<unsigned> tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames, const LangOptions &LangOpts) { // Accept replacements starting with - or + as valid ObjC method names. if (!Name.empty() && (Name.front() == '-' || Name.front() == '+')) Name = Name.drop_front(1); if (Name.empty()) - return None; + return std::nullopt; Name.split(SlotNames, ':'); unsigned NumParams; if (Name.back() == ':') { @@ -260,7 +264,7 @@ tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames, } else { if (SlotNames.size() != 1) // Not a valid method name, just a colon-separated string. - return None; + return std::nullopt; NumParams = 0; } // Verify all slot names are valid. @@ -269,28 +273,28 @@ tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames, if (S.empty()) continue; if (!isValidAsciiIdentifier(S, AllowDollar)) - return None; + return std::nullopt; } return NumParams; } /// Returns a source location in which it's appropriate to insert a new /// attribute for the given declaration \D. -static Optional<AttributeInsertion> +static std::optional<AttributeInsertion> createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, const LangOptions &LangOpts) { if (isa<ObjCPropertyDecl>(D)) return AttributeInsertion::createInsertionAfter(D); if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { if (MD->hasBody()) - return None; + return std::nullopt; return AttributeInsertion::createInsertionAfter(D); } if (const auto *TD = dyn_cast<TagDecl>(D)) { SourceLocation Loc = Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts); if (Loc.isInvalid()) - return None; + return std::nullopt; // Insert after the 'struct'/whatever keyword. return AttributeInsertion::createInsertionAfter(Loc); } @@ -397,7 +401,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, return; if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE")) return; - Optional<AttributeInsertion> Insertion = createAttributeInsertion( + std::optional<AttributeInsertion> Insertion = createAttributeInsertion( Enclosing, S.getSourceManager(), S.getLangOpts()); if (!Insertion) return; @@ -499,7 +503,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) { Selector Sel = MethodDecl->getSelector(); SmallVector<StringRef, 12> SelectorSlotNames; - Optional<unsigned> NumParams = tryParseObjCMethodName( + std::optional<unsigned> NumParams = tryParseObjCMethodName( Replacement, SelectorSlotNames, S.getLangOpts()); if (NumParams && *NumParams == Sel.getNumArgs()) { assert(SelectorSlotNames.size() == Locs.size()); @@ -895,6 +899,11 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) { return; Body = FD->getBody(); + + if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) + for (const CXXCtorInitializer *CI : CD->inits()) + DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(CI->getInit()); + } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) Body = MD->getBody(); else if (auto *BD = dyn_cast<BlockDecl>(D)) diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index 0a49d72ba963..cfea6493ced7 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -22,8 +22,8 @@ #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" +#include <optional> using namespace clang; template <typename AttrT> static bool hasExplicitAttr(const VarDecl *D) { @@ -338,7 +338,7 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, if (!InClass || HasExplicitAttr) return false; - llvm::Optional<CUDAFunctionTarget> InferredTarget; + std::optional<CUDAFunctionTarget> InferredTarget; // We're going to invoke special member lookup; mark that these special // members are called from this one, and not from its caller. @@ -381,13 +381,12 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, InferredTarget = BaseMethodTarget; } else { bool ResolutionError = resolveCalleeCUDATargetConflict( - InferredTarget.value(), BaseMethodTarget, - InferredTarget.getPointer()); + *InferredTarget, BaseMethodTarget, &*InferredTarget); if (ResolutionError) { if (Diagnose) { Diag(ClassDecl->getLocation(), diag::note_implicit_member_target_infer_collision) - << (unsigned)CSM << InferredTarget.value() << BaseMethodTarget; + << (unsigned)CSM << *InferredTarget << BaseMethodTarget; } MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context)); return true; @@ -425,13 +424,12 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, InferredTarget = FieldMethodTarget; } else { bool ResolutionError = resolveCalleeCUDATargetConflict( - InferredTarget.value(), FieldMethodTarget, - InferredTarget.getPointer()); + *InferredTarget, FieldMethodTarget, &*InferredTarget); if (ResolutionError) { if (Diagnose) { Diag(ClassDecl->getLocation(), diag::note_implicit_member_target_infer_collision) - << (unsigned)CSM << InferredTarget.value() << FieldMethodTarget; + << (unsigned)CSM << *InferredTarget << FieldMethodTarget; } MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context)); return true; @@ -444,9 +442,9 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, // it's the least restrictive option that can be invoked from any target. bool NeedsH = true, NeedsD = true; if (InferredTarget) { - if (InferredTarget.value() == CFT_Device) + if (*InferredTarget == CFT_Device) NeedsH = false; - else if (InferredTarget.value() == CFT_Host) + else if (*InferredTarget == CFT_Host) NeedsD = false; } diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 3f8fedda7174..daa61ba45e8e 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -931,10 +931,9 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, // Handle a dependent template specialization for which we cannot resolve // the template name. assert(DTN->getQualifier() == SS.getScopeRep()); - QualType T = Context.getDependentTemplateSpecializationType(ETK_None, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + QualType T = Context.getDependentTemplateSpecializationType( + ETK_None, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Create source-location information for this type. TypeLocBuilder Builder; diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 7b5bc7ca80b1..9fd9369c9641 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -451,6 +451,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, case InitializationSequence::FK_ConstructorOverloadFailed: case InitializationSequence::FK_UserConversionOverloadFailed: + case InitializationSequence::FK_ParenthesizedListInitFailed: break; } @@ -1059,11 +1060,19 @@ static bool argTypeIsABIEquivalent(QualType SrcType, QualType DestType, return Context.hasSameUnqualifiedType(SrcType, DestType); } -static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr, - QualType DestType) { - if (Self.Diags.isIgnored(diag::warn_cast_function_type, - SrcExpr.get()->getExprLoc())) - return true; +static unsigned int checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr, + QualType DestType) { + unsigned int DiagID = 0; + const unsigned int DiagList[] = {diag::warn_cast_function_type_strict, + diag::warn_cast_function_type}; + for (auto ID : DiagList) { + if (!Self.Diags.isIgnored(ID, SrcExpr.get()->getExprLoc())) { + DiagID = ID; + break; + } + } + if (!DiagID) + return 0; QualType SrcType = SrcExpr.get()->getType(); const FunctionType *SrcFTy = nullptr; @@ -1078,10 +1087,17 @@ static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr, SrcFTy = SrcType->castAs<FunctionType>(); DstFTy = DestType.getNonReferenceType()->castAs<FunctionType>(); } else { - return true; + return 0; } assert(SrcFTy && DstFTy); + if (Self.Context.hasSameType(SrcFTy, DstFTy)) + return 0; + + // For strict checks, ensure we have an exact match. + if (DiagID == diag::warn_cast_function_type_strict) + return DiagID; + auto IsVoidVoid = [](const FunctionType *T) { if (!T->getReturnType()->isVoidType()) return false; @@ -1092,16 +1108,16 @@ static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr, // Skip if either function type is void(*)(void) if (IsVoidVoid(SrcFTy) || IsVoidVoid(DstFTy)) - return true; + return 0; // Check return type. if (!argTypeIsABIEquivalent(SrcFTy->getReturnType(), DstFTy->getReturnType(), Self.Context)) - return false; + return DiagID; // Check if either has unspecified number of parameters if (SrcFTy->isFunctionNoProtoType() || DstFTy->isFunctionNoProtoType()) - return true; + return 0; // Check parameter types. @@ -1114,19 +1130,19 @@ static bool checkCastFunctionType(Sema &Self, const ExprResult &SrcExpr, unsigned DstNumParams = DstFPTy->getNumParams(); if (NumParams > DstNumParams) { if (!DstFPTy->isVariadic()) - return false; + return DiagID; NumParams = DstNumParams; } else if (NumParams < DstNumParams) { if (!SrcFPTy->isVariadic()) - return false; + return DiagID; } for (unsigned i = 0; i < NumParams; ++i) if (!argTypeIsABIEquivalent(SrcFPTy->getParamType(i), DstFPTy->getParamType(i), Self.Context)) - return false; + return DiagID; - return true; + return 0; } /// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is @@ -1167,8 +1183,8 @@ void CastOperation::CheckReinterpretCast() { checkObjCConversion(Sema::CCK_OtherCast); DiagnoseReinterpretUpDownCast(Self, SrcExpr.get(), DestType, OpRange); - if (!checkCastFunctionType(Self, SrcExpr, DestType)) - Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type) + if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType)) + Self.Diag(OpRange.getBegin(), DiagID) << SrcExpr.get()->getType() << DestType << OpRange; } else { SrcExpr = ExprError(); @@ -2797,8 +2813,8 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, if (Kind == CK_BitCast) checkCastAlign(); - if (!checkCastFunctionType(Self, SrcExpr, DestType)) - Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type) + if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType)) + Self.Diag(OpRange.getBegin(), DiagID) << SrcExpr.get()->getType() << DestType << OpRange; } else { @@ -2985,6 +3001,37 @@ void CastOperation::CheckCStyleCast() { return; } + // C2x 6.5.4p4: + // The type nullptr_t shall not be converted to any type other than void, + // bool, or a pointer type. No type other than nullptr_t shall be converted + // to nullptr_t. + if (SrcType->isNullPtrType()) { + // FIXME: 6.3.2.4p2 says that nullptr_t can be converted to itself, but + // 6.5.4p4 is a constraint check and nullptr_t is not void, bool, or a + // pointer type. We're not going to diagnose that as a constraint violation. + if (!DestType->isVoidType() && !DestType->isBooleanType() && + !DestType->isPointerType() && !DestType->isNullPtrType()) { + Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_nullptr_cast) + << /*nullptr to type*/ 0 << DestType; + SrcExpr = ExprError(); + return; + } + if (!DestType->isNullPtrType()) { + // Implicitly cast from the null pointer type to the type of the + // destination. + CastKind CK = DestType->isPointerType() ? CK_NullToPointer : CK_BitCast; + SrcExpr = ImplicitCastExpr::Create(Self.Context, DestType, CK, + SrcExpr.get(), nullptr, VK_PRValue, + Self.CurFPFeatureOverrides()); + } + } + if (DestType->isNullPtrType() && !SrcType->isNullPtrType()) { + Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_nullptr_cast) + << /*type to nullptr*/ 1 << SrcType; + SrcExpr = ExprError(); + return; + } + if (DestType->isExtVectorType()) { SrcExpr = Self.CheckExtVectorCast(OpRange, DestType, SrcExpr.get(), Kind); return; @@ -3125,9 +3172,8 @@ void CastOperation::CheckCStyleCast() { } } - if (!checkCastFunctionType(Self, SrcExpr, DestType)) - Self.Diag(OpRange.getBegin(), diag::warn_cast_function_type) - << SrcType << DestType << OpRange; + if (unsigned DiagID = checkCastFunctionType(Self, SrcExpr, DestType)) + Self.Diag(OpRange.getBegin(), DiagID) << SrcType << DestType << OpRange; if (isa<PointerType>(SrcType) && isa<PointerType>(DestType)) { QualType SrcTy = cast<PointerType>(SrcType)->getPointeeType(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index dae51d0690e6..ea21171aaac6 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -67,8 +67,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -96,6 +94,7 @@ #include <cstdint> #include <functional> #include <limits> +#include <optional> #include <string> #include <tuple> #include <utility> @@ -128,6 +127,28 @@ static bool checkArgCountAtLeast(Sema &S, CallExpr *Call, << Call->getSourceRange(); } +/// Checks that a call expression's argument count is at most the desired +/// number. This is useful when doing custom type-checking on a variadic +/// function. Returns true on error. +static bool checkArgCountAtMost(Sema &S, CallExpr *Call, unsigned MaxArgCount) { + unsigned ArgCount = Call->getNumArgs(); + if (ArgCount <= MaxArgCount) + return false; + return S.Diag(Call->getEndLoc(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << MaxArgCount << ArgCount + << Call->getSourceRange(); +} + +/// Checks that a call expression's argument count is in the desired range. This +/// is useful when doing custom type-checking on a variadic function. Returns +/// true on error. +static bool checkArgCountRange(Sema &S, CallExpr *Call, unsigned MinArgCount, + unsigned MaxArgCount) { + return checkArgCountAtLeast(S, Call, MinArgCount) || + checkArgCountAtMost(S, Call, MaxArgCount); +} + /// Checks that a call expression's argument count is the desired number. /// This is useful when doing custom type-checking. Returns true on error. static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) { @@ -148,6 +169,20 @@ static bool checkArgCount(Sema &S, CallExpr *Call, unsigned DesiredArgCount) { << Call->getArg(1)->getSourceRange(); } +static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) { + if (Value->isTypeDependent()) + return false; + + InitializedEntity Entity = + InitializedEntity::InitializeParameter(S.Context, Ty, false); + ExprResult Result = + S.PerformCopyInitialization(Entity, SourceLocation(), Value); + if (Result.isInvalid()) + return true; + Value = Result.get(); + return false; +} + /// Check that the first argument to __builtin_annotation is an integer /// and the second argument is a non-wide string literal. static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) { @@ -760,7 +795,7 @@ class ScanfDiagnosticFormatHandler // Accepts the argument index (relative to the first destination index) of the // argument whose size we want. using ComputeSizeFunction = - llvm::function_ref<Optional<llvm::APSInt>(unsigned)>; + llvm::function_ref<std::optional<llvm::APSInt>(unsigned)>; // Accepts the argument index (relative to the first destination index), the // destination size, and the source size). @@ -800,7 +835,8 @@ public: unsigned SourceSize = FW.getConstantAmount() + NulByte; - Optional<llvm::APSInt> DestSizeAPS = ComputeSizeArgument(FS.getArgIndex()); + std::optional<llvm::APSInt> DestSizeAPS = + ComputeSizeArgument(FS.getArgIndex()); if (!DestSizeAPS) return true; @@ -1018,7 +1054,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, const TargetInfo &TI = getASTContext().getTargetInfo(); unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType()); - auto TranslateIndex = [&](unsigned Index) -> Optional<unsigned> { + auto TranslateIndex = [&](unsigned Index) -> std::optional<unsigned> { // If we refer to a diagnose_as_builtin attribute, we need to change the // argument index to refer to the arguments of the called function. Unless // the index is out of bounds, which presumably means it's a variadic @@ -1030,26 +1066,27 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, ? DABAttr->argIndices_begin()[Index] : Index - DABIndices + FD->getNumParams(); if (NewIndex >= TheCall->getNumArgs()) - return llvm::None; + return std::nullopt; return NewIndex; }; auto ComputeExplicitObjectSizeArgument = - [&](unsigned Index) -> Optional<llvm::APSInt> { - Optional<unsigned> IndexOptional = TranslateIndex(Index); + [&](unsigned Index) -> std::optional<llvm::APSInt> { + std::optional<unsigned> IndexOptional = TranslateIndex(Index); if (!IndexOptional) - return llvm::None; + return std::nullopt; unsigned NewIndex = *IndexOptional; Expr::EvalResult Result; Expr *SizeArg = TheCall->getArg(NewIndex); if (!SizeArg->EvaluateAsInt(Result, getASTContext())) - return llvm::None; + return std::nullopt; llvm::APSInt Integer = Result.Val.getInt(); Integer.setIsUnsigned(true); return Integer; }; - auto ComputeSizeArgument = [&](unsigned Index) -> Optional<llvm::APSInt> { + auto ComputeSizeArgument = + [&](unsigned Index) -> std::optional<llvm::APSInt> { // If the parameter has a pass_object_size attribute, then we should use its // (potentially) more strict checking mode. Otherwise, conservatively assume // type 0. @@ -1061,36 +1098,40 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, BOSType = POS->getType(); } - Optional<unsigned> IndexOptional = TranslateIndex(Index); + std::optional<unsigned> IndexOptional = TranslateIndex(Index); if (!IndexOptional) - return llvm::None; + return std::nullopt; unsigned NewIndex = *IndexOptional; + if (NewIndex >= TheCall->getNumArgs()) + return std::nullopt; + const Expr *ObjArg = TheCall->getArg(NewIndex); uint64_t Result; if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType)) - return llvm::None; + return std::nullopt; // Get the object size in the target's size_t width. return llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth); }; - auto ComputeStrLenArgument = [&](unsigned Index) -> Optional<llvm::APSInt> { - Optional<unsigned> IndexOptional = TranslateIndex(Index); + auto ComputeStrLenArgument = + [&](unsigned Index) -> std::optional<llvm::APSInt> { + std::optional<unsigned> IndexOptional = TranslateIndex(Index); if (!IndexOptional) - return llvm::None; + return std::nullopt; unsigned NewIndex = *IndexOptional; const Expr *ObjArg = TheCall->getArg(NewIndex); uint64_t Result; if (!ObjArg->tryEvaluateStrLen(Result, getASTContext())) - return llvm::None; + return std::nullopt; // Add 1 for null byte. return llvm::APSInt::getUnsigned(Result + 1).extOrTrunc(SizeTypeWidth); }; - Optional<llvm::APSInt> SourceSize; - Optional<llvm::APSInt> DestinationSize; + std::optional<llvm::APSInt> SourceSize; + std::optional<llvm::APSInt> DestinationSize; unsigned DiagID = 0; bool IsChkVariant = false; @@ -1869,18 +1910,18 @@ static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) { TheCall->setType(ParamTy); - auto DiagSelect = [&]() -> llvm::Optional<unsigned> { + auto DiagSelect = [&]() -> std::optional<unsigned> { if (!ParamTy->isPointerType()) return 0; if (ParamTy->isFunctionPointerType()) return 1; if (ParamTy->isVoidPointerType()) return 2; - return llvm::Optional<unsigned>{}; + return std::optional<unsigned>{}; }(); if (DiagSelect) { S.Diag(TheCall->getBeginLoc(), diag::err_builtin_launder_invalid_arg) - << DiagSelect.value() << TheCall->getSourceRange(); + << *DiagSelect << TheCall->getSourceRange(); return ExprError(); } @@ -1981,7 +2022,37 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case llvm::Triple::riscv32: case llvm::Triple::riscv64: return CheckRISCVBuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + return CheckLoongArchBuiltinFunctionCall(TI, BuiltinID, TheCall); + } +} + +// Check if \p Ty is a valid type for the elementwise math builtins. If it is +// not a valid type, emit an error message and return true. Otherwise return +// false. +static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc, + QualType Ty) { + if (!Ty->getAs<VectorType>() && !ConstantMatrixType::isValidElementType(Ty)) { + return S.Diag(Loc, diag::err_builtin_invalid_arg_type) + << 1 << /* vector, integer or float ty*/ 0 << Ty; + } + + return false; +} + +static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc, + QualType ArgTy, int ArgIndex) { + QualType EltTy = ArgTy; + if (auto *VecTy = EltTy->getAs<VectorType>()) + EltTy = VecTy->getElementType(); + + if (!EltTy->isRealFloatingType()) { + return S.Diag(Loc, diag::err_builtin_invalid_arg_type) + << ArgIndex << /* vector or float ty*/ 5 << ArgTy; } + + return false; } ExprResult @@ -2108,7 +2179,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_alloca_with_align_uninitialized: if (SemaBuiltinAllocaWithAlign(TheCall)) return ExprError(); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Builtin::BI__builtin_alloca: case Builtin::BI__builtin_alloca_uninitialized: Diag(TheCall->getBeginLoc(), diag::warn_alloca) @@ -2485,7 +2556,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; case Builtin::BI__builtin_os_log_format: Cleanup.setExprNeedsCleanups(true); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Builtin::BI__builtin_os_log_format_buffer_size: if (SemaBuiltinOSLogFormat(TheCall)) return ExprError(); @@ -2532,9 +2603,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // These builtins restrict the element type to floating point // types only. case Builtin::BI__builtin_elementwise_ceil: + case Builtin::BI__builtin_elementwise_cos: case Builtin::BI__builtin_elementwise_floor: case Builtin::BI__builtin_elementwise_roundeven: - case Builtin::BI__builtin_elementwise_trunc: { + case Builtin::BI__builtin_elementwise_sin: + case Builtin::BI__builtin_elementwise_trunc: + case Builtin::BI__builtin_elementwise_canonicalize: { if (PrepareBuiltinElementwiseMathOneArgCall(TheCall)) return ExprError(); @@ -2580,6 +2654,35 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinElementwiseMath(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_elementwise_copysign: { + if (checkArgCount(*this, TheCall, 2)) + return ExprError(); + + ExprResult Magnitude = UsualUnaryConversions(TheCall->getArg(0)); + ExprResult Sign = UsualUnaryConversions(TheCall->getArg(1)); + if (Magnitude.isInvalid() || Sign.isInvalid()) + return ExprError(); + + QualType MagnitudeTy = Magnitude.get()->getType(); + QualType SignTy = Sign.get()->getType(); + if (checkFPMathBuiltinElementType(*this, TheCall->getArg(0)->getBeginLoc(), + MagnitudeTy, 1) || + checkFPMathBuiltinElementType(*this, TheCall->getArg(1)->getBeginLoc(), + SignTy, 2)) { + return ExprError(); + } + + if (MagnitudeTy.getCanonicalType() != SignTy.getCanonicalType()) { + return Diag(Sign.get()->getBeginLoc(), + diag::err_typecheck_call_different_arg_types) + << MagnitudeTy << SignTy; + } + + TheCall->setArg(0, Magnitude.get()); + TheCall->setArg(1, Sign.get()); + TheCall->setType(Magnitude.get()->getType()); + break; + } case Builtin::BI__builtin_reduce_max: case Builtin::BI__builtin_reduce_min: { if (PrepareBuiltinReduceMathOneArgCall(TheCall)) @@ -3183,13 +3286,15 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 2) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 4, 0, 1); + SemaBuiltinConstantArgRange(TheCall, 2, 0, 3) || + SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) || + SemaBuiltinConstantArgRange(TheCall, 4, 0, 1); } if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || - BuiltinID == AArch64::BI__builtin_arm_wsr64) + BuiltinID == AArch64::BI__builtin_arm_wsr64 || + BuiltinID == AArch64::BI__builtin_arm_rsr128 || + BuiltinID == AArch64::BI__builtin_arm_wsr128) return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); // Memory Tagging Extensions (MTE) Intrinsics @@ -3338,7 +3443,7 @@ bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, // The second argument needs to be a constant int Expr *Arg = TheCall->getArg(1); - Optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context); + std::optional<llvm::APSInt> Value = Arg->getIntegerConstantExpr(Context); diag::kind kind; if (!Value) { if (BuiltinID == BPF::BI__builtin_preserve_field_info) @@ -3585,6 +3690,31 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, {{ 3, false, 1, 0 }} }, { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, {{ 3, false, 1, 0 }} }, + + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10, {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_128B, + {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx, + {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyhubs10_vxx_128B, + {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10, {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_128B, + {{ 2, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx, + {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_v6mpyvubs10_vxx_128B, + {{ 3, false, 2, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, {{ 3, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B, + {{ 3, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, {{ 2, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, {{ 3, false, 3, 0 }} }, + { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B, + {{ 3, false, 3, 0 }} }, }; // Use a dynamically initialized static to sort the table exactly once on @@ -3629,6 +3759,91 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, return CheckHexagonBuiltinArgument(BuiltinID, TheCall); } +bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { + switch (BuiltinID) { + default: + break; + case LoongArch::BI__builtin_loongarch_cacop_d: + if (!TI.hasFeature("64bit")) + return Diag(TheCall->getBeginLoc(), + diag::err_loongarch_builtin_requires_la64) + << TheCall->getSourceRange(); + LLVM_FALLTHROUGH; + case LoongArch::BI__builtin_loongarch_cacop_w: { + if (BuiltinID == LoongArch::BI__builtin_loongarch_cacop_w && + !TI.hasFeature("32bit")) + return Diag(TheCall->getBeginLoc(), + diag::err_loongarch_builtin_requires_la32) + << TheCall->getSourceRange(); + SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5)); + SemaBuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12), + llvm::maxIntN(12)); + break; + } + case LoongArch::BI__builtin_loongarch_crc_w_b_w: + case LoongArch::BI__builtin_loongarch_crc_w_h_w: + case LoongArch::BI__builtin_loongarch_crc_w_w_w: + case LoongArch::BI__builtin_loongarch_crc_w_d_w: + case LoongArch::BI__builtin_loongarch_crcc_w_b_w: + case LoongArch::BI__builtin_loongarch_crcc_w_h_w: + case LoongArch::BI__builtin_loongarch_crcc_w_w_w: + case LoongArch::BI__builtin_loongarch_crcc_w_d_w: + case LoongArch::BI__builtin_loongarch_iocsrrd_d: + case LoongArch::BI__builtin_loongarch_iocsrwr_d: + case LoongArch::BI__builtin_loongarch_asrtle_d: + case LoongArch::BI__builtin_loongarch_asrtgt_d: + if (!TI.hasFeature("64bit")) + return Diag(TheCall->getBeginLoc(), + diag::err_loongarch_builtin_requires_la64) + << TheCall->getSourceRange(); + break; + case LoongArch::BI__builtin_loongarch_break: + case LoongArch::BI__builtin_loongarch_dbar: + case LoongArch::BI__builtin_loongarch_ibar: + case LoongArch::BI__builtin_loongarch_syscall: + // Check if immediate is in [0, 32767]. + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 32767); + case LoongArch::BI__builtin_loongarch_csrrd_w: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383); + case LoongArch::BI__builtin_loongarch_csrwr_w: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383); + case LoongArch::BI__builtin_loongarch_csrxchg_w: + return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383); + case LoongArch::BI__builtin_loongarch_csrrd_d: + if (!TI.hasFeature("64bit")) + return Diag(TheCall->getBeginLoc(), + diag::err_loongarch_builtin_requires_la64) + << TheCall->getSourceRange(); + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383); + case LoongArch::BI__builtin_loongarch_csrwr_d: + if (!TI.hasFeature("64bit")) + return Diag(TheCall->getBeginLoc(), + diag::err_loongarch_builtin_requires_la64) + << TheCall->getSourceRange(); + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383); + case LoongArch::BI__builtin_loongarch_csrxchg_d: + if (!TI.hasFeature("64bit")) + return Diag(TheCall->getBeginLoc(), + diag::err_loongarch_builtin_requires_la64) + << TheCall->getSourceRange(); + return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383); + case LoongArch::BI__builtin_loongarch_lddir_d: + case LoongArch::BI__builtin_loongarch_ldpte_d: + if (!TI.hasFeature("64bit")) + return Diag(TheCall->getBeginLoc(), + diag::err_loongarch_builtin_requires_la64) + << TheCall->getSourceRange(); + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + case LoongArch::BI__builtin_loongarch_movfcsr2gr: + case LoongArch::BI__builtin_loongarch_movgr2fcsr: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2)); + } + + return false; +} + bool Sema::CheckMipsBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { return CheckMipsBuiltinCpu(TI, BuiltinID, TheCall) || @@ -4039,7 +4254,7 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_unpack_longdouble: if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 1)) return true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case PPC::BI__builtin_pack_longdouble: if (&TI.getLongDoubleFormat() != &llvm::APFloat::PPCDoubleDouble()) return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_requires_abi) @@ -4172,10 +4387,11 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, diag::err_ppc_builtin_requires_vsx); case PPC::BI__builtin_ppc_test_data_class: { // Check if the first argument of the __builtin_ppc_test_data_class call is - // valid. The argument must be either a 'float' or a 'double'. + // valid. The argument must be 'float' or 'double' or '__float128'. QualType ArgType = TheCall->getArg(0)->getType(); if (ArgType != QualType(Context.FloatTy) && - ArgType != QualType(Context.DoubleTy)) + ArgType != QualType(Context.DoubleTy) && + ArgType != QualType(Context.Float128Ty)) return Diag(TheCall->getBeginLoc(), diag::err_ppc_invalid_test_data_class_type); return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", @@ -4321,27 +4537,6 @@ bool Sema::CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum) { << Arg->getSourceRange(); } -static bool isRISCV32Builtin(unsigned BuiltinID) { - // These builtins only work on riscv32 targets. - switch (BuiltinID) { - case RISCV::BI__builtin_riscv_zip_32: - case RISCV::BI__builtin_riscv_unzip_32: - case RISCV::BI__builtin_riscv_aes32dsi_32: - case RISCV::BI__builtin_riscv_aes32dsmi_32: - case RISCV::BI__builtin_riscv_aes32esi_32: - case RISCV::BI__builtin_riscv_aes32esmi_32: - case RISCV::BI__builtin_riscv_sha512sig0h_32: - case RISCV::BI__builtin_riscv_sha512sig0l_32: - case RISCV::BI__builtin_riscv_sha512sig1h_32: - case RISCV::BI__builtin_riscv_sha512sig1l_32: - case RISCV::BI__builtin_riscv_sha512sum0r_32: - case RISCV::BI__builtin_riscv_sha512sum1r_32: - return true; - } - - return false; -} - bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { @@ -4352,31 +4547,28 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID); Features.split(ReqFeatures, ','); - // Check for 32-bit only builtins on a 64-bit target. - const llvm::Triple &TT = TI.getTriple(); - if (TT.getArch() != llvm::Triple::riscv32 && isRISCV32Builtin(BuiltinID)) - return Diag(TheCall->getCallee()->getBeginLoc(), - diag::err_32_bit_builtin_64_bit_tgt); - // Check if each required feature is included for (StringRef F : ReqFeatures) { SmallVector<StringRef> ReqOpFeatures; F.split(ReqOpFeatures, '|'); - bool HasFeature = false; - for (StringRef OF : ReqOpFeatures) { - if (TI.hasFeature(OF)) { - HasFeature = true; - continue; - } - } - if (!HasFeature) { + if (llvm::none_of(ReqOpFeatures, + [&TI](StringRef OF) { return TI.hasFeature(OF); })) { std::string FeatureStrs; + bool IsExtension = true; for (StringRef OF : ReqOpFeatures) { // If the feature is 64bit, alter the string so it will print better in // the diagnostic. - if (OF == "64bit") + if (OF == "64bit") { + assert(ReqOpFeatures.size() == 1 && "Expected '64bit' to be alone"); OF = "RV64"; + IsExtension = false; + } + if (OF == "32bit") { + assert(ReqOpFeatures.size() == 1 && "Expected '32bit' to be alone"); + OF = "RV32"; + IsExtension = false; + } // Convert features like "zbr" and "experimental-zbr" to "Zbr". OF.consume_front("experimental-"); @@ -4391,6 +4583,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, // Error message FeatureMissing = true; Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension) + << IsExtension << TheCall->getSourceRange() << StringRef(FeatureStrs); } } @@ -4449,7 +4642,8 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == SystemZ::BI__builtin_tabort) { Expr *Arg = TheCall->getArg(0); - if (Optional<llvm::APSInt> AbortCode = Arg->getIntegerConstantExpr(Context)) + if (std::optional<llvm::APSInt> AbortCode = + Arg->getIntegerConstantExpr(Context)) if (AbortCode->getSExtValue() >= 0 && AbortCode->getSExtValue() < 256) return Diag(Arg->getBeginLoc(), diag::err_systemz_invalid_tabort_code) << Arg->getSourceRange(); @@ -5010,6 +5204,7 @@ bool Sema::CheckX86BuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_tdpbusd: case X86::BI__builtin_ia32_tdpbuud: case X86::BI__builtin_ia32_tdpbf16ps: + case X86::BI__builtin_ia32_tdpfp16ps: return CheckX86BuiltinTileRangeAndDuplicate(TheCall, {0, 1, 2}); } } @@ -5394,6 +5589,10 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case X86::BI__builtin_ia32_reducesh_mask: i = 4; l = 0; u = 255; break; + case X86::BI__builtin_ia32_cmpccxadd32: + case X86::BI__builtin_ia32_cmpccxadd64: + i = 3; l = 0; u = 15; + break; } // Note that we don't force a hard error on the range check here, allowing @@ -5437,8 +5636,7 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, /// Returns true if the value evaluates to null. static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { // If the expression has non-null type, it doesn't evaluate to null. - if (auto nullability - = Expr->IgnoreImplicit()->getType()->getNullability(S.Context)) { + if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) { if (*nullability == NullabilityKind::NonNull) return false; } @@ -5522,8 +5720,8 @@ DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, } /// Determine whether the given type has a non-null nullability annotation. -static bool isNonNullType(ASTContext &ctx, QualType type) { - if (auto nullability = type->getNullability(ctx)) +static bool isNonNullType(QualType type) { + if (auto nullability = type->getNullability()) return *nullability == NullabilityKind::NonNull; return false; @@ -5536,7 +5734,7 @@ static void CheckNonNullArguments(Sema &S, SourceLocation CallSiteLoc) { assert((FDecl || Proto) && "Need a function declaration or prototype"); - // Already checked by by constant evaluator. + // Already checked by constant evaluator. if (S.isConstantEvaluated()) return; // Check the attributes attached to the method/function itself. @@ -5576,8 +5774,7 @@ static void CheckNonNullArguments(Sema &S, for (ArrayRef<ParmVarDecl*>::iterator I = parms.begin(), E = parms.end(); I != E; ++I, ++ParamIndex) { const ParmVarDecl *PVD = *I; - if (PVD->hasAttr<NonNullAttr>() || - isNonNullType(S.Context, PVD->getType())) { + if (PVD->hasAttr<NonNullAttr>() || isNonNullType(PVD->getType())) { if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); @@ -5606,7 +5803,7 @@ static void CheckNonNullArguments(Sema &S, if (Proto) { unsigned Index = 0; for (auto paramType : Proto->getParamTypes()) { - if (isNonNullType(S.Context, paramType)) { + if (isNonNullType(paramType)) { if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); @@ -5622,7 +5819,7 @@ static void CheckNonNullArguments(Sema &S, for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size(); ArgIndex != ArgIndexEnd; ++ArgIndex) { if (NonNullArgs[ArgIndex]) - CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); + CheckNonNullArgument(S, Args[ArgIndex], Args[ArgIndex]->getExprLoc()); } } @@ -5683,9 +5880,9 @@ void Sema::CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl, // Find expected alignment, and the actual alignment of the passed object. // getTypeAlignInChars requires complete types - if (ArgTy.isNull() || ParamTy->isIncompleteType() || - ArgTy->isIncompleteType() || ParamTy->isUndeducedType() || - ArgTy->isUndeducedType()) + if (ArgTy.isNull() || ParamTy->isDependentType() || + ParamTy->isIncompleteType() || ArgTy->isIncompleteType() || + ParamTy->isUndeducedType() || ArgTy->isUndeducedType()) return; CharUnits ParamAlign = Context.getTypeAlignInChars(ParamTy); @@ -5837,14 +6034,14 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, unsigned NumArgs = TheCall->getNumArgs(); Expr *ImplicitThis = nullptr; - if (IsMemberOperatorCall) { - // If this is a call to a member operator, hide the first argument - // from checkCall. + if (IsMemberOperatorCall && !FDecl->isStatic()) { + // If this is a call to a non-static member operator, hide the first + // argument from checkCall. // FIXME: Our choice of AST representation here is less than ideal. ImplicitThis = Args[0]; ++Args; --NumArgs; - } else if (IsMemberFunction) + } else if (IsMemberFunction && !FDecl->isStatic()) ImplicitThis = cast<CXXMemberCallExpr>(TheCall)->getImplicitObjectArgument(); @@ -5864,7 +6061,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, ThisTypeFromDecl); } - checkCall(FDecl, Proto, ImplicitThis, llvm::makeArrayRef(Args, NumArgs), + checkCall(FDecl, Proto, ImplicitThis, llvm::ArrayRef(Args, NumArgs), IsMemberFunction, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); @@ -5945,7 +6142,7 @@ bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, } checkCall(NDecl, Proto, /*ThisArg=*/nullptr, - llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), + llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), /*IsMemberFunction=*/false, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); @@ -5958,7 +6155,7 @@ bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) { VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto, TheCall->getCallee()); checkCall(/*FDecl=*/nullptr, Proto, /*ThisArg=*/nullptr, - llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), + llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), /*IsMemberFunction=*/false, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); @@ -6463,7 +6660,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, } if (SubExprs.size() >= 2 && Form != Init) { - if (Optional<llvm::APSInt> Result = + if (std::optional<llvm::APSInt> Result = SubExprs[1]->getIntegerConstantExpr(Context)) if (!isValidOrderingForOp(Result->getSExtValue(), Op)) Diag(SubExprs[1]->getBeginLoc(), @@ -6473,7 +6670,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, if (auto ScopeModel = AtomicExpr::getScopeModel(Op)) { auto *Scope = Args[Args.size() - 1]; - if (Optional<llvm::APSInt> Result = + if (std::optional<llvm::APSInt> Result = Scope->getIntegerConstantExpr(Context)) { if (!ScopeModel->isValid(Result->getZExtValue())) Diag(Scope->getBeginLoc(), diag::err_atomic_op_has_invalid_synch_scope) @@ -6840,7 +7037,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // Get the decl for the concrete builtin from this, we can tell what the // concrete integer type we should convert to is. unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex]; - const char *NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID); + StringRef NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID); FunctionDecl *NewBuiltinDecl; if (NewBuiltinID == BuiltinID) NewBuiltinDecl = FDecl; @@ -7122,6 +7319,9 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { if (checkVAStartABI(*this, BuiltinID, Fn)) return true; + // In C2x mode, va_start only needs one argument. However, the builtin still + // requires two arguments (which matches the behavior of the GCC builtin), + // <stdarg.h> passes `0` as the second argument in C2x mode. if (checkArgCount(*this, TheCall, 2)) return true; @@ -7135,9 +7335,15 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { return true; // Verify that the second argument to the builtin is the last argument of the - // current function or method. + // current function or method. In C2x mode, if the second argument is an + // integer constant expression with value 0, then we don't bother with this + // check. bool SecondArgIsLastNamedArgument = false; const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts(); + if (std::optional<llvm::APSInt> Val = + TheCall->getArg(1)->getIntegerConstantExpr(Context); + Val && LangOpts.C2x && *Val == 0) + return false; // These are valid if SecondArgIsLastNamedArgument is false after the next // block. @@ -7163,7 +7369,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { Type->isSpecificBuiltinType(BuiltinType::Float) || [=] { // Promotable integers are UB, but enumerations need a bit of // extra checking to see what their promotable type actually is. - if (!Type->isPromotableIntegerType()) + if (!Context.isPromotableIntegerType(Type)) return false; if (!Type->isEnumeralType()) return true; @@ -7178,7 +7384,6 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { Diag(ParamLoc, diag::note_parameter_type) << Type; } - TheCall->setType(Context.VoidTy); return false; } @@ -7490,7 +7695,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { TheCall->getArg(i)->isValueDependent()) continue; - Optional<llvm::APSInt> Result; + std::optional<llvm::APSInt> Result; if (!(Result = TheCall->getArg(i)->getIntegerConstantExpr(Context))) return ExprError(Diag(TheCall->getBeginLoc(), diag::err_shufflevector_nonconstant_argument) @@ -7644,38 +7849,43 @@ bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) { /// Handle __builtin_assume_aligned. This is declared /// as (const void*, size_t, ...) and can take one optional constant int arg. bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { + if (checkArgCountRange(*this, TheCall, 2, 3)) + return true; + unsigned NumArgs = TheCall->getNumArgs(); + Expr *FirstArg = TheCall->getArg(0); - if (NumArgs > 3) - return Diag(TheCall->getEndLoc(), - diag::err_typecheck_call_too_many_args_at_most) - << 0 /*function call*/ << 3 << NumArgs << TheCall->getSourceRange(); + { + ExprResult FirstArgResult = + DefaultFunctionArrayLvalueConversion(FirstArg); + if (FirstArgResult.isInvalid()) + return true; + TheCall->setArg(0, FirstArgResult.get()); + } // The alignment must be a constant integer. - Expr *Arg = TheCall->getArg(1); + Expr *SecondArg = TheCall->getArg(1); // We can't check the value of a dependent argument. - if (!Arg->isTypeDependent() && !Arg->isValueDependent()) { + if (!SecondArg->isValueDependent()) { llvm::APSInt Result; if (SemaBuiltinConstantArg(TheCall, 1, Result)) return true; if (!Result.isPowerOf2()) return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two) - << Arg->getSourceRange(); + << SecondArg->getSourceRange(); if (Result > Sema::MaximumAlignment) Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great) - << Arg->getSourceRange() << Sema::MaximumAlignment; + << SecondArg->getSourceRange() << Sema::MaximumAlignment; } if (NumArgs > 2) { - ExprResult Arg(TheCall->getArg(2)); - InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, - Context.getSizeType(), false); - Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); - if (Arg.isInvalid()) return true; - TheCall->setArg(2, Arg.get()); + Expr *ThirdArg = TheCall->getArg(2); + if (convertArgumentToType(*this, ThirdArg, Context.getSizeType())) + return true; + TheCall->setArg(2, ThirdArg); } return false; @@ -7771,7 +7981,7 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, if (Arg->isTypeDependent() || Arg->isValueDependent()) return false; - Optional<llvm::APSInt> R; + std::optional<llvm::APSInt> R; if (!(R = Arg->getIntegerConstantExpr(Context))) return Diag(TheCall->getBeginLoc(), diag::err_constant_integer_arg_type) << FDecl->getDeclName() << Arg->getSourceRange(); @@ -8106,6 +8316,8 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, BuiltinID == ARM::BI__builtin_arm_wsrp; bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 || BuiltinID == AArch64::BI__builtin_arm_wsr64 || + BuiltinID == AArch64::BI__builtin_arm_rsr128 || + BuiltinID == AArch64::BI__builtin_arm_wsr128 || BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsrp || BuiltinID == AArch64::BI__builtin_arm_wsr || @@ -8173,21 +8385,51 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg) << Arg->getSourceRange(); } else if (IsAArch64Builtin && Fields.size() == 1) { - // If the register name is one of those that appear in the condition below - // and the special register builtin being used is one of the write builtins, - // then we require that the argument provided for writing to the register - // is an integer constant expression. This is because it will be lowered to - // an MSR (immediate) instruction, so we need to know the immediate at - // compile time. + // This code validates writes to PSTATE registers. + + // Not a write. if (TheCall->getNumArgs() != 2) return false; - std::string RegLower = Reg.lower(); - if (RegLower != "spsel" && RegLower != "daifset" && RegLower != "daifclr" && - RegLower != "pan" && RegLower != "uao") + // The 128-bit system register accesses do not touch PSTATE. + if (BuiltinID == AArch64::BI__builtin_arm_rsr128 || + BuiltinID == AArch64::BI__builtin_arm_wsr128) return false; - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + // These are the named PSTATE accesses using "MSR (immediate)" instructions, + // along with the upper limit on the immediates allowed. + auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg) + .CaseLower("spsel", 15) + .CaseLower("daifclr", 15) + .CaseLower("daifset", 15) + .CaseLower("pan", 15) + .CaseLower("uao", 15) + .CaseLower("dit", 15) + .CaseLower("ssbs", 15) + .CaseLower("tco", 15) + .CaseLower("allint", 1) + .CaseLower("pm", 1) + .Default(std::nullopt); + + // If this is not a named PSTATE, just continue without validating, as this + // will be lowered to an "MSR (register)" instruction directly + if (!MaxLimit) + return false; + + // Here we only allow constants in the range for that pstate, as required by + // the ACLE. + // + // While clang also accepts the names of system registers in its ACLE + // intrinsics, we prevent this with the PSTATE names used in MSR (immediate) + // as the value written via a register is different to the value used as an + // immediate to have the same effect. e.g., for the instruction `msr tco, + // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but + // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO. + // + // If a programmer wants to codegen the MSR (register) form of `msr tco, + // xN`, they can still do so by specifying the register using five + // colon-separated numbers in a string. + return SemaBuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit); } return false; @@ -8473,6 +8715,9 @@ static void CheckFormatString( llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg, bool IgnoreStringsWithoutSpecifiers); +static const Expr *maybeConstEvalStringLiteral(ASTContext &Context, + const Expr *E); + // Determine if an expression is a string literal or constant string. // If this function returns false on the arguments to a function expecting a // format string, we will usually need to emit a warning. @@ -8503,6 +8748,15 @@ tryAgain: return SLCT_UncheckedLiteral; switch (E->getStmtClass()) { + case Stmt::InitListExprClass: + // Handle expressions like {"foobar"}. + if (const clang::Expr *SLE = maybeConstEvalStringLiteral(S.Context, E)) { + return checkFormatStringExpr(S, SLE, Args, APK, format_idx, firstDataArg, + Type, CallType, /*InFunctionCall*/ false, + CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); + } + return SLCT_NotALiteral; case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { // The expression is a literal if both sub-expressions were, and it was @@ -8713,7 +8967,11 @@ tryAgain: } } } - + if (const Expr *SLE = maybeConstEvalStringLiteral(S.Context, E)) + return checkFormatStringExpr(S, SLE, Args, APK, format_idx, firstDataArg, + Type, CallType, /*InFunctionCall*/ false, + CheckedVarArgs, UncoveredArg, Offset, + IgnoreStringsWithoutSpecifiers); return SLCT_NotALiteral; } case Stmt::ObjCMessageExprClass: { @@ -8823,6 +9081,20 @@ tryAgain: } } +// If this expression can be evaluated at compile-time, +// check if the result is a StringLiteral and return it +// otherwise return nullptr +static const Expr *maybeConstEvalStringLiteral(ASTContext &Context, + const Expr *E) { + Expr::EvalResult Result; + if (E->EvaluateAsRValue(Result, Context) && Result.Val.isLValue()) { + const auto *LVE = Result.Val.getLValueBase().dyn_cast<const Expr *>(); + if (isa_and_nonnull<StringLiteral>(LVE)) + return LVE; + } + return nullptr; +} + Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) { return llvm::StringSwitch<FormatStringType>(Format->getType()->getName()) .Case("scanf", FST_Scanf) @@ -9013,7 +9285,7 @@ public: EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr, const PartialDiagnostic &PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - ArrayRef<FixItHint> Fixit = None); + ArrayRef<FixItHint> Fixit = std::nullopt); protected: bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, @@ -9040,7 +9312,7 @@ protected: template <typename Range> void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - ArrayRef<FixItHint> Fixit = None); + ArrayRef<FixItHint> Fixit = std::nullopt); }; } // namespace @@ -9083,7 +9355,7 @@ void CheckFormatHandler::HandleInvalidLengthModifier( CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength()); // See if we know how to fix this length modifier. - Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier(); + std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier(); if (FixedLM) { EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(), getLocationOfByte(LM.getStart()), @@ -9116,7 +9388,7 @@ void CheckFormatHandler::HandleNonStandardLengthModifier( CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength()); // See if we know how to fix this length modifier. - Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier(); + std::optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier(); if (FixedLM) { EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << LM.toString() << 0, @@ -9143,7 +9415,7 @@ void CheckFormatHandler::HandleNonStandardConversionSpecifier( using namespace analyze_format_string; // See if we know how to fix this conversion specifier. - Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier(); + std::optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier(); if (FixedCS) { EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << CS.toString() << /*conversion specifier*/1, @@ -10005,7 +10277,7 @@ isArithmeticArgumentPromotion(Sema &S, const ImplicitCastExpr *ICE) { // It's an integer promotion if the destination type is the promoted // source type. if (ICE->getCastKind() == CK_IntegralCast && - From->isPromotableIntegerType() && + S.Context.isPromotableIntegerType(From) && S.Context.getPromotedIntegerType(From) == To) return true; // Look through vector types, since we do default argument promotion for @@ -10060,10 +10332,14 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, return true; } - analyze_printf::ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy); - if (Match == analyze_printf::ArgType::Match) + ArgType::MatchKind ImplicitMatch = ArgType::NoMatch; + ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy); + if (Match == ArgType::Match) return true; + // NoMatchPromotionTypeConfusion should be only returned in ImplictCastExpr + assert(Match != ArgType::NoMatchPromotionTypeConfusion); + // Look through argument promotions for our error message's reported type. // This includes the integral and floating promotions, but excludes array // and function pointer decay (seeing that an argument intended to be a @@ -10080,13 +10356,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, if (ICE->getType() == S.Context.IntTy || ICE->getType() == S.Context.UnsignedIntTy) { // All further checking is done on the subexpression - const analyze_printf::ArgType::MatchKind ImplicitMatch = - AT.matchesType(S.Context, ExprTy); - if (ImplicitMatch == analyze_printf::ArgType::Match) + ImplicitMatch = AT.matchesType(S.Context, ExprTy); + if (ImplicitMatch == ArgType::Match) return true; - if (ImplicitMatch == ArgType::NoMatchPedantic || - ImplicitMatch == ArgType::NoMatchTypeConfusion) - Match = ImplicitMatch; } } } else if (const CharacterLiteral *CL = dyn_cast<CharacterLiteral>(E)) { @@ -10097,10 +10369,29 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // modifier is provided. if (ExprTy == S.Context.IntTy && FS.getLengthModifier().getKind() != LengthModifier::AsChar) - if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue())) + if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue())) { ExprTy = S.Context.CharTy; + // To improve check results, we consider a character literal in C + // to be a 'char' rather than an 'int'. 'printf("%hd", 'a');' is + // more likely a type confusion situation, so we will suggest to + // use '%hhd' instead by discarding the MatchPromotion. + if (Match == ArgType::MatchPromotion) + Match = ArgType::NoMatch; + } } - + if (Match == ArgType::MatchPromotion) { + // WG14 N2562 only clarified promotions in *printf + // For NSLog in ObjC, just preserve -Wformat behavior + if (!S.getLangOpts().ObjC && + ImplicitMatch != ArgType::NoMatchPromotionTypeConfusion && + ImplicitMatch != ArgType::NoMatchTypeConfusion) + return true; + Match = ArgType::NoMatch; + } + if (ImplicitMatch == ArgType::NoMatchPedantic || + ImplicitMatch == ArgType::NoMatchTypeConfusion) + Match = ImplicitMatch; + assert(Match != ArgType::MatchPromotion); // Look through enums to their underlying type. bool IsEnum = false; if (auto EnumTy = ExprTy->getAs<EnumType>()) { @@ -10173,7 +10464,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) { unsigned Diag; switch (Match) { - case ArgType::Match: llvm_unreachable("expected non-matching"); + case ArgType::Match: + case ArgType::MatchPromotion: + case ArgType::NoMatchPromotionTypeConfusion: + llvm_unreachable("expected non-matching"); case ArgType::NoMatchPedantic: Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; break; @@ -10236,7 +10530,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // We extract the name from the typedef because we don't want to show // the underlying type in the diagnostic. StringRef Name; - if (const TypedefType *TypedefTy = dyn_cast<TypedefType>(ExprTy)) + if (const auto *TypedefTy = ExprTy->getAs<TypedefType>()) Name = TypedefTy->getDecl()->getName(); else Name = CastTyName; @@ -10270,7 +10564,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, case Sema::VAK_ValidInCXX11: { unsigned Diag; switch (Match) { - case ArgType::Match: llvm_unreachable("expected non-matching"); + case ArgType::Match: + case ArgType::MatchPromotion: + case ArgType::NoMatchPromotionTypeConfusion: + llvm_unreachable("expected non-matching"); case ArgType::NoMatchPedantic: Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; break; @@ -10824,7 +11121,7 @@ static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range, unsigned AbsKind, QualType ArgType) { bool EmitHeaderHint = true; const char *HeaderName = nullptr; - const char *FunctionName = nullptr; + StringRef FunctionName; if (S.getLangOpts().CPlusPlus && !ArgType->isAnyComplexType()) { FunctionName = "std::abs"; if (ArgType->isIntegralOrEnumerationType()) { @@ -10932,7 +11229,7 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, // Unsigned types cannot be negative. Suggest removing the absolute value // function call. if (ArgType->isUnsignedIntegerType()) { - const char *FunctionName = + StringRef FunctionName = IsStdAbs ? "std::abs" : Context.BuiltinInfo.getName(AbsKind); Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType; Diag(Call->getExprLoc(), diag::note_remove_abs) @@ -11851,7 +12148,7 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, const FunctionDecl *FD) { // Check if the return value is null but should not be. if (((Attrs && hasSpecificAttr<ReturnsNonNullAttr>(*Attrs)) || - (!isObjCMethod && isNonNullType(Context, lhsType))) && + (!isObjCMethod && isNonNullType(lhsType))) && CheckNonNullExpr(*this, RetValExp)) Diag(ReturnLoc, diag::warn_null_ret) << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange(); @@ -12301,7 +12598,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, return IntRange(R.Width, /*NonNegative*/ true); } } - LLVM_FALLTHROUGH; + [[fallthrough]]; case BO_ShlAssign: return IntRange::forValueOfType(C, GetExprType(E)); @@ -12314,7 +12611,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, // If the shift amount is a positive constant, drop the width by // that much. - if (Optional<llvm::APSInt> shift = + if (std::optional<llvm::APSInt> shift = BO->getRHS()->getIntegerConstantExpr(C)) { if (shift->isNonNegative()) { unsigned zext = shift->getZExtValue(); @@ -12359,7 +12656,7 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, Approximate); // If the divisor is constant, use that. - if (Optional<llvm::APSInt> divisor = + if (std::optional<llvm::APSInt> divisor = BO->getRHS()->getIntegerConstantExpr(C)) { unsigned log2 = divisor->logBase2(); // floor(log_2(divisor)) if (log2 >= L.Width) @@ -12589,7 +12886,7 @@ struct PromotedRange { llvm_unreachable("impossible compare result"); } - static llvm::Optional<StringRef> + static std::optional<StringRef> constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) { if (Op == BO_Cmp) { ComparisonResult LTFlag = LT, GTFlag = GT; @@ -12598,7 +12895,7 @@ struct PromotedRange { if (R & EQ) return StringRef("'std::strong_ordering::equal'"); if (R & LTFlag) return StringRef("'std::strong_ordering::less'"); if (R & GTFlag) return StringRef("'std::strong_ordering::greater'"); - return llvm::None; + return std::nullopt; } ComparisonResult TrueFlag, FalseFlag; @@ -12623,7 +12920,7 @@ struct PromotedRange { return StringRef("true"); if (R & FalseFlag) return StringRef("false"); - return llvm::None; + return std::nullopt; } }; } @@ -12833,8 +13130,10 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) { Expr *RHS = E->getRHS(); if (T->isIntegralType(S.Context)) { - Optional<llvm::APSInt> RHSValue = RHS->getIntegerConstantExpr(S.Context); - Optional<llvm::APSInt> LHSValue = LHS->getIntegerConstantExpr(S.Context); + std::optional<llvm::APSInt> RHSValue = + RHS->getIntegerConstantExpr(S.Context); + std::optional<llvm::APSInt> LHSValue = + LHS->getIntegerConstantExpr(S.Context); // We don't care about expressions whose result is a constant. if (RHSValue && LHSValue) @@ -12955,9 +13254,6 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, } } - if (Bitfield->getType()->isBooleanType()) - return false; - // Ignore value- or type-dependent expressions. if (Bitfield->getBitWidth()->isValueDependent() || Bitfield->getBitWidth()->isTypeDependent() || @@ -13029,6 +13325,18 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, unsigned OriginalWidth = Value.getBitWidth(); + // In C, the macro 'true' from stdbool.h will evaluate to '1'; To reduce + // false positives where the user is demonstrating they intend to use the + // bit-field as a Boolean, check to see if the value is 1 and we're assigning + // to a one-bit bit-field to see if the value came from a macro named 'true'. + bool OneAssignedToOneBitBitfield = FieldWidth == 1 && Value == 1; + if (OneAssignedToOneBitBitfield && !S.LangOpts.CPlusPlus) { + SourceLocation MaybeMacroLoc = OriginalInit->getBeginLoc(); + if (S.SourceMgr.isInSystemMacro(MaybeMacroLoc) && + S.findMacroSpelling(MaybeMacroLoc, "true")) + return false; + } + if (!Value.isSigned() || Value.isNegative()) if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit)) if (UO->getOpcode() == UO_Minus || UO->getOpcode() == UO_Not) @@ -13046,17 +13354,14 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, if (llvm::APSInt::isSameValue(Value, TruncatedValue)) return false; - // Special-case bitfields of width 1: booleans are naturally 0/1, and - // therefore don't strictly fit into a signed bitfield of width 1. - if (FieldWidth == 1 && Value == 1) - return false; - std::string PrettyValue = toString(Value, 10); std::string PrettyTrunc = toString(TruncatedValue, 10); - S.Diag(InitLoc, diag::warn_impcast_bitfield_precision_constant) - << PrettyValue << PrettyTrunc << OriginalInit->getType() - << Init->getSourceRange(); + S.Diag(InitLoc, OneAssignedToOneBitBitfield + ? diag::warn_impcast_single_bit_bitield_precision_constant + : diag::warn_impcast_bitfield_precision_constant) + << PrettyValue << PrettyTrunc << OriginalInit->getType() + << Init->getSourceRange(); return true; } @@ -13342,9 +13647,10 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, return; // Check for NULL (GNUNull) or nullptr (CXX11_nullptr). - const Expr::NullPointerConstantKind NullKind = - E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull); - if (NullKind != Expr::NPCK_GNUNull && NullKind != Expr::NPCK_CXX11_nullptr) + const Expr *NewE = E->IgnoreParenImpCasts(); + bool IsGNUNullExpr = isa<GNUNullExpr>(NewE); + bool HasNullPtrType = NewE->getType()->isNullPtrType(); + if (!IsGNUNullExpr && !HasNullPtrType) return; // Return if target type is a safe conversion. @@ -13361,7 +13667,7 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, CC = S.SourceMgr.getTopMacroCallerLoc(CC); // __null is usually wrapped in a macro. Go up a macro if that is the case. - if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) { + if (IsGNUNullExpr && Loc.isMacroID()) { StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( Loc, S.SourceMgr, S.getLangOpts()); if (MacroName == "NULL") @@ -13373,7 +13679,7 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, return; S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer) - << (NullKind == Expr::NPCK_CXX11_nullptr) << T << SourceRange(CC) + << HasNullPtrType << T << SourceRange(CC) << FixItHint::CreateReplacement(Loc, S.getFixItZeroLiteralForType(T, Loc)); } @@ -13836,7 +14142,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (SourcePrecision > 0 && TargetPrecision > 0 && SourcePrecision > TargetPrecision) { - if (Optional<llvm::APSInt> SourceInt = + if (std::optional<llvm::APSInt> SourceInt = E->getIntegerConstantExpr(S.Context)) { // If the source integer is a constant, convert it to the target // floating point type. Issue a warning if the value changes @@ -14559,6 +14865,17 @@ void Sema::CheckForIntOverflow (Expr *E) { Exprs.append(Call->arg_begin(), Call->arg_end()); else if (auto Message = dyn_cast<ObjCMessageExpr>(E)) Exprs.append(Message->arg_begin(), Message->arg_end()); + else if (auto Construct = dyn_cast<CXXConstructExpr>(E)) + Exprs.append(Construct->arg_begin(), Construct->arg_end()); + else if (auto Array = dyn_cast<ArraySubscriptExpr>(E)) + Exprs.push_back(Array->getIdx()); + else if (auto Compound = dyn_cast<CompoundLiteralExpr>(E)) + Exprs.push_back(Compound->getInitializer()); + else if (auto New = dyn_cast<CXXNewExpr>(E)) { + if (New->isArray()) + if (auto ArraySize = New->getArraySize()) + Exprs.push_back(*ArraySize); + } } while (!Exprs.empty()); } @@ -15425,8 +15742,8 @@ void Sema::CheckUnsequencedOperations(const Expr *E) { void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, bool IsConstexpr) { - llvm::SaveAndRestore<bool> ConstantContext( - isConstantEvaluatedOverride, IsConstexpr || isa<ConstantExpr>(E)); + llvm::SaveAndRestore ConstantContext(isConstantEvaluatedOverride, + IsConstexpr || isa<ConstantExpr>(E)); CheckImplicitConversions(E, CheckLoc); if (!E->isInstantiationDependent()) CheckUnsequencedOperations(E); @@ -15551,8 +15868,11 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, return HasInvalidParm; } -Optional<std::pair<CharUnits, CharUnits>> -static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx); +std::optional<std::pair< + CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr + *E, + ASTContext + &Ctx); /// Compute the alignment and offset of the base class object given the /// derived-to-base cast expression and the alignment and offset of the derived @@ -15586,21 +15906,21 @@ getDerivedToBaseAlignmentAndOffset(const CastExpr *CE, QualType DerivedType, } /// Compute the alignment and offset of a binary additive operator. -static Optional<std::pair<CharUnits, CharUnits>> +static std::optional<std::pair<CharUnits, CharUnits>> getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE, bool IsSub, ASTContext &Ctx) { QualType PointeeType = PtrE->getType()->getPointeeType(); if (!PointeeType->isConstantSizeType()) - return llvm::None; + return std::nullopt; auto P = getBaseAlignmentAndOffsetFromPtr(PtrE, Ctx); if (!P) - return llvm::None; + return std::nullopt; CharUnits EltSize = Ctx.getTypeSizeInChars(PointeeType); - if (Optional<llvm::APSInt> IdxRes = IntE->getIntegerConstantExpr(Ctx)) { + if (std::optional<llvm::APSInt> IdxRes = IntE->getIntegerConstantExpr(Ctx)) { CharUnits Offset = EltSize * IdxRes->getExtValue(); if (IsSub) Offset = -Offset; @@ -15617,8 +15937,10 @@ getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE, /// This helper function takes an lvalue expression and returns the alignment of /// a VarDecl and a constant offset from the VarDecl. -Optional<std::pair<CharUnits, CharUnits>> -static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) { +std::optional<std::pair< + CharUnits, + CharUnits>> static getBaseAlignmentAndOffsetFromLValue(const Expr *E, + ASTContext &Ctx) { E = E->IgnoreParens(); switch (E->getStmtClass()) { default: @@ -15666,7 +15988,7 @@ static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) { if (!FD || FD->getType()->isReferenceType() || FD->getParent()->isInvalidDecl()) break; - Optional<std::pair<CharUnits, CharUnits>> P; + std::optional<std::pair<CharUnits, CharUnits>> P; if (ME->isArrow()) P = getBaseAlignmentAndOffsetFromPtr(ME->getBase(), Ctx); else @@ -15700,13 +16022,16 @@ static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) { break; } } - return llvm::None; + return std::nullopt; } /// This helper function takes a pointer expression and returns the alignment of /// a VarDecl and a constant offset from the VarDecl. -Optional<std::pair<CharUnits, CharUnits>> -static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx) { +std::optional<std::pair< + CharUnits, CharUnits>> static getBaseAlignmentAndOffsetFromPtr(const Expr + *E, + ASTContext + &Ctx) { E = E->IgnoreParens(); switch (E->getStmtClass()) { default: @@ -15765,12 +16090,12 @@ static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx) { break; } } - return llvm::None; + return std::nullopt; } static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) { // See if we can compute the alignment of a VarDecl and an offset from it. - Optional<std::pair<CharUnits, CharUnits>> P = + std::optional<std::pair<CharUnits, CharUnits>> P = getBaseAlignmentAndOffsetFromPtr(E, S.Context); if (P) @@ -15824,71 +16149,6 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { << TRange << Op->getSourceRange(); } -/// Check whether this array fits the idiom of a size-one tail padded -/// array member of a struct. -/// -/// We avoid emitting out-of-bounds access warnings for such arrays as they are -/// commonly used to emulate flexible arrays in C89 code. -static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size, - const NamedDecl *ND, - unsigned StrictFlexArraysLevel) { - if (!ND) - return false; - - if (StrictFlexArraysLevel >= 2 && Size != 0) - return false; - - if (StrictFlexArraysLevel == 1 && Size.ule(1)) - return false; - - // FIXME: While the default -fstrict-flex-arrays=0 permits Size>1 trailing - // arrays to be treated as flexible-array-members, we still emit diagnostics - // as if they are not. Pending further discussion... - if (StrictFlexArraysLevel == 0 && Size != 1) - return false; - - const FieldDecl *FD = dyn_cast<FieldDecl>(ND); - if (!FD) - return false; - - // Don't consider sizes resulting from macro expansions or template argument - // substitution to form C89 tail-padded arrays. - - TypeSourceInfo *TInfo = FD->getTypeSourceInfo(); - while (TInfo) { - TypeLoc TL = TInfo->getTypeLoc(); - // Look through typedefs. - if (TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>()) { - const TypedefNameDecl *TDL = TTL.getTypedefNameDecl(); - TInfo = TDL->getTypeSourceInfo(); - continue; - } - if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) { - const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr()); - if (!SizeExpr || SizeExpr->getExprLoc().isMacroID()) - return false; - } - break; - } - - const RecordDecl *RD = dyn_cast<RecordDecl>(FD->getDeclContext()); - if (!RD) - return false; - if (RD->isUnion()) - return false; - if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(RD)) { - if (!CRD->isStandardLayout()) - return false; - } - - // See if this is the last field decl in the record. - const Decl *D = FD; - while ((D = D->getNextDeclInContext())) - if (isa<FieldDecl>(D)) - return false; - return true; -} - void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE, bool AllowOnePastEnd, bool IndexNegated) { @@ -15906,9 +16166,15 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ConstantArrayType *ArrayTy = Context.getAsConstantArrayType(BaseExpr->getType()); + LangOptions::StrictFlexArraysLevelKind + StrictFlexArraysLevel = getLangOpts().getStrictFlexArraysLevel(); + const Type *BaseType = ArrayTy == nullptr ? nullptr : ArrayTy->getElementType().getTypePtr(); - bool IsUnboundedArray = (BaseType == nullptr); + bool IsUnboundedArray = + BaseType == nullptr || BaseExpr->isFlexibleArrayMemberLike( + Context, StrictFlexArraysLevel, + /*IgnoreTemplateOrMacroSubstitution=*/true); if (EffectiveType->isDependentType() || (!IsUnboundedArray && BaseType->isDependentType())) return; @@ -15923,23 +16189,16 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, index = -index; } - const NamedDecl *ND = nullptr; - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = DRE->getDecl(); - if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = ME->getMemberDecl(); - if (IsUnboundedArray) { if (EffectiveType->isFunctionType()) return; if (index.isUnsigned() || !index.isNegative()) { const auto &ASTC = getASTContext(); - unsigned AddrBits = - ASTC.getTargetInfo().getPointerWidth(ASTC.getTargetAddressSpace( - EffectiveType->getCanonicalTypeInternal())); + unsigned AddrBits = ASTC.getTargetInfo().getPointerWidth( + EffectiveType->getCanonicalTypeInternal().getAddressSpace()); if (index.getBitWidth() < AddrBits) index = index.zext(AddrBits); - Optional<CharUnits> ElemCharUnits = + std::optional<CharUnits> ElemCharUnits = ASTC.getTypeSizeInCharsIfKnown(EffectiveType); // PR50741 - If EffectiveType has unknown size (e.g., if it's a void // pointer) bounds-checking isn't meaningful. @@ -15982,15 +16241,14 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, << (unsigned)MaxElems.getLimitedValue(~0U) << IndexExpr->getSourceRange()); - if (!ND) { - // Try harder to find a NamedDecl to point at in the note. - while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr)) - BaseExpr = ASE->getBase()->IgnoreParenCasts(); - if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = DRE->getDecl(); - if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = ME->getMemberDecl(); - } + const NamedDecl *ND = nullptr; + // Try harder to find a NamedDecl to point at in the note. + while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr)) + BaseExpr = ASE->getBase()->IgnoreParenCasts(); + if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) + ND = DRE->getDecl(); + if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr)) + ND = ME->getMemberDecl(); if (ND) DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr, @@ -16006,29 +16264,28 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, // example). In this case we have no information about whether the array // access exceeds the array bounds. However we can still diagnose an array // access which precedes the array bounds. - // - // FIXME: this check should be redundant with the IsUnboundedArray check - // above. if (BaseType->isIncompleteType()) return; - // FIXME: this check should belong to the IsTailPaddedMemberArray call - // below. llvm::APInt size = ArrayTy->getSize(); - if (!size.isStrictlyPositive()) - return; if (BaseType != EffectiveType) { - // Make sure we're comparing apples to apples when comparing index to size + // Make sure we're comparing apples to apples when comparing index to + // size. uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType); uint64_t array_typesize = Context.getTypeSize(BaseType); - // Handle ptrarith_typesize being zero, such as when casting to void* - if (!ptrarith_typesize) ptrarith_typesize = 1; + + // Handle ptrarith_typesize being zero, such as when casting to void*. + // Use the size in bits (what "getTypeSize()" returns) rather than bytes. + if (!ptrarith_typesize) + ptrarith_typesize = Context.getCharWidth(); + if (ptrarith_typesize != array_typesize) { - // There's a cast to a different size type involved + // There's a cast to a different size type involved. uint64_t ratio = array_typesize / ptrarith_typesize; + // TODO: Be smarter about handling cases where array_typesize is not a - // multiple of ptrarith_typesize + // multiple of ptrarith_typesize. if (ptrarith_typesize * ratio == array_typesize) size *= llvm::APInt(size.getBitWidth(), ratio); } @@ -16046,11 +16303,6 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, if (AllowOnePastEnd ? index.ule(size) : index.ult(size)) return; - // Also don't warn for Flexible Array Member emulation. - const unsigned StrictFlexArraysLevel = getLangOpts().StrictFlexArrays; - if (IsTailPaddedMemberArray(*this, size, ND, StrictFlexArraysLevel)) - return; - // Suppress the warning if the subscript expression (as identified by the // ']' location) and the index expression are both from macro expansions // within a system header. @@ -16067,12 +16319,13 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, unsigned DiagID = ASE ? diag::warn_array_index_exceeds_bounds : diag::warn_ptr_arith_exceeds_bounds; + unsigned CastMsg = (!ASE || BaseType == EffectiveType) ? 0 : 1; + QualType CastMsgTy = ASE ? ASE->getLHS()->getType() : QualType(); - DiagRuntimeBehavior(BaseExpr->getBeginLoc(), BaseExpr, - PDiag(DiagID) << toString(index, 10, true) - << toString(size, 10, true) - << (unsigned)size.getLimitedValue(~0U) - << IndexExpr->getSourceRange()); + DiagRuntimeBehavior( + BaseExpr->getBeginLoc(), BaseExpr, + PDiag(DiagID) << toString(index, 10, true) << ArrayTy->desugar() + << CastMsg << CastMsgTy << IndexExpr->getSourceRange()); } else { unsigned DiagID = diag::warn_array_index_precedes_bounds; if (!ASE) { @@ -16085,15 +16338,14 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, << IndexExpr->getSourceRange()); } - if (!ND) { - // Try harder to find a NamedDecl to point at in the note. - while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr)) - BaseExpr = ASE->getBase()->IgnoreParenCasts(); - if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) - ND = DRE->getDecl(); - if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr)) - ND = ME->getMemberDecl(); - } + const NamedDecl *ND = nullptr; + // Try harder to find a NamedDecl to point at in the note. + while (const auto *ASE = dyn_cast<ArraySubscriptExpr>(BaseExpr)) + BaseExpr = ASE->getBase()->IgnoreParenCasts(); + if (const auto *DRE = dyn_cast<DeclRefExpr>(BaseExpr)) + ND = DRE->getDecl(); + if (const auto *ME = dyn_cast<MemberExpr>(BaseExpr)) + ND = ME->getMemberDecl(); if (ND) DiagRuntimeBehavior(ND->getBeginLoc(), BaseExpr, @@ -16318,7 +16570,7 @@ namespace { return; if (Expr *RHS = BinOp->getRHS()) { RHS = RHS->IgnoreParenCasts(); - Optional<llvm::APSInt> Value; + std::optional<llvm::APSInt> Value; VarWillBeReased = (RHS && (Value = RHS->getIntegerConstantExpr(Context)) && *Value == 0); @@ -16399,21 +16651,21 @@ static bool isSetterLikeSelector(Selector sel) { return !isLowercase(str.front()); } -static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S, - ObjCMessageExpr *Message) { +static std::optional<int> +GetNSMutableArrayArgumentIndex(Sema &S, ObjCMessageExpr *Message) { bool IsMutableArray = S.NSAPIObj->isSubclassOfNSClass( Message->getReceiverInterface(), NSAPI::ClassId_NSMutableArray); if (!IsMutableArray) { - return None; + return std::nullopt; } Selector Sel = Message->getSelector(); - Optional<NSAPI::NSArrayMethodKind> MKOpt = - S.NSAPIObj->getNSArrayMethodKind(Sel); + std::optional<NSAPI::NSArrayMethodKind> MKOpt = + S.NSAPIObj->getNSArrayMethodKind(Sel); if (!MKOpt) { - return None; + return std::nullopt; } NSAPI::NSArrayMethodKind MK = *MKOpt; @@ -16427,28 +16679,27 @@ static Optional<int> GetNSMutableArrayArgumentIndex(Sema &S, return 1; default: - return None; + return std::nullopt; } - return None; + return std::nullopt; } -static -Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S, - ObjCMessageExpr *Message) { +static std::optional<int> +GetNSMutableDictionaryArgumentIndex(Sema &S, ObjCMessageExpr *Message) { bool IsMutableDictionary = S.NSAPIObj->isSubclassOfNSClass( Message->getReceiverInterface(), NSAPI::ClassId_NSMutableDictionary); if (!IsMutableDictionary) { - return None; + return std::nullopt; } Selector Sel = Message->getSelector(); - Optional<NSAPI::NSDictionaryMethodKind> MKOpt = - S.NSAPIObj->getNSDictionaryMethodKind(Sel); + std::optional<NSAPI::NSDictionaryMethodKind> MKOpt = + S.NSAPIObj->getNSDictionaryMethodKind(Sel); if (!MKOpt) { - return None; + return std::nullopt; } NSAPI::NSDictionaryMethodKind MK = *MKOpt; @@ -16460,13 +16711,14 @@ Optional<int> GetNSMutableDictionaryArgumentIndex(Sema &S, return 0; default: - return None; + return std::nullopt; } - return None; + return std::nullopt; } -static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) { +static std::optional<int> GetNSSetArgumentIndex(Sema &S, + ObjCMessageExpr *Message) { bool IsMutableSet = S.NSAPIObj->isSubclassOfNSClass( Message->getReceiverInterface(), NSAPI::ClassId_NSMutableSet); @@ -16475,14 +16727,15 @@ static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) { Message->getReceiverInterface(), NSAPI::ClassId_NSMutableOrderedSet); if (!IsMutableSet && !IsMutableOrderedSet) { - return None; + return std::nullopt; } Selector Sel = Message->getSelector(); - Optional<NSAPI::NSSetMethodKind> MKOpt = S.NSAPIObj->getNSSetMethodKind(Sel); + std::optional<NSAPI::NSSetMethodKind> MKOpt = + S.NSAPIObj->getNSSetMethodKind(Sel); if (!MKOpt) { - return None; + return std::nullopt; } NSAPI::NSSetMethodKind MK = *MKOpt; @@ -16497,7 +16750,7 @@ static Optional<int> GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) { return 1; } - return None; + return std::nullopt; } void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { @@ -16505,7 +16758,7 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { return; } - Optional<int> ArgOpt; + std::optional<int> ArgOpt; if (!(ArgOpt = GetNSMutableArrayArgumentIndex(*this, Message)) && !(ArgOpt = GetNSMutableDictionaryArgumentIndex(*this, Message)) && @@ -17386,15 +17639,15 @@ void Sema::DiagnoseMisalignedMembers() { void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { E = E->IgnoreParens(); - if (!T->isPointerType() && !T->isIntegerType()) + if (!T->isPointerType() && !T->isIntegerType() && !T->isDependentType()) return; if (isa<UnaryOperator>(E) && cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) { auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); if (isa<MemberExpr>(Op)) { - auto MA = llvm::find(MisalignedMembers, MisalignedMember(Op)); + auto *MA = llvm::find(MisalignedMembers, MisalignedMember(Op)); if (MA != MisalignedMembers.end() && - (T->isIntegerType() || + (T->isDependentType() || T->isIntegerType() || (T->isPointerType() && (T->getPointeeType()->isIncompleteType() || Context.getTypeAlignInChars( T->getPointeeType()) <= MA->Alignment)))) @@ -17520,19 +17773,6 @@ void Sema::CheckAddressOfPackedMember(Expr *rhs) { _2, _3, _4)); } -// Check if \p Ty is a valid type for the elementwise math builtins. If it is -// not a valid type, emit an error message and return true. Otherwise return -// false. -static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc, - QualType Ty) { - if (!Ty->getAs<VectorType>() && !ConstantMatrixType::isValidElementType(Ty)) { - S.Diag(Loc, diag::err_builtin_invalid_arg_type) - << 1 << /* vector, integer or float ty*/ 0 << Ty; - return true; - } - return false; -} - bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) { if (checkArgCount(*this, TheCall, 1)) return true; @@ -17624,10 +17864,10 @@ ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall, } // Get and verify the matrix dimensions. -static llvm::Optional<unsigned> +static std::optional<unsigned> getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) { SourceLocation ErrorPos; - Optional<llvm::APSInt> Value = + std::optional<llvm::APSInt> Value = Expr->getIntegerConstantExpr(S.Context, &ErrorPos); if (!Value) { S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_scalar_unsigned_arg) @@ -17715,7 +17955,7 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, } else ColumnsExpr = nullptr; - // If any any part of the result matrix type is still pending, just use + // If any part of the result matrix type is still pending, just use // Context.DependentTy, until all parts are resolved. if ((RowsExpr && RowsExpr->isTypeDependent()) || (ColumnsExpr && ColumnsExpr->isTypeDependent())) { @@ -17724,11 +17964,11 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, } // Check row and column dimensions. - llvm::Optional<unsigned> MaybeRows; + std::optional<unsigned> MaybeRows; if (RowsExpr) MaybeRows = getAndVerifyMatrixDimension(RowsExpr, "row", *this); - llvm::Optional<unsigned> MaybeColumns; + std::optional<unsigned> MaybeColumns; if (ColumnsExpr) MaybeColumns = getAndVerifyMatrixDimension(ColumnsExpr, "column", *this); @@ -17740,7 +17980,7 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, TheCall->setArg(3, StrideExpr); if (MaybeRows) { - if (Optional<llvm::APSInt> Value = + if (std::optional<llvm::APSInt> Value = StrideExpr->getIntegerConstantExpr(Context)) { uint64_t Stride = Value->getZExtValue(); if (Stride < *MaybeRows) { @@ -17840,7 +18080,7 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, // Check stride argument. if (MatrixTy) { - if (Optional<llvm::APSInt> Value = + if (std::optional<llvm::APSInt> Value = StrideExpr->getIntegerConstantExpr(Context)) { uint64_t Stride = Value->getZExtValue(); if (Stride < MatrixTy->getNumRows()) { diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 8ede7c015315..144bbe150abb 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -56,6 +56,7 @@ #include <list> #include <map> +#include <optional> #include <string> #include <vector> @@ -1098,7 +1099,8 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { getBasePriority(Using->getTargetDecl()), R.Qualifier, false, (R.Availability == CXAvailability_Available || - R.Availability == CXAvailability_Deprecated)); + R.Availability == CXAvailability_Deprecated), + std::move(R.FixIts)); Result.ShadowDecl = Using; MaybeAddResult(Result, CurContext); return; @@ -1212,7 +1214,7 @@ static void setInBaseClass(ResultBuilder::Result &R) { enum class OverloadCompare { BothViable, Dominates, Dominated }; // Will Candidate ever be called on the object, when overloaded with Incumbent? // Returns Dominates if Candidate is always called, Dominated if Incumbent is -// always called, BothViable if either may be called dependending on arguments. +// always called, BothViable if either may be called depending on arguments. // Precondition: must actually be overloads! static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate, const CXXMethodDecl &Incumbent, @@ -1230,8 +1232,8 @@ static OverloadCompare compareOverloads(const CXXMethodDecl &Candidate, if (Candidate.parameters()[I]->getType().getCanonicalType() != Incumbent.parameters()[I]->getType().getCanonicalType()) return OverloadCompare::BothViable; - if (!llvm::empty(Candidate.specific_attrs<EnableIfAttr>()) || - !llvm::empty(Incumbent.specific_attrs<EnableIfAttr>())) + if (!Candidate.specific_attrs<EnableIfAttr>().empty() || + !Incumbent.specific_attrs<EnableIfAttr>().empty()) return OverloadCompare::BothViable; // At this point, we know calls can't pick one or the other based on // arguments, so one of the two must win. (Or both fail, handled elsewhere). @@ -1273,7 +1275,8 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, getBasePriority(Using->getTargetDecl()), R.Qualifier, false, (R.Availability == CXAvailability_Available || - R.Availability == CXAvailability_Deprecated)); + R.Availability == CXAvailability_Deprecated), + std::move(R.FixIts)); Result.ShadowDecl = Using; AddResult(Result, CurContext, Hiding); return; @@ -1377,6 +1380,33 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, OverloadSet.Add(Method, Results.size()); } + // When completing a non-static member function (and not via + // dot/arrow member access) and we're not inside that class' scope, + // it can't be a call. + if (CompletionContext.getKind() == clang::CodeCompletionContext::CCC_Symbol) { + const auto *Method = dyn_cast<CXXMethodDecl>(R.getDeclaration()); + if (Method && !Method->isStatic()) { + // Find the class scope that we're currently in. + // We could e.g. be inside a lambda, so walk up the DeclContext until we + // find a CXXMethodDecl. + const auto *CurrentClassScope = [&]() -> const CXXRecordDecl * { + for (DeclContext *Ctx = SemaRef.CurContext; Ctx; + Ctx = Ctx->getParent()) { + const auto *CtxMethod = llvm::dyn_cast<CXXMethodDecl>(Ctx); + if (CtxMethod && !CtxMethod->getParent()->isLambda()) { + return CtxMethod->getParent(); + } + } + return nullptr; + }(); + + R.FunctionCanBeCall = + CurrentClassScope && + (CurrentClassScope == Method->getParent() || + CurrentClassScope->isDerivedFrom(Method->getParent())); + } + } + // Insert this result into the set of results. Results.push_back(R); @@ -1807,7 +1837,7 @@ static void AddFunctionSpecifiers(Sema::ParserCompletionContext CCC, Results.AddResult(Result("mutable")); Results.AddResult(Result("virtual")); } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::PCC_ObjCInterface: case Sema::PCC_ObjCImplementation: @@ -2095,7 +2125,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, AddObjCTopLevelResults(Results, true); AddTypedefResult(Results); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::PCC_Class: if (SemaRef.getLangOpts().CPlusPlus) { @@ -2153,7 +2183,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Builder); } } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::PCC_Template: case Sema::PCC_MemberTemplate: @@ -2423,14 +2453,14 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, AddStaticAssertResult(Builder, Results, SemaRef.getLangOpts()); } - LLVM_FALLTHROUGH; + [[fallthrough]]; // Fall through (for statement expressions). case Sema::PCC_ForInit: case Sema::PCC_Condition: AddStorageSpecifiers(CCC, SemaRef.getLangOpts(), Results); // Fall through: conditions and statements can have expressions. - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::PCC_ParenthesizedExpression: if (SemaRef.getLangOpts().ObjCAutoRefCount && @@ -2460,7 +2490,7 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Results.AddResult(Result(Builder.TakeString())); } // Fall through - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::PCC_Expression: { if (SemaRef.getLangOpts().CPlusPlus) { @@ -2643,6 +2673,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Results.AddResult(Result(Builder.TakeString())); } + if (SemaRef.getLangOpts().C2x) { + // nullptr + Builder.AddResultTypeChunk("nullptr_t"); + Builder.AddTypedTextChunk("nullptr"); + Results.AddResult(Result(Builder.TakeString())); + } + // sizeof expression Builder.AddResultTypeChunk("size_t"); Builder.AddTypedTextChunk("sizeof"); @@ -2783,7 +2820,7 @@ static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo, while (true) { // Look through typedefs. if (!SuppressBlock) { - if (TypedefTypeLoc TypedefTL = TL.getAs<TypedefTypeLoc>()) { + if (TypedefTypeLoc TypedefTL = TL.getAsAdjusted<TypedefTypeLoc>()) { if (TypeSourceInfo *InnerTSInfo = TypedefTL.getTypedefNameDecl()->getTypeSourceInfo()) { TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc(); @@ -2814,18 +2851,16 @@ static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo, } } -static std::string -formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, - FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, - bool SuppressBlockName = false, - bool SuppressBlock = false, - Optional<ArrayRef<QualType>> ObjCSubsts = None); +static std::string formatBlockPlaceholder( + const PrintingPolicy &Policy, const NamedDecl *BlockDecl, + FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, + bool SuppressBlockName = false, bool SuppressBlock = false, + std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt); -static std::string -FormatFunctionParameter(const PrintingPolicy &Policy, - const DeclaratorDecl *Param, bool SuppressName = false, - bool SuppressBlock = false, - Optional<ArrayRef<QualType>> ObjCSubsts = None) { +static std::string FormatFunctionParameter( + const PrintingPolicy &Policy, const DeclaratorDecl *Param, + bool SuppressName = false, bool SuppressBlock = false, + std::optional<ArrayRef<QualType>> ObjCSubsts = std::nullopt) { // Params are unavailable in FunctionTypeLoc if the FunctionType is invalid. // It would be better to pass in the param Type, which is usually available. // But this case is rare, so just pretend we fell back to int as elsewhere. @@ -2920,7 +2955,7 @@ static std::string formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, bool SuppressBlockName, bool SuppressBlock, - Optional<ArrayRef<QualType>> ObjCSubsts) { + std::optional<ArrayRef<QualType>> ObjCSubsts) { std::string Result; QualType ResultType = Block.getTypePtr()->getReturnType(); if (ObjCSubsts) @@ -3589,7 +3624,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( std::string Arg; QualType ParamType = (*P)->getType(); - Optional<ArrayRef<QualType>> ObjCSubsts; + std::optional<ArrayRef<QualType>> ObjCSubsts; if (!CCContext.getBaseType().isNull()) ObjCSubsts = CCContext.getBaseType()->getObjCSubstitutions(Method); @@ -4199,7 +4234,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, // We need to have names for all of the parameters, if we're going to // generate a forwarding call. - for (auto P : Method->parameters()) + for (auto *P : Method->parameters()) if (!P->getDeclName()) return; @@ -4227,7 +4262,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, Results.getAllocator().CopyString(Overridden->getNameAsString())); Builder.AddChunk(CodeCompletionString::CK_LeftParen); bool FirstParam = true; - for (auto P : Method->parameters()) { + for (auto *P : Method->parameters()) { if (FirstParam) FirstParam = false; else @@ -4444,7 +4479,8 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, 0) { ParsedType T = DS.getRepAsType(); if (!T.get().isNull() && T.get()->isObjCObjectOrInterfaceType()) - AddClassMessageCompletions(*this, S, T, None, false, false, Results); + AddClassMessageCompletions(*this, S, T, std::nullopt, false, false, + Results); } // Note that we intentionally suppress macro results here, since we do not @@ -4657,9 +4693,9 @@ static const FunctionProtoType *TryDeconstructFunctionLike(QualType T) { // Note we only handle the sugared types, they closely match what users wrote. // We explicitly choose to not handle ClassTemplateSpecializationDecl. if (auto *Specialization = T->getAs<TemplateSpecializationType>()) { - if (Specialization->getNumArgs() != 1) + if (Specialization->template_arguments().size() != 1) return nullptr; - const TemplateArgument &Argument = Specialization->getArg(0); + const TemplateArgument &Argument = Specialization->template_arguments()[0]; if (Argument.getKind() != TemplateArgument::Type) return nullptr; return Argument.getAsType()->getAs<FunctionProtoType>(); @@ -4801,7 +4837,7 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E, if (E.isInvalid()) CodeCompleteExpression(S, PreferredType); else if (getLangOpts().ObjC) - CodeCompleteObjCInstanceMessage(S, E.get(), None, false); + CodeCompleteObjCInstanceMessage(S, E.get(), std::nullopt, false); } /// The set of properties that have already been added, referenced by @@ -5045,9 +5081,11 @@ AddObjCProperties(const CodeCompletionContext &CCContext, } } -static void AddRecordMembersCompletionResults( - Sema &SemaRef, ResultBuilder &Results, Scope *S, QualType BaseType, - ExprValueKind BaseKind, RecordDecl *RD, Optional<FixItHint> AccessOpFixIt) { +static void +AddRecordMembersCompletionResults(Sema &SemaRef, ResultBuilder &Results, + Scope *S, QualType BaseType, + ExprValueKind BaseKind, RecordDecl *RD, + std::optional<FixItHint> AccessOpFixIt) { // Indicate that we are performing a member access, and the cv-qualifiers // for the base object type. Results.setObjectTypeQualifiers(BaseType.getQualifiers(), BaseKind); @@ -5086,7 +5124,8 @@ static void AddRecordMembersCompletionResults( // Returns the RecordDecl inside the BaseType, falling back to primary template // in case of specializations. Since we might not have a decl for the // instantiation/specialization yet, e.g. dependent code. -static RecordDecl *getAsRecordDecl(const QualType BaseType) { +static RecordDecl *getAsRecordDecl(QualType BaseType) { + BaseType = BaseType.getNonReferenceType(); if (auto *RD = BaseType->getAsRecordDecl()) { if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(RD)) { @@ -5145,7 +5184,7 @@ public: // We don't have the declared parameter types, only the actual types of // arguments we've seen. These are still valuable, as it's hard to render // a useful function completion with neither parameter types nor names! - llvm::Optional<SmallVector<QualType, 1>> ArgTypes; + std::optional<SmallVector<QualType, 1>> ArgTypes; // Whether this is accessed as T.member, T->member, or T::member. enum AccessOperator { Colons, @@ -5475,11 +5514,16 @@ private: // We accept some lossiness (like dropping parameters). // We only try to handle common expressions on the LHS of MemberExpr. QualType getApproximateType(const Expr *E) { + if (E->getType().isNull()) + return QualType(); + E = E->IgnoreParenImpCasts(); QualType Unresolved = E->getType(); - if (Unresolved.isNull() || - !Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) - return Unresolved; - E = E->IgnoreParens(); + // We only resolve DependentTy, or undeduced autos (including auto* etc). + if (!Unresolved->isSpecificBuiltinType(BuiltinType::Dependent)) { + AutoType *Auto = Unresolved->getContainedAutoType(); + if (!Auto || !Auto->isUndeducedAutoType()) + return Unresolved; + } // A call: approximate-resolve callee to a function type, get its return type if (const CallExpr *CE = llvm::dyn_cast<CallExpr>(E)) { QualType Callee = getApproximateType(CE->getCallee()); @@ -5542,6 +5586,13 @@ QualType getApproximateType(const Expr *E) { } } } + // A reference to an `auto` variable: approximate-resolve its initializer. + if (const auto *DRE = llvm::dyn_cast<DeclRefExpr>(E)) { + if (const auto *VD = llvm::dyn_cast<VarDecl>(DRE->getDecl())) { + if (VD->hasInit()) + return getApproximateType(VD->getInit()); + } + } return Unresolved; } @@ -5600,7 +5651,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, &ResultBuilder::IsMember); auto DoCompletion = [&](Expr *Base, bool IsArrow, - Optional<FixItHint> AccessOpFixIt) -> bool { + std::optional<FixItHint> AccessOpFixIt) -> bool { if (!Base) return false; @@ -5698,7 +5749,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Results.EnterNewScope(); - bool CompletionSucceded = DoCompletion(Base, IsArrow, None); + bool CompletionSucceded = DoCompletion(Base, IsArrow, std::nullopt); if (CodeCompleter->includeFixIts()) { const CharSourceRange OpRange = CharSourceRange::getTokenRange(OpLoc, OpLoc); @@ -6157,8 +6208,8 @@ QualType Sema::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args, // Only aggregate initialization is possible, but we can't assist with it. // Returns an out-of-range index. // - we saw no designators, just positional arguments. -// Returns None. -static llvm::Optional<unsigned> +// Returns std::nullopt. +static std::optional<unsigned> getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate, ArrayRef<Expr *> Args) { static constexpr unsigned Invalid = std::numeric_limits<unsigned>::max(); @@ -6183,7 +6234,7 @@ getNextAggregateIndexAfterDesignatedInit(const ResultCandidate &Aggregate, } } if (!DesignatedFieldName) - return llvm::None; + return std::nullopt; // Find the index within the class's fields. // (Probing getParamDecl() directly would be quadratic in number of fields). @@ -7537,7 +7588,8 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) { Results.EnterNewScope(); VisitedSelectorSet Selectors; - AddObjCMethods(Class, true, MK_ZeroArgSelector, None, CurContext, Selectors, + AddObjCMethods(Class, true, MK_ZeroArgSelector, std::nullopt, CurContext, + Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), @@ -7563,7 +7615,8 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) { Results.EnterNewScope(); VisitedSelectorSet Selectors; - AddObjCMethods(Class, true, MK_OneArgSelector, None, CurContext, Selectors, + AddObjCMethods(Class, true, MK_OneArgSelector, std::nullopt, CurContext, + Selectors, /*AllowSameLength=*/true, Results); Results.ExitScope(); @@ -7859,7 +7912,8 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { if (Iface->getSuperClass()) { Results.AddResult(Result("super")); - AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, None, Results); + AddSuperSendCompletion(*this, /*NeedSuperKeyword=*/true, std::nullopt, + Results); } if (getLangOpts().CPlusPlus11) @@ -8505,7 +8559,7 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCCategoryName); - // Add all of the categories that have have corresponding interface + // Add all of the categories that have corresponding interface // declarations in this class and any of its superclasses, except for // already-implemented categories in the class itself. llvm::SmallPtrSet<IdentifierInfo *, 16> CategoryNames; @@ -8669,7 +8723,7 @@ typedef llvm::DenseMap<Selector, /// indexed by selector so they can be easily found. static void FindImplementableMethods(ASTContext &Context, ObjCContainerDecl *Container, - Optional<bool> WantInstanceMethods, + std::optional<bool> WantInstanceMethods, QualType ReturnType, KnownMethodsMap &KnownMethods, bool InOriginalClass = true) { @@ -9393,7 +9447,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, } } -void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, +void Sema::CodeCompleteObjCMethodDecl(Scope *S, + std::optional<bool> IsInstanceMethod, ParsedType ReturnTy) { // Determine the return type of the method we're declaring, if // provided. @@ -9978,10 +10033,10 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { break; case llvm::sys::fs::file_type::regular_file: { // Only files that really look like headers. (Except in special dirs). - // Header extensions from Types.def, which we can't depend on here. const bool IsHeader = Filename.endswith_insensitive(".h") || Filename.endswith_insensitive(".hh") || Filename.endswith_insensitive(".hpp") || + Filename.endswith_insensitive(".hxx") || Filename.endswith_insensitive(".inc") || (ExtensionlessHeaders && !Filename.contains('.')); if (!IsHeader) @@ -10048,7 +10103,7 @@ void Sema::CodeCompleteAvailabilityPlatformName() { CodeCompletionContext::CCC_Other); Results.EnterNewScope(); static const char *Platforms[] = {"macOS", "iOS", "watchOS", "tvOS"}; - for (const char *Platform : llvm::makeArrayRef(Platforms)) { + for (const char *Platform : llvm::ArrayRef(Platforms)) { Results.AddResult(CodeCompletionResult(Platform)); Results.AddResult(CodeCompletionResult(Results.getAllocator().CopyString( Twine(Platform) + "ApplicationExtension"))); diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 239e5dc4394c..4d4b2482d046 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "TreeTransform.h" #include "clang/Sema/SemaConcept.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" @@ -18,18 +19,21 @@ #include "clang/Sema/Template.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Initialization.h" +#include "clang/AST/ASTLambda.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/OperatorPrecedence.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/StringExtras.h" +#include <optional> using namespace clang; using namespace sema; namespace { class LogicalBinOp { + SourceLocation Loc; OverloadedOperatorKind Op = OO_None; const Expr *LHS = nullptr; const Expr *RHS = nullptr; @@ -40,12 +44,14 @@ public: Op = BinaryOperator::getOverloadedOperator(BO->getOpcode()); LHS = BO->getLHS(); RHS = BO->getRHS(); + Loc = BO->getExprLoc(); } else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) { // If OO is not || or && it might not have exactly 2 arguments. if (OO->getNumArgs() == 2) { Op = OO->getOperator(); LHS = OO->getArg(0); RHS = OO->getArg(1); + Loc = OO->getOperatorLoc(); } } } @@ -56,6 +62,26 @@ public: const Expr *getLHS() const { return LHS; } const Expr *getRHS() const { return RHS; } + + ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS) const { + return recreateBinOp(SemaRef, LHS, const_cast<Expr *>(getRHS())); + } + + ExprResult recreateBinOp(Sema &SemaRef, ExprResult LHS, + ExprResult RHS) const { + assert((isAnd() || isOr()) && "Not the right kind of op?"); + assert((!LHS.isInvalid() && !RHS.isInvalid()) && "not good expressions?"); + + if (!LHS.isUsable() || !RHS.isUsable()) + return ExprEmpty(); + + // We should just be able to 'normalize' these to the builtin Binary + // Operator, since that is how they are evaluated in constriant checks. + return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(), + BinaryOperator::getOverloadedOpcode(Op), + SemaRef.Context.BoolTy, VK_PRValue, + OK_Ordinary, Loc, FPOptionsOverride{}); + } }; } @@ -121,17 +147,30 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression, return true; } +namespace { +struct SatisfactionStackRAII { + Sema &SemaRef; + SatisfactionStackRAII(Sema &SemaRef, llvm::FoldingSetNodeID FSNID) + : SemaRef(SemaRef) { + SemaRef.PushSatisfactionStackEntry(FSNID); + } + ~SatisfactionStackRAII() { SemaRef.PopSatisfactionStackEntry(); } +}; +} // namespace + template <typename AtomicEvaluator> -static bool +static ExprResult calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction, AtomicEvaluator &&Evaluator) { ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); if (LogicalBinOp BO = ConstraintExpr) { - if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction, - Evaluator)) - return true; + ExprResult LHSRes = calculateConstraintSatisfaction( + S, BO.getLHS(), Satisfaction, Evaluator); + + if (LHSRes.isInvalid()) + return ExprError(); bool IsLHSSatisfied = Satisfaction.IsSatisfied; @@ -142,7 +181,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, // is checked. If that is satisfied, the disjunction is satisfied. // Otherwise, the disjunction is satisfied if and only if the second // operand is satisfied. - return false; + // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp. + return LHSRes; if (BO.isAnd() && !IsLHSSatisfied) // [temp.constr.op] p2 @@ -151,12 +191,22 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, // is checked. If that is not satisfied, the conjunction is not // satisfied. Otherwise, the conjunction is satisfied if and only if // the second operand is satisfied. - return false; + // LHS is instantiated while RHS is not. Skip creating invalid BinaryOp. + return LHSRes; - return calculateConstraintSatisfaction( + ExprResult RHSRes = calculateConstraintSatisfaction( S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator)); - } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) { - return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction, + if (RHSRes.isInvalid()) + return ExprError(); + + return BO.recreateBinOp(S, LHSRes, RHSRes); + } + + if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) { + // These aren't evaluated, so we don't care about cleanups, so we can just + // evaluate these as if the cleanups didn't exist. + return calculateConstraintSatisfaction( + S, C->getSubExpr(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator)); } @@ -164,11 +214,35 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr); if (SubstitutedAtomicExpr.isInvalid()) - return true; + return ExprError(); if (!SubstitutedAtomicExpr.isUsable()) // Evaluator has decided satisfaction without yielding an expression. - return false; + return ExprEmpty(); + + // We don't have the ability to evaluate this, since it contains a + // RecoveryExpr, so we want to fail overload resolution. Otherwise, + // we'd potentially pick up a different overload, and cause confusing + // diagnostics. SO, add a failure detail that will cause us to make this + // overload set not viable. + if (SubstitutedAtomicExpr.get()->containsErrors()) { + Satisfaction.IsSatisfied = false; + Satisfaction.ContainsErrors = true; + + PartialDiagnostic Msg = S.PDiag(diag::note_constraint_references_error); + SmallString<128> DiagString; + DiagString = ": "; + Msg.EmitToString(S.getDiagnostics(), DiagString); + unsigned MessageSize = DiagString.size(); + char *Mem = new (S.Context) char[MessageSize]; + memcpy(Mem, DiagString.c_str(), MessageSize); + Satisfaction.Details.emplace_back( + ConstraintExpr, + new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{ + SubstitutedAtomicExpr.get()->getBeginLoc(), + StringRef(Mem, MessageSize)}); + return SubstitutedAtomicExpr; + } EnterExpressionEvaluationContext ConstantEvaluated( S, Sema::ExpressionEvaluationContext::ConstantEvaluated); @@ -185,7 +259,7 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, << SubstitutedAtomicExpr.get()->getSourceRange(); for (const PartialDiagnosticAt &PDiag : EvaluationDiags) S.Diag(PDiag.first, PDiag.second); - return true; + return ExprError(); } assert(EvalResult.Val.isInt() && @@ -195,17 +269,41 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, Satisfaction.Details.emplace_back(ConstraintExpr, SubstitutedAtomicExpr.get()); + return SubstitutedAtomicExpr; +} + +static bool +DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID, const Expr *E, + const MultiLevelTemplateArgumentList &MLTAL) { + E->Profile(ID, S.Context, /*Canonical=*/true); + for (const auto &List : MLTAL) + for (const auto &TemplateArg : List.Args) + TemplateArg.Profile(ID, S.Context); + + // Note that we have to do this with our own collection, because there are + // times where a constraint-expression check can cause us to need to evaluate + // other constriants that are unrelated, such as when evaluating a recovery + // expression, or when trying to determine the constexpr-ness of special + // members. Otherwise we could just use the + // Sema::InstantiatingTemplate::isAlreadyBeingInstantiated function. + if (S.SatisfactionStackContains(ID)) { + S.Diag(E->getExprLoc(), diag::err_constraint_depends_on_self) + << const_cast<Expr *>(E) << E->getSourceRange(); + return true; + } + return false; } -static bool calculateConstraintSatisfaction( - Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, - SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL, - const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { +static ExprResult calculateConstraintSatisfaction( + Sema &S, const NamedDecl *Template, SourceLocation TemplateNameLoc, + const MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr, + ConstraintSatisfaction &Satisfaction) { return calculateConstraintSatisfaction( S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) { EnterExpressionEvaluationContext ConstantEvaluated( - S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + S, Sema::ExpressionEvaluationContext::ConstantEvaluated, + Sema::ReuseLambdaContextDecl); // Atomic constraint - substitute arguments and check satisfaction. ExprResult SubstitutedExpression; @@ -217,17 +315,21 @@ static bool calculateConstraintSatisfaction( AtomicExpr->getSourceRange()); if (Inst.isInvalid()) return ExprError(); + + llvm::FoldingSetNodeID ID; + if (DiagRecursiveConstraintEval(S, ID, AtomicExpr, MLTAL)) { + Satisfaction.IsSatisfied = false; + Satisfaction.ContainsErrors = true; + return ExprEmpty(); + } + + SatisfactionStackRAII StackRAII(S, ID); + // We do not want error diagnostics escaping here. Sema::SFINAETrap Trap(S); - SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr), - MLTAL); - // Substitution might have stripped off a contextual conversion to - // bool if this is the operand of an '&&' or '||'. For example, we - // might lose an lvalue-to-rvalue conversion here. If so, put it back - // before we try to evaluate. - if (!SubstitutedExpression.isInvalid()) - SubstitutedExpression = - S.PerformContextuallyConvertToBool(SubstitutedExpression.get()); + SubstitutedExpression = + S.SubstConstraintExpr(const_cast<Expr *>(AtomicExpr), MLTAL); + if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) { // C++2a [temp.constr.atomic]p1 // ...If substitution results in an invalid type or expression, the @@ -264,78 +366,129 @@ static bool calculateConstraintSatisfaction( if (!S.CheckConstraintExpression(SubstitutedExpression.get())) return ExprError(); + // [temp.constr.atomic]p3: To determine if an atomic constraint is + // satisfied, the parameter mapping and template arguments are first + // substituted into its expression. If substitution results in an + // invalid type or expression, the constraint is not satisfied. + // Otherwise, the lvalue-to-rvalue conversion is performed if necessary, + // and E shall be a constant expression of type bool. + // + // Perform the L to R Value conversion if necessary. We do so for all + // non-PRValue categories, else we fail to extend the lifetime of + // temporaries, and that fails the constant expression check. + if (!SubstitutedExpression.get()->isPRValue()) + SubstitutedExpression = ImplicitCastExpr::Create( + S.Context, SubstitutedExpression.get()->getType(), + CK_LValueToRValue, SubstitutedExpression.get(), + /*BasePath=*/nullptr, VK_PRValue, FPOptionsOverride()); + return SubstitutedExpression; }); } -static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template, - ArrayRef<const Expr *> ConstraintExprs, - ArrayRef<TemplateArgument> TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { +static bool CheckConstraintSatisfaction( + Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, + llvm::SmallVectorImpl<Expr *> &Converted, + const MultiLevelTemplateArgumentList &TemplateArgsLists, + SourceRange TemplateIDRange, ConstraintSatisfaction &Satisfaction) { if (ConstraintExprs.empty()) { Satisfaction.IsSatisfied = true; return false; } - for (auto& Arg : TemplateArgs) - if (Arg.isInstantiationDependent()) { - // No need to check satisfaction for dependent constraint expressions. - Satisfaction.IsSatisfied = true; - return false; - } + if (TemplateArgsLists.isAnyArgInstantiationDependent()) { + // No need to check satisfaction for dependent constraint expressions. + Satisfaction.IsSatisfied = true; + return false; + } + ArrayRef<TemplateArgument> TemplateArgs = + TemplateArgsLists.getNumSubstitutedLevels() > 0 + ? TemplateArgsLists.getOutermost() + : ArrayRef<TemplateArgument> {}; Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), Sema::InstantiatingTemplate::ConstraintsCheck{}, const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange); if (Inst.isInvalid()) return true; - MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(TemplateArgs); - for (const Expr *ConstraintExpr : ConstraintExprs) { - if (calculateConstraintSatisfaction(S, Template, TemplateArgs, - TemplateIDRange.getBegin(), MLTAL, - ConstraintExpr, Satisfaction)) + ExprResult Res = calculateConstraintSatisfaction( + S, Template, TemplateIDRange.getBegin(), TemplateArgsLists, + ConstraintExpr, Satisfaction); + if (Res.isInvalid()) return true; - if (!Satisfaction.IsSatisfied) + + Converted.push_back(Res.get()); + if (!Satisfaction.IsSatisfied) { + // Backfill the 'converted' list with nulls so we can keep the Converted + // and unconverted lists in sync. + Converted.append(ConstraintExprs.size() - Converted.size(), nullptr); // [temp.constr.op] p2 - // [...] To determine if a conjunction is satisfied, the satisfaction - // of the first operand is checked. If that is not satisfied, the - // conjunction is not satisfied. [...] + // [...] To determine if a conjunction is satisfied, the satisfaction + // of the first operand is checked. If that is not satisfied, the + // conjunction is not satisfied. [...] return false; + } } return false; } bool Sema::CheckConstraintSatisfaction( const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, - ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange, - ConstraintSatisfaction &OutSatisfaction) { + llvm::SmallVectorImpl<Expr *> &ConvertedConstraints, + const MultiLevelTemplateArgumentList &TemplateArgsLists, + SourceRange TemplateIDRange, ConstraintSatisfaction &OutSatisfaction) { if (ConstraintExprs.empty()) { OutSatisfaction.IsSatisfied = true; return false; } if (!Template) { - return ::CheckConstraintSatisfaction(*this, nullptr, ConstraintExprs, - TemplateArgs, TemplateIDRange, - OutSatisfaction); + return ::CheckConstraintSatisfaction( + *this, nullptr, ConstraintExprs, ConvertedConstraints, + TemplateArgsLists, TemplateIDRange, OutSatisfaction); } + + // A list of the template argument list flattened in a predictible manner for + // the purposes of caching. The ConstraintSatisfaction type is in AST so it + // has no access to the MultiLevelTemplateArgumentList, so this has to happen + // here. + llvm::SmallVector<TemplateArgument, 4> FlattenedArgs; + for (auto List : TemplateArgsLists) + FlattenedArgs.insert(FlattenedArgs.end(), List.Args.begin(), + List.Args.end()); + llvm::FoldingSetNodeID ID; - ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs); + ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs); void *InsertPos; if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) { OutSatisfaction = *Cached; return false; } + auto Satisfaction = - std::make_unique<ConstraintSatisfaction>(Template, TemplateArgs); + std::make_unique<ConstraintSatisfaction>(Template, FlattenedArgs); if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, - TemplateArgs, TemplateIDRange, - *Satisfaction)) { + ConvertedConstraints, TemplateArgsLists, + TemplateIDRange, *Satisfaction)) { + OutSatisfaction = *Satisfaction; return true; } + + if (auto *Cached = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos)) { + // The evaluation of this constraint resulted in us trying to re-evaluate it + // recursively. This isn't really possible, except we try to form a + // RecoveryExpr as a part of the evaluation. If this is the case, just + // return the 'cached' version (which will have the same result), and save + // ourselves the extra-insert. If it ever becomes possible to legitimately + // recursively check a constraint, we should skip checking the 'inner' one + // above, and replace the cached version with this one, as it would be more + // specific. + OutSatisfaction = *Cached; + return false; + } + + // Else we can simply add this satisfaction to the list. OutSatisfaction = *Satisfaction; // We cannot use InsertPos here because CheckConstraintSatisfaction might have // invalidated it. @@ -347,21 +500,133 @@ bool Sema::CheckConstraintSatisfaction( bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { return calculateConstraintSatisfaction( - *this, ConstraintExpr, Satisfaction, - [this](const Expr *AtomicExpr) -> ExprResult { - // We only do this to immitate lvalue-to-rvalue conversion. - return PerformContextuallyConvertToBool(const_cast<Expr *>(AtomicExpr)); - }); + *this, ConstraintExpr, Satisfaction, + [this](const Expr *AtomicExpr) -> ExprResult { + // We only do this to immitate lvalue-to-rvalue conversion. + return PerformContextuallyConvertToBool( + const_cast<Expr *>(AtomicExpr)); + }) + .isInvalid(); +} + +bool Sema::SetupConstraintScope( + FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, + MultiLevelTemplateArgumentList MLTAL, LocalInstantiationScope &Scope) { + if (FD->isTemplateInstantiation() && FD->getPrimaryTemplate()) { + FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate(); + InstantiatingTemplate Inst( + *this, FD->getPointOfInstantiation(), + Sema::InstantiatingTemplate::ConstraintsCheck{}, PrimaryTemplate, + TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{}, + SourceRange()); + if (Inst.isInvalid()) + return true; + + // addInstantiatedParametersToScope creates a map of 'uninstantiated' to + // 'instantiated' parameters and adds it to the context. For the case where + // this function is a template being instantiated NOW, we also need to add + // the list of current template arguments to the list so that they also can + // be picked out of the map. + if (auto *SpecArgs = FD->getTemplateSpecializationArgs()) { + MultiLevelTemplateArgumentList JustTemplArgs(FD, SpecArgs->asArray(), + /*Final=*/false); + if (addInstantiatedParametersToScope( + FD, PrimaryTemplate->getTemplatedDecl(), Scope, JustTemplArgs)) + return true; + } + + // If this is a member function, make sure we get the parameters that + // reference the original primary template. + if (const auto *FromMemTempl = + PrimaryTemplate->getInstantiatedFromMemberTemplate()) { + if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(), + Scope, MLTAL)) + return true; + } + + return false; + } + + if (FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization || + FD->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate) { + FunctionDecl *InstantiatedFrom = + FD->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization + ? FD->getInstantiatedFromMemberFunction() + : FD->getInstantiatedFromDecl(); + + InstantiatingTemplate Inst( + *this, FD->getPointOfInstantiation(), + Sema::InstantiatingTemplate::ConstraintsCheck{}, InstantiatedFrom, + TemplateArgs ? *TemplateArgs : ArrayRef<TemplateArgument>{}, + SourceRange()); + if (Inst.isInvalid()) + return true; + + // Case where this was not a template, but instantiated as a + // child-function. + if (addInstantiatedParametersToScope(FD, InstantiatedFrom, Scope, MLTAL)) + return true; + } + + return false; +} + +// This function collects all of the template arguments for the purposes of +// constraint-instantiation and checking. +std::optional<MultiLevelTemplateArgumentList> +Sema::SetupConstraintCheckingTemplateArgumentsAndScope( + FunctionDecl *FD, std::optional<ArrayRef<TemplateArgument>> TemplateArgs, + LocalInstantiationScope &Scope) { + MultiLevelTemplateArgumentList MLTAL; + + // Collect the list of template arguments relative to the 'primary' template. + // We need the entire list, since the constraint is completely uninstantiated + // at this point. + MLTAL = + getTemplateInstantiationArgs(FD, /*Final=*/false, /*Innermost=*/nullptr, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); + if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope)) + return std::nullopt; + + return MLTAL; } bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, ConstraintSatisfaction &Satisfaction, - SourceLocation UsageLoc) { - const Expr *RC = FD->getTrailingRequiresClause(); - if (RC->isInstantiationDependent()) { + SourceLocation UsageLoc, + bool ForOverloadResolution) { + // Don't check constraints if the function is dependent. Also don't check if + // this is a function template specialization, as the call to + // CheckinstantiatedFunctionTemplateConstraints after this will check it + // better. + if (FD->isDependentContext() || + FD->getTemplatedKind() == + FunctionDecl::TK_FunctionTemplateSpecialization) { Satisfaction.IsSatisfied = true; return false; } + + DeclContext *CtxToSave = const_cast<FunctionDecl *>(FD); + + while (isLambdaCallOperator(CtxToSave) || FD->isTransparentContext()) { + if (isLambdaCallOperator(CtxToSave)) + CtxToSave = CtxToSave->getParent()->getParent(); + else + CtxToSave = CtxToSave->getNonTransparentContext(); + } + + ContextRAII SavedContext{*this, CtxToSave}; + LocalInstantiationScope Scope(*this, !ForOverloadResolution || + isLambdaCallOperator(FD)); + std::optional<MultiLevelTemplateArgumentList> MLTAL = + SetupConstraintCheckingTemplateArgumentsAndScope( + const_cast<FunctionDecl *>(FD), {}, Scope); + + if (!MLTAL) + return true; + Qualifiers ThisQuals; CXXRecordDecl *Record = nullptr; if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) { @@ -372,19 +637,124 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, // We substitute with empty arguments in order to rebuild the atomic // constraint in a constant-evaluated context. // FIXME: Should this be a dedicated TreeTransform? - return CheckConstraintSatisfaction( - FD, {RC}, /*TemplateArgs=*/{}, - SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), - Satisfaction); + const Expr *RC = FD->getTrailingRequiresClause(); + llvm::SmallVector<Expr *, 1> Converted; + + if (CheckConstraintSatisfaction( + FD, {RC}, Converted, *MLTAL, + SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), + Satisfaction)) + return true; + + // FIXME: we need to do this for the function constraints for + // comparison of constraints to work, but do we also need to do it for + // CheckInstantiatedFunctionConstraints? That one is more difficult, but we + // seem to always just pick up the constraints from the primary template. + assert(Converted.size() <= 1 && "Got more expressions converted?"); + if (!Converted.empty() && Converted[0] != nullptr) + const_cast<FunctionDecl *>(FD)->setTrailingRequiresClause(Converted[0]); + return false; +} + + +// Figure out the to-translation-unit depth for this function declaration for +// the purpose of seeing if they differ by constraints. This isn't the same as +// getTemplateDepth, because it includes already instantiated parents. +static unsigned +CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND, + bool SkipForSpecialization = false) { + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( + ND, /*Final=*/false, /*Innermost=*/nullptr, /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true, SkipForSpecialization); + return MLTAL.getNumSubstitutedLevels(); +} + +namespace { + class AdjustConstraintDepth : public TreeTransform<AdjustConstraintDepth> { + unsigned TemplateDepth = 0; + public: + using inherited = TreeTransform<AdjustConstraintDepth>; + AdjustConstraintDepth(Sema &SemaRef, unsigned TemplateDepth) + : inherited(SemaRef), TemplateDepth(TemplateDepth) {} + + using inherited::TransformTemplateTypeParmType; + QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, + TemplateTypeParmTypeLoc TL, bool) { + const TemplateTypeParmType *T = TL.getTypePtr(); + + TemplateTypeParmDecl *NewTTPDecl = nullptr; + if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl()) + NewTTPDecl = cast_or_null<TemplateTypeParmDecl>( + TransformDecl(TL.getNameLoc(), OldTTPDecl)); + + QualType Result = getSema().Context.getTemplateTypeParmType( + T->getDepth() + TemplateDepth, T->getIndex(), T->isParameterPack(), + NewTTPDecl); + TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + }; +} // namespace + +bool Sema::AreConstraintExpressionsEqual(const NamedDecl *Old, + const Expr *OldConstr, + const NamedDecl *New, + const Expr *NewConstr) { + if (Old && New && Old != New) { + unsigned Depth1 = CalculateTemplateDepthForConstraints( + *this, Old); + unsigned Depth2 = CalculateTemplateDepthForConstraints( + *this, New); + + // Adjust the 'shallowest' verison of this to increase the depth to match + // the 'other'. + if (Depth2 > Depth1) { + OldConstr = AdjustConstraintDepth(*this, Depth2 - Depth1) + .TransformExpr(const_cast<Expr *>(OldConstr)) + .get(); + } else if (Depth1 > Depth2) { + NewConstr = AdjustConstraintDepth(*this, Depth1 - Depth2) + .TransformExpr(const_cast<Expr *>(NewConstr)) + .get(); + } + } + + llvm::FoldingSetNodeID ID1, ID2; + OldConstr->Profile(ID1, Context, /*Canonical=*/true); + NewConstr->Profile(ID2, Context, /*Canonical=*/true); + return ID1 == ID2; +} + +bool Sema::FriendConstraintsDependOnEnclosingTemplate(const FunctionDecl *FD) { + assert(FD->getFriendObjectKind() && "Must be a friend!"); + + // The logic for non-templates is handled in ASTContext::isSameEntity, so we + // don't have to bother checking 'DependsOnEnclosingTemplate' for a + // non-function-template. + assert(FD->getDescribedFunctionTemplate() && + "Non-function templates don't need to be checked"); + + SmallVector<const Expr *, 3> ACs; + FD->getDescribedFunctionTemplate()->getAssociatedConstraints(ACs); + + unsigned OldTemplateDepth = CalculateTemplateDepthForConstraints(*this, FD); + for (const Expr *Constraint : ACs) + if (ConstraintExpressionDependsOnEnclosingTemplate(FD, OldTemplateDepth, + Constraint)) + return true; + + return false; } bool Sema::EnsureTemplateArgumentListConstraints( - TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs, + TemplateDecl *TD, const MultiLevelTemplateArgumentList &TemplateArgsLists, SourceRange TemplateIDRange) { ConstraintSatisfaction Satisfaction; llvm::SmallVector<const Expr *, 3> AssociatedConstraints; TD->getAssociatedConstraints(AssociatedConstraints); - if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgs, + if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgsLists, TemplateIDRange, Satisfaction)) return true; @@ -392,7 +762,8 @@ bool Sema::EnsureTemplateArgumentListConstraints( SmallString<128> TemplateArgString; TemplateArgString = " "; TemplateArgString += getTemplateArgumentBindingsText( - TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size()); + TD->getTemplateParameters(), TemplateArgsLists.getInnermost().data(), + TemplateArgsLists.getInnermost().size()); Diag(TemplateIDRange.getBegin(), diag::err_template_arg_list_constraints_not_satisfied) @@ -424,21 +795,13 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( Sema::ContextRAII savedContext(*this, Decl); LocalInstantiationScope Scope(*this); - // If this is not an explicit specialization - we need to get the instantiated - // version of the template arguments and add them to scope for the - // substitution. - if (Decl->isTemplateInstantiation()) { - InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(), - InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(), - TemplateArgs, SourceRange()); - if (Inst.isInvalid()) - return true; - MultiLevelTemplateArgumentList MLTAL( - *Decl->getTemplateSpecializationArgs()); - if (addInstantiatedParametersToScope( - Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), Scope, MLTAL)) - return true; - } + std::optional<MultiLevelTemplateArgumentList> MLTAL = + SetupConstraintCheckingTemplateArgumentsAndScope(Decl, TemplateArgs, + Scope); + + if (!MLTAL) + return true; + Qualifiers ThisQuals; CXXRecordDecl *Record = nullptr; if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { @@ -446,7 +809,14 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( Record = Method->getParent(); } CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); - return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs, + FunctionScopeRAII FuncScope(*this); + if (isLambdaCallOperator(Decl)) + PushLambdaScope(); + else + FuncScope.disable(); + + llvm::SmallVector<Expr *, 1> Converted; + return CheckConstraintSatisfaction(Template, TemplateAC, Converted, *MLTAL, PointOfInstantiation, Satisfaction); } @@ -541,31 +911,28 @@ static void diagnoseUnsatisfiedRequirement(Sema &S, return; } } +static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, + Expr *SubstExpr, + bool First = true); static void diagnoseUnsatisfiedRequirement(Sema &S, concepts::NestedRequirement *Req, bool First) { - if (Req->isSubstitutionFailure()) { - concepts::Requirement::SubstitutionDiagnostic *SubstDiag = - Req->getSubstitutionDiagnostic(); - if (!SubstDiag->DiagMessage.empty()) - S.Diag(SubstDiag->DiagLoc, - diag::note_nested_requirement_substitution_error) - << (int)First << SubstDiag->SubstitutedEntity - << SubstDiag->DiagMessage; + using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>; + for (auto &Pair : Req->getConstraintSatisfaction()) { + if (auto *SubstDiag = Pair.second.dyn_cast<SubstitutionDiagnostic *>()) + S.Diag(SubstDiag->first, diag::note_nested_requirement_substitution_error) + << (int)First << Req->getInvalidConstraintEntity() << SubstDiag->second; else - S.Diag(SubstDiag->DiagLoc, - diag::note_nested_requirement_unknown_substitution_error) - << (int)First << SubstDiag->SubstitutedEntity; - return; + diagnoseWellFormedUnsatisfiedConstraintExpr( + S, Pair.second.dyn_cast<Expr *>(), First); + First = false; } - S.DiagnoseUnsatisfiedConstraint(Req->getConstraintSatisfaction(), First); } - static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, Expr *SubstExpr, - bool First = true) { + bool First) { SubstExpr = SubstExpr->IgnoreParenImpCasts(); if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) { switch (BO->getOpcode()) { @@ -645,6 +1012,7 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction()); return; } else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) { + // FIXME: RequiresExpr should store dependent diagnostics. for (concepts::Requirement *Req : RE->getRequirements()) if (!Req->isDependent() && !Req->isSatisfied()) { if (auto *E = dyn_cast<concepts::ExprRequirement>(Req)) @@ -721,34 +1089,33 @@ Sema::getNormalizedAssociatedConstraints( return CacheEntry->second; } -static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, - ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs, - const ASTTemplateArgumentListInfo *ArgsAsWritten) { +static bool +substituteParameterMappings(Sema &S, NormalizedConstraint &N, + ConceptDecl *Concept, + const MultiLevelTemplateArgumentList &MLTAL, + const ASTTemplateArgumentListInfo *ArgsAsWritten) { if (!N.isAtomic()) { - if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs, + if (substituteParameterMappings(S, N.getLHS(), Concept, MLTAL, ArgsAsWritten)) return true; - return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs, + return substituteParameterMappings(S, N.getRHS(), Concept, MLTAL, ArgsAsWritten); } TemplateParameterList *TemplateParams = Concept->getTemplateParameters(); AtomicConstraint &Atomic = *N.getAtomicConstraint(); TemplateArgumentListInfo SubstArgs; - MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(TemplateArgs); if (!Atomic.ParameterMapping) { llvm::SmallBitVector OccurringIndices(TemplateParams->size()); S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false, /*Depth=*/0, OccurringIndices); - Atomic.ParameterMapping.emplace( - MutableArrayRef<TemplateArgumentLoc>( - new (S.Context) TemplateArgumentLoc[OccurringIndices.count()], - OccurringIndices.count())); + TemplateArgumentLoc *TempArgs = + new (S.Context) TemplateArgumentLoc[OccurringIndices.count()]; for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I) if (OccurringIndices[I]) - new (&(*Atomic.ParameterMapping)[J++]) TemplateArgumentLoc( - S.getIdentityTemplateArgumentLoc(TemplateParams->begin()[I], + new (&(TempArgs)[J++]) + TemplateArgumentLoc(S.getIdentityTemplateArgumentLoc( + TemplateParams->begin()[I], // Here we assume we do not support things like // template<typename A, typename B> // concept C = ...; @@ -757,9 +1124,10 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, // struct S { }; // The above currently yields a diagnostic. // We still might have default arguments for concept parameters. - ArgsAsWritten->NumTemplateArgs > I ? - ArgsAsWritten->arguments()[I].getLocation() : - SourceLocation())); + ArgsAsWritten->NumTemplateArgs > I + ? ArgsAsWritten->arguments()[I].getLocation() + : SourceLocation())); + Atomic.ParameterMapping.emplace(TempArgs, OccurringIndices.count()); } Sema::InstantiatingTemplate Inst( S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(), @@ -768,33 +1136,47 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, ArgsAsWritten->arguments().back().getSourceRange().getEnd())); if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs)) return true; - Atomic.ParameterMapping.emplace( - MutableArrayRef<TemplateArgumentLoc>( - new (S.Context) TemplateArgumentLoc[SubstArgs.size()], - SubstArgs.size())); + + TemplateArgumentLoc *TempArgs = + new (S.Context) TemplateArgumentLoc[SubstArgs.size()]; std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(), - N.getAtomicConstraint()->ParameterMapping->begin()); + TempArgs); + Atomic.ParameterMapping.emplace(TempArgs, SubstArgs.size()); return false; } -Optional<NormalizedConstraint> +static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, + const ConceptSpecializationExpr *CSE) { + TemplateArgumentList TAL{TemplateArgumentList::OnStack, + CSE->getTemplateArguments()}; + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( + CSE->getNamedConcept(), /*Final=*/false, &TAL, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); + + return substituteParameterMappings(S, N, CSE->getNamedConcept(), MLTAL, + CSE->getTemplateArgsAsWritten()); +} + +std::optional<NormalizedConstraint> NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef<const Expr *> E) { assert(E.size() != 0); auto Conjunction = fromConstraintExpr(S, D, E[0]); if (!Conjunction) - return None; + return std::nullopt; for (unsigned I = 1; I < E.size(); ++I) { auto Next = fromConstraintExpr(S, D, E[I]); if (!Next) - return None; + return std::nullopt; *Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction), std::move(*Next), CCK_Conjunction); } return Conjunction; } -llvm::Optional<NormalizedConstraint> +std::optional<NormalizedConstraint> NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { assert(E != nullptr); @@ -803,13 +1185,19 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { // - The normal form of an expression (E) is the normal form of E. // [...] E = E->IgnoreParenImpCasts(); + + // C++2a [temp.param]p4: + // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). + // Fold expression is considered atomic constraints per current wording. + // See http://cplusplus.github.io/concepts-ts/ts-active.html#28 + if (LogicalBinOp BO = E) { auto LHS = fromConstraintExpr(S, D, BO.getLHS()); if (!LHS) - return None; + return std::nullopt; auto RHS = fromConstraintExpr(S, D, BO.getRHS()); if (!RHS) - return None; + return std::nullopt; return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS), BO.isAnd() ? CCK_Conjunction : CCK_Disjunction); @@ -833,16 +1221,14 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { SubNF = S.getNormalizedAssociatedConstraints(CD, {CD->getConstraintExpr()}); if (!SubNF) - return None; + return std::nullopt; } - Optional<NormalizedConstraint> New; + std::optional<NormalizedConstraint> New; New.emplace(S.Context, *SubNF); - if (substituteParameterMappings( - S, *New, CSE->getNamedConcept(), - CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten())) - return None; + if (substituteParameterMappings(S, *New, CSE)) + return std::nullopt; return New; } @@ -965,9 +1351,26 @@ static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P, return false; } -bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1, - NamedDecl *D2, ArrayRef<const Expr *> AC2, +bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, + MutableArrayRef<const Expr *> AC1, + NamedDecl *D2, + MutableArrayRef<const Expr *> AC2, bool &Result) { + if (const auto *FD1 = dyn_cast<FunctionDecl>(D1)) { + auto IsExpectedEntity = [](const FunctionDecl *FD) { + FunctionDecl::TemplatedKind Kind = FD->getTemplatedKind(); + return Kind == FunctionDecl::TK_NonTemplate || + Kind == FunctionDecl::TK_FunctionTemplate; + }; + const auto *FD2 = dyn_cast<FunctionDecl>(D2); + (void)IsExpectedEntity; + (void)FD1; + (void)FD2; + assert(IsExpectedEntity(FD1) && FD2 && IsExpectedEntity(FD2) && + "use non-instantiated function declaration for constraints partial " + "ordering"); + } + if (AC1.empty()) { Result = AC2.empty(); return false; @@ -985,6 +1388,21 @@ bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1, return false; } + unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true); + unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true); + + for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) { + if (Depth2 > Depth1) { + AC1[I] = AdjustConstraintDepth(*this, Depth2 - Depth1) + .TransformExpr(const_cast<Expr *>(AC1[I])) + .get(); + } else if (Depth1 > Depth2) { + AC2[I] = AdjustConstraintDepth(*this, Depth1 - Depth2) + .TransformExpr(const_cast<Expr *>(AC2[I])) + .get(); + } + } + if (subsumes(*this, D1, AC1, D2, AC2, Result, [this] (const AtomicConstraint &A, const AtomicConstraint &B) { return A.subsumes(Context, B); diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index a738befdd6ce..79c08adb8fab 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -339,7 +339,7 @@ static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E, // EvaluateBinaryTypeTrait(BTT_IsConvertible, ...) which is at the moment // a private function in SemaExprCXX.cpp - ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", None); + ExprResult AddressExpr = buildMemberCall(S, E, Loc, "address", std::nullopt); if (AddressExpr.isInvalid()) return nullptr; @@ -395,8 +395,8 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, return Result.get(); }; - CallExpr *AwaitReady = - cast_or_null<CallExpr>(BuildSubExpr(ACT::ACT_Ready, "await_ready", None)); + CallExpr *AwaitReady = cast_or_null<CallExpr>( + BuildSubExpr(ACT::ACT_Ready, "await_ready", std::nullopt)); if (!AwaitReady) return Calls; if (!AwaitReady->getType()->isDependentType()) { @@ -457,7 +457,7 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, VarDecl *CoroPromise, } } - BuildSubExpr(ACT::ACT_Resume, "await_resume", None); + BuildSubExpr(ACT::ACT_Resume, "await_resume", std::nullopt); // Make sure the awaiter object gets a chance to be cleaned up. S.Cleanup.setExprNeedsCleanups(true); @@ -705,8 +705,8 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc, SourceLocation Loc = Fn->getLocation(); // Build the initial suspend point auto buildSuspends = [&](StringRef Name) mutable -> StmtResult { - ExprResult Operand = - buildPromiseCall(*this, ScopeInfo->CoroutinePromise, Loc, Name, None); + ExprResult Operand = buildPromiseCall(*this, ScopeInfo->CoroutinePromise, + Loc, Name, std::nullopt); if (Operand.isInvalid()) return StmtError(); ExprResult Suspend = @@ -768,27 +768,34 @@ static bool isWithinCatchScope(Scope *S) { // function-body *outside of a handler* [...] A context within a function // where an await-expression can appear is called a suspension context of the // function." -static void checkSuspensionContext(Sema &S, SourceLocation Loc, +static bool checkSuspensionContext(Sema &S, SourceLocation Loc, StringRef Keyword) { // First emphasis of [expr.await]p2: must be a potentially evaluated context. // That is, 'co_await' and 'co_yield' cannot appear in subexpressions of // \c sizeof. - if (S.isUnevaluatedContext()) + if (S.isUnevaluatedContext()) { S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword; + return false; + } // Second emphasis of [expr.await]p2: must be outside of an exception handler. - if (isWithinCatchScope(S.getCurScope())) + if (isWithinCatchScope(S.getCurScope())) { S.Diag(Loc, diag::err_coroutine_within_handler) << Keyword; + return false; + } + + return true; } ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) { + if (!checkSuspensionContext(*this, Loc, "co_await")) + return ExprError(); + if (!ActOnCoroutineBodyStart(S, Loc, "co_await")) { CorrectDelayedTyposInExpr(E); return ExprError(); } - checkSuspensionContext(*this, Loc, "co_await"); - if (E->hasPlaceholderType()) { ExprResult R = CheckPlaceholderExpr(E); if (R.isInvalid()) return ExprError(); @@ -905,13 +912,14 @@ ExprResult Sema::BuildResolvedCoawaitExpr(SourceLocation Loc, Expr *Operand, } ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) { + if (!checkSuspensionContext(*this, Loc, "co_yield")) + return ExprError(); + if (!ActOnCoroutineBodyStart(S, Loc, "co_yield")) { CorrectDelayedTyposInExpr(E); return ExprError(); } - checkSuspensionContext(*this, Loc, "co_yield"); - // Build yield_value call. ExprResult Awaitable = buildPromiseCall( *this, getCurFunction()->CoroutinePromise, Loc, "yield_value", E); @@ -989,7 +997,7 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E, PC = buildPromiseCall(*this, Promise, Loc, "return_value", E); } else { E = MakeFullDiscardedValueExpr(E).get(); - PC = buildPromiseCall(*this, Promise, Loc, "return_void", None); + PC = buildPromiseCall(*this, Promise, Loc, "return_void", std::nullopt); } if (PC.isInvalid()) return StmtError(); @@ -1030,41 +1038,55 @@ static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) { return DR.get(); } -// Find an appropriate delete for the promise. -static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc, - QualType PromiseType) { - FunctionDecl *OperatorDelete = nullptr; +static TypeSourceInfo *getTypeSourceInfoForStdAlignValT(Sema &S, + SourceLocation Loc) { + EnumDecl *StdAlignValT = S.getStdAlignValT(); + QualType StdAlignValDecl = S.Context.getTypeDeclType(StdAlignValT); + return S.Context.getTrivialTypeSourceInfo(StdAlignValDecl); +} +// Find an appropriate delete for the promise. +static bool findDeleteForPromise(Sema &S, SourceLocation Loc, QualType PromiseType, + FunctionDecl *&OperatorDelete) { DeclarationName DeleteName = S.Context.DeclarationNames.getCXXOperatorName(OO_Delete); auto *PointeeRD = PromiseType->getAsCXXRecordDecl(); assert(PointeeRD && "PromiseType must be a CxxRecordDecl type"); + const bool Overaligned = S.getLangOpts().CoroAlignedAllocation; + // [dcl.fct.def.coroutine]p12 // The deallocation function's name is looked up by searching for it in the // scope of the promise type. If nothing is found, a search is performed in // the global scope. - if (S.FindDeallocationFunction(Loc, PointeeRD, DeleteName, OperatorDelete)) - return nullptr; + if (S.FindDeallocationFunction(Loc, PointeeRD, DeleteName, OperatorDelete, + /*Diagnose*/ true, /*WantSize*/ true, + /*WantAligned*/ Overaligned)) + return false; - // FIXME: We didn't implement following selection: // [dcl.fct.def.coroutine]p12 // If both a usual deallocation function with only a pointer parameter and a // usual deallocation function with both a pointer parameter and a size // parameter are found, then the selected deallocation function shall be the // one with two parameters. Otherwise, the selected deallocation function // shall be the function with one parameter. - if (!OperatorDelete) { // Look for a global declaration. - const bool CanProvideSize = S.isCompleteType(Loc, PromiseType); - const bool Overaligned = false; + // Coroutines can always provide their required size. + const bool CanProvideSize = true; + // Sema::FindUsualDeallocationFunction will try to find the one with two + // parameters first. It will return the deallocation function with one + // parameter if failed. OperatorDelete = S.FindUsualDeallocationFunction(Loc, CanProvideSize, Overaligned, DeleteName); + + if (!OperatorDelete) + return false; } + S.MarkFunctionReferenced(Loc, OperatorDelete); - return OperatorDelete; + return true; } @@ -1103,6 +1125,12 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { Diag(Fn->FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) << Fn->getFirstCoroutineStmtKeyword(); } + + // Coroutines will get splitted into pieces. The GNU address of label + // extension wouldn't be meaningful in coroutines. + for (AddrLabelExpr *ALE : Fn->AddrLabels) + Diag(ALE->getBeginLoc(), diag::err_coro_invalid_addr_of_label); + CoroutineStmtBuilder Builder(*this, *FD, *Fn, Body); if (Builder.isInvalid() || !Builder.buildStatements()) return FD->setInvalidDecl(); @@ -1319,12 +1347,9 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { // lvalue that denotes the parameter copy corresponding to p_i. FunctionDecl *OperatorNew = nullptr; - FunctionDecl *OperatorDelete = nullptr; - FunctionDecl *UnusedResult = nullptr; - bool PassAlignment = false; SmallVector<Expr *, 1> PlacementArgs; - bool PromiseContainsNew = [this, &PromiseType]() -> bool { + const bool PromiseContainsNew = [this, &PromiseType]() -> bool { DeclarationName NewName = S.getASTContext().DeclarationNames.getCXXOperatorName(OO_New); LookupResult R(S, NewName, Loc, Sema::LookupOrdinaryName); @@ -1335,19 +1360,29 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { return !R.empty() && !R.isAmbiguous(); }(); - auto LookupAllocationFunction = [&]() { + // Helper function to indicate whether the last lookup found the aligned + // allocation function. + bool PassAlignment = S.getLangOpts().CoroAlignedAllocation; + auto LookupAllocationFunction = [&](Sema::AllocationFunctionScope NewScope = + Sema::AFS_Both, + bool WithoutPlacementArgs = false, + bool ForceNonAligned = false) { // [dcl.fct.def.coroutine]p9 // The allocation function's name is looked up by searching for it in the // scope of the promise type. // - If any declarations are found, ... // - If no declarations are found in the scope of the promise type, a search // is performed in the global scope. - Sema::AllocationFunctionScope NewScope = - PromiseContainsNew ? Sema::AFS_Class : Sema::AFS_Global; - S.FindAllocationFunctions(Loc, SourceRange(), - NewScope, + if (NewScope == Sema::AFS_Both) + NewScope = PromiseContainsNew ? Sema::AFS_Class : Sema::AFS_Global; + + PassAlignment = !ForceNonAligned && S.getLangOpts().CoroAlignedAllocation; + FunctionDecl *UnusedResult = nullptr; + S.FindAllocationFunctions(Loc, SourceRange(), NewScope, /*DeleteScope*/ Sema::AFS_Both, PromiseType, - /*isArray*/ false, PassAlignment, PlacementArgs, + /*isArray*/ false, PassAlignment, + WithoutPlacementArgs ? MultiExprArg{} + : PlacementArgs, OperatorNew, UnusedResult, /*Diagnose*/ false); }; @@ -1359,15 +1394,58 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { LookupAllocationFunction(); - // [dcl.fct.def.coroutine]p9 - // If no viable function is found ([over.match.viable]), overload resolution - // is performed again on a function call created by passing just the amount of - // space required as an argument of type std::size_t. - if (!OperatorNew && !PlacementArgs.empty() && PromiseContainsNew) { - PlacementArgs.clear(); - LookupAllocationFunction(); + if (PromiseContainsNew && !PlacementArgs.empty()) { + // [dcl.fct.def.coroutine]p9 + // If no viable function is found ([over.match.viable]), overload + // resolution + // is performed again on a function call created by passing just the amount + // of space required as an argument of type std::size_t. + // + // Proposed Change of [dcl.fct.def.coroutine]p9 in P2014R0: + // Otherwise, overload resolution is performed again on a function call + // created + // by passing the amount of space requested as an argument of type + // std::size_t as the first argument, and the requested alignment as + // an argument of type std:align_val_t as the second argument. + if (!OperatorNew || + (S.getLangOpts().CoroAlignedAllocation && !PassAlignment)) + LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class, + /*WithoutPlacementArgs*/ true); } + // Proposed Change of [dcl.fct.def.coroutine]p12 in P2014R0: + // Otherwise, overload resolution is performed again on a function call + // created + // by passing the amount of space requested as an argument of type + // std::size_t as the first argument, and the lvalues p1 ... pn as the + // succeeding arguments. Otherwise, overload resolution is performed again + // on a function call created by passing just the amount of space required as + // an argument of type std::size_t. + // + // So within the proposed change in P2014RO, the priority order of aligned + // allocation functions wiht promise_type is: + // + // void* operator new( std::size_t, std::align_val_t, placement_args... ); + // void* operator new( std::size_t, std::align_val_t); + // void* operator new( std::size_t, placement_args... ); + // void* operator new( std::size_t); + + // Helper variable to emit warnings. + bool FoundNonAlignedInPromise = false; + if (PromiseContainsNew && S.getLangOpts().CoroAlignedAllocation) + if (!OperatorNew || !PassAlignment) { + FoundNonAlignedInPromise = OperatorNew; + + LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class, + /*WithoutPlacementArgs*/ false, + /*ForceNonAligned*/ true); + + if (!OperatorNew && !PlacementArgs.empty()) + LookupAllocationFunction(/*NewScope*/ Sema::AFS_Class, + /*WithoutPlacementArgs*/ true, + /*ForceNonAligned*/ true); + } + bool IsGlobalOverload = OperatorNew && !isa<CXXRecordDecl>(OperatorNew->getDeclContext()); // If we didn't find a class-local new declaration and non-throwing new @@ -1379,15 +1457,24 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { return false; PlacementArgs = {StdNoThrow}; OperatorNew = nullptr; - S.FindAllocationFunctions(Loc, SourceRange(), /*NewScope*/ Sema::AFS_Both, - /*DeleteScope*/ Sema::AFS_Both, PromiseType, - /*isArray*/ false, PassAlignment, PlacementArgs, - OperatorNew, UnusedResult); + LookupAllocationFunction(Sema::AFS_Global); + } + + // If we found a non-aligned allocation function in the promise_type, + // it indicates the user forgot to update the allocation function. Let's emit + // a warning here. + if (FoundNonAlignedInPromise) { + S.Diag(OperatorNew->getLocation(), + diag::warn_non_aligned_allocation_function) + << &FD; } if (!OperatorNew) { if (PromiseContainsNew) S.Diag(Loc, diag::err_coroutine_unusable_new) << PromiseType << &FD; + else if (RequiresNoThrowAlloc) + S.Diag(Loc, diag::err_coroutine_unfound_nothrow_new) + << &FD << S.getLangOpts().CoroAlignedAllocation; return false; } @@ -1404,7 +1491,8 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { } } - if ((OperatorDelete = findDeleteForPromise(S, Loc, PromiseType)) == nullptr) { + FunctionDecl *OperatorDelete = nullptr; + if (!findDeleteForPromise(S, Loc, PromiseType, OperatorDelete)) { // FIXME: We should add an error here. According to: // [dcl.fct.def.coroutine]p12 // If no usual deallocation function is found, the program is ill-formed. @@ -1417,15 +1505,34 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { Expr *FrameSize = S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_size, {}); - // Make new call. + Expr *FrameAlignment = nullptr; + + if (S.getLangOpts().CoroAlignedAllocation) { + FrameAlignment = + S.BuildBuiltinCallExpr(Loc, Builtin::BI__builtin_coro_align, {}); + + TypeSourceInfo *AlignValTy = getTypeSourceInfoForStdAlignValT(S, Loc); + if (!AlignValTy) + return false; + + FrameAlignment = S.BuildCXXNamedCast(Loc, tok::kw_static_cast, AlignValTy, + FrameAlignment, SourceRange(Loc, Loc), + SourceRange(Loc, Loc)) + .get(); + } + // Make new call. ExprResult NewRef = S.BuildDeclRefExpr(OperatorNew, OperatorNew->getType(), VK_LValue, Loc); if (NewRef.isInvalid()) return false; SmallVector<Expr *, 2> NewArgs(1, FrameSize); - llvm::append_range(NewArgs, PlacementArgs); + if (S.getLangOpts().CoroAlignedAllocation && PassAlignment) + NewArgs.push_back(FrameAlignment); + + if (OperatorNew->getNumParams() > NewArgs.size()) + llvm::append_range(NewArgs, PlacementArgs); ExprResult NewExpr = S.BuildCallExpr(S.getCurScope(), NewRef.get(), Loc, NewArgs, Loc); @@ -1454,9 +1561,29 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { // used, the size of the block is passed as the corresponding argument. const auto *OpDeleteType = OpDeleteQualType.getTypePtr()->castAs<FunctionProtoType>(); - if (OpDeleteType->getNumParams() > 1) + if (OpDeleteType->getNumParams() > DeleteArgs.size() && + S.getASTContext().hasSameType( + OpDeleteType->getParamType(DeleteArgs.size()), FrameSize->getType())) DeleteArgs.push_back(FrameSize); + // Proposed Change of [dcl.fct.def.coroutine]p12 in P2014R0: + // If deallocation function lookup finds a usual deallocation function with + // a pointer parameter, size parameter and alignment parameter then this + // will be the selected deallocation function, otherwise if lookup finds a + // usual deallocation function with both a pointer parameter and a size + // parameter, then this will be the selected deallocation function. + // Otherwise, if lookup finds a usual deallocation function with only a + // pointer parameter, then this will be the selected deallocation + // function. + // + // So we are not forced to pass alignment to the deallocation function. + if (S.getLangOpts().CoroAlignedAllocation && + OpDeleteType->getNumParams() > DeleteArgs.size() && + S.getASTContext().hasSameType( + OpDeleteType->getParamType(DeleteArgs.size()), + FrameAlignment->getType())) + DeleteArgs.push_back(FrameAlignment); + ExprResult DeleteExpr = S.BuildCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc); DeleteExpr = @@ -1549,8 +1676,8 @@ bool CoroutineStmtBuilder::makeOnException() { if (!S.getLangOpts().CXXExceptions) return true; - ExprResult UnhandledException = buildPromiseCall(S, Fn.CoroutinePromise, Loc, - "unhandled_exception", None); + ExprResult UnhandledException = buildPromiseCall( + S, Fn.CoroutinePromise, Loc, "unhandled_exception", std::nullopt); UnhandledException = S.ActOnFinishFullExpr(UnhandledException.get(), Loc, /*DiscardedValue*/ false); if (UnhandledException.isInvalid()) @@ -1573,8 +1700,8 @@ bool CoroutineStmtBuilder::makeReturnObject() { // [dcl.fct.def.coroutine]p7 // The expression promise.get_return_object() is used to initialize the // returned reference or prvalue result object of a call to a coroutine. - ExprResult ReturnObject = - buildPromiseCall(S, Fn.CoroutinePromise, Loc, "get_return_object", None); + ExprResult ReturnObject = buildPromiseCall(S, Fn.CoroutinePromise, Loc, + "get_return_object", std::nullopt); if (ReturnObject.isInvalid()) return false; @@ -1694,7 +1821,7 @@ bool Sema::buildCoroutineParameterMoves(SourceLocation Loc) { // [dcl.fct.def.coroutine]p13 // The initialization and destruction of each parameter copy occurs in the // context of the called coroutine. - auto D = buildVarDecl(*this, Loc, PD->getType(), PD->getIdentifier()); + auto *D = buildVarDecl(*this, Loc, PD->getType(), PD->getIdentifier()); AddInitializerToDecl(D, CExpr, /*DirectInit=*/true); // Convert decl to a statement. @@ -1724,7 +1851,8 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc, // discovered. // TODO: Become stricter when <experimental/coroutine> is removed. - auto const &TraitIdent = PP.getIdentifierTable().get("coroutine_traits"); + IdentifierInfo const &TraitIdent = + PP.getIdentifierTable().get("coroutine_traits"); NamespaceDecl *StdSpace = getStdNamespace(); LookupResult ResStd(*this, &TraitIdent, FuncLoc, LookupOrdinaryName); @@ -1742,7 +1870,7 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc, } // Prefer ::std to std::experimental. - auto &Result = InStd ? ResStd : ResExp; + LookupResult &Result = InStd ? ResStd : ResExp; CoroTraitsNamespaceCache = InStd ? StdSpace : ExpSpace; // coroutine_traits is required to be a class template. @@ -1759,7 +1887,7 @@ ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc, Diag(KwLoc, diag::warn_deprecated_coroutine_namespace) << "coroutine_traits"; ResExp.suppressDiagnostics(); - auto *Found = *ResExp.begin(); + NamedDecl *Found = *ResExp.begin(); Diag(Found->getLocation(), diag::note_entity_declared_at) << Found; if (InStd && diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 985005d0b79b..e2b921bfe78f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -27,6 +27,7 @@ #include "clang/AST/Randstruct.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/HLSLRuntime.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -49,6 +50,7 @@ #include <algorithm> #include <cstring> #include <functional> +#include <optional> #include <unordered_map> using namespace clang; @@ -145,7 +147,8 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { case tok::kw___ibm128: case tok::kw_wchar_t: case tok::kw_bool: - case tok::kw___underlying_type: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" case tok::kw___auto_type: return true; @@ -275,6 +278,45 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } +/// Build a ParsedType for a simple-type-specifier with a nested-name-specifier. +static ParsedType buildNamedType(Sema &S, const CXXScopeSpec *SS, QualType T, + SourceLocation NameLoc, + bool WantNontrivialTypeSourceInfo = true) { + switch (T->getTypeClass()) { + case Type::DeducedTemplateSpecialization: + case Type::Enum: + case Type::InjectedClassName: + case Type::Record: + case Type::Typedef: + case Type::UnresolvedUsing: + case Type::Using: + break; + // These can never be qualified so an ElaboratedType node + // would carry no additional meaning. + case Type::ObjCInterface: + case Type::ObjCTypeParam: + case Type::TemplateTypeParm: + return ParsedType::make(T); + default: + llvm_unreachable("Unexpected Type Class"); + } + + if (!SS || SS->isEmpty()) + return ParsedType::make( + S.Context.getElaboratedType(ETK_None, nullptr, T, nullptr)); + + QualType ElTy = S.getElaboratedType(ETK_None, *SS, T); + if (!WantNontrivialTypeSourceInfo) + return ParsedType::make(ElTy); + + TypeLocBuilder Builder; + Builder.pushTypeSpec(T).setNameLoc(NameLoc); + ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(ElTy); + ElabTL.setElaboratedKeywordLoc(SourceLocation()); + ElabTL.setQualifierLoc(SS->getWithLocInContext(S.Context)); + return S.CreateParsedType(ElTy, Builder.getTypeSourceInfo(S.Context, ElTy)); +} + /// If the identifier refers to a type name within this scope, /// return the declaration of that type. /// @@ -284,12 +326,12 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, /// opaque pointer (actually a QualType) corresponding to that /// type. Otherwise, returns NULL. ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, CXXScopeSpec *SS, - bool isClassName, bool HasTrailingDot, - ParsedType ObjectTypePtr, + Scope *S, CXXScopeSpec *SS, bool isClassName, + bool HasTrailingDot, ParsedType ObjectTypePtr, bool IsCtorOrDtorName, bool WantNontrivialTypeSourceInfo, bool IsClassTemplateDeductionContext, + ImplicitTypenameContext AllowImplicitTypename, IdentifierInfo **CorrectedII) { // FIXME: Consider allowing this outside C++1z mode as an extension. bool AllowDeducedTemplate = IsClassTemplateDeductionContext && @@ -316,17 +358,33 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, // // We therefore do not perform any name lookup if the result would // refer to a member of an unknown specialization. - if (!isClassName && !IsCtorOrDtorName) + // In C++2a, in several contexts a 'typename' is not required. Also + // allow this as an extension. + if (AllowImplicitTypename == ImplicitTypenameContext::No && + !isClassName && !IsCtorOrDtorName) return nullptr; + bool IsImplicitTypename = !isClassName && !IsCtorOrDtorName; + if (IsImplicitTypename) { + SourceLocation QualifiedLoc = SS->getRange().getBegin(); + if (getLangOpts().CPlusPlus20) + Diag(QualifiedLoc, diag::warn_cxx17_compat_implicit_typename); + else + Diag(QualifiedLoc, diag::ext_implicit_typename) + << SS->getScopeRep() << II.getName() + << FixItHint::CreateInsertion(QualifiedLoc, "typename "); + } // We know from the grammar that this name refers to a type, // so build a dependent node to describe the type. if (WantNontrivialTypeSourceInfo) - return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get(); + return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc, + (ImplicitTypenameContext)IsImplicitTypename) + .get(); NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context); - QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc, - II, NameLoc); + QualType T = + CheckTypenameType(IsImplicitTypename ? ETK_Typename : ETK_None, + SourceLocation(), QualifierLoc, II, NameLoc); return ParsedType::make(T); } @@ -417,7 +475,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, } } // If typo correction failed or was not performed, fall through - LLVM_FALLTHROUGH; + [[fallthrough]]; case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: Result.suppressDiagnostics(); @@ -500,8 +558,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, } else if (auto *UD = dyn_cast<UnresolvedUsingIfExistsDecl>(IIDecl)) { (void)DiagnoseUseOfDecl(UD, NameLoc); // Recover with 'int' - T = Context.IntTy; - FoundUsingShadow = nullptr; + return ParsedType::make(Context.IntTy); } else if (AllowDeducedTemplate) { if (auto *TD = getAsTypeTemplateDecl(IIDecl)) { assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD); @@ -523,27 +580,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, if (FoundUsingShadow) T = Context.getUsingType(FoundUsingShadow, T); - // NOTE: avoid constructing an ElaboratedType(Loc) if this is a - // constructor or destructor name (in such a case, the scope specifier - // will be attached to the enclosing Expr or Decl node). - if (SS && SS->isNotEmpty() && !IsCtorOrDtorName && - !isa<ObjCInterfaceDecl, UnresolvedUsingIfExistsDecl>(IIDecl)) { - if (WantNontrivialTypeSourceInfo) { - // Construct a type with type-source information. - TypeLocBuilder Builder; - Builder.pushTypeSpec(T).setNameLoc(NameLoc); - - T = getElaboratedType(ETK_None, *SS, T); - ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T); - ElabTL.setElaboratedKeywordLoc(SourceLocation()); - ElabTL.setQualifierLoc(SS->getWithLocInContext(Context)); - return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); - } else { - T = getElaboratedType(ETK_None, *SS, T); - } - } - - return ParsedType::make(T); + return buildNamedType(*this, SS, T, NameLoc, WantNontrivialTypeSourceInfo); } // Builds a fake NNS for the given decl context. @@ -1147,17 +1184,7 @@ Corrected: QualType T = Context.getTypeDeclType(Type); if (const auto *USD = dyn_cast<UsingShadowDecl>(Found)) T = Context.getUsingType(USD, T); - - if (SS.isEmpty()) // No elaborated type, trivial location info - return ParsedType::make(T); - - TypeLocBuilder Builder; - Builder.pushTypeSpec(T).setNameLoc(NameLoc); - T = getElaboratedType(ETK_None, SS, T); - ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T); - ElabTL.setElaboratedKeywordLoc(SourceLocation()); - ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); - return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); + return buildNamedType(*this, &SS, T, NameLoc); }; NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl(); @@ -1221,7 +1248,8 @@ Corrected: // member accesses, as we need to defer certain access checks until we know // the context. bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); - if (Result.isSingleResult() && !ADL && !FirstDecl->isCXXClassMember()) + if (Result.isSingleResult() && !ADL && + (!FirstDecl->isCXXClassMember() || isa<EnumConstantDecl>(FirstDecl))) return NameClassification::NonType(Result.getRepresentativeDecl()); // Otherwise, this is an overload set that we will need to resolve later. @@ -1266,7 +1294,7 @@ ExprResult Sema::ActOnNameClassifiedAsNonType(Scope *S, const CXXScopeSpec &SS, Result.resolveKind(); bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); - return BuildDeclarationNameExpr(SS, Result, ADL); + return BuildDeclarationNameExpr(SS, Result, ADL, /*AcceptInvalidDecl=*/true); } ExprResult Sema::ActOnNameClassifiedAsOverloadSet(Scope *S, Expr *E) { @@ -1635,9 +1663,11 @@ bool Sema::CheckRedeclarationModuleOwnership(NamedDecl *New, NamedDecl *Old) { // Partitions are part of the module, but a partition could import another // module, so verify that the PMIs agree. - if (NewM && OldM && (NewM->isModulePartition() || OldM->isModulePartition())) - return NewM->getPrimaryModuleInterfaceName() == - OldM->getPrimaryModuleInterfaceName(); + if (NewM && OldM && + (NewM->isModulePartition() || OldM->isModulePartition()) && + NewM->getPrimaryModuleInterfaceName() == + OldM->getPrimaryModuleInterfaceName()) + return false; bool NewIsModuleInterface = NewM && NewM->isModulePurview(); bool OldIsModuleInterface = OldM && OldM->isModulePurview(); @@ -1711,6 +1741,80 @@ bool Sema::CheckRedeclarationInModule(NamedDecl *New, NamedDecl *Old) { return false; } +// Check the redefinition in C++20 Modules. +// +// [basic.def.odr]p14: +// For any definable item D with definitions in multiple translation units, +// - if D is a non-inline non-templated function or variable, or +// - if the definitions in different translation units do not satisfy the +// following requirements, +// the program is ill-formed; a diagnostic is required only if the definable +// item is attached to a named module and a prior definition is reachable at +// the point where a later definition occurs. +// - Each such definition shall not be attached to a named module +// ([module.unit]). +// - Each such definition shall consist of the same sequence of tokens, ... +// ... +// +// Return true if the redefinition is not allowed. Return false otherwise. +bool Sema::IsRedefinitionInModule(const NamedDecl *New, + const NamedDecl *Old) const { + assert(getASTContext().isSameEntity(New, Old) && + "New and Old are not the same definition, we should diagnostic it " + "immediately instead of checking it."); + assert(const_cast<Sema *>(this)->isReachable(New) && + const_cast<Sema *>(this)->isReachable(Old) && + "We shouldn't see unreachable definitions here."); + + Module *NewM = New->getOwningModule(); + Module *OldM = Old->getOwningModule(); + + // We only checks for named modules here. The header like modules is skipped. + // FIXME: This is not right if we import the header like modules in the module + // purview. + // + // For example, assuming "header.h" provides definition for `D`. + // ```C++ + // //--- M.cppm + // export module M; + // import "header.h"; // or #include "header.h" but import it by clang modules + // actually. + // + // //--- Use.cpp + // import M; + // import "header.h"; // or uses clang modules. + // ``` + // + // In this case, `D` has multiple definitions in multiple TU (M.cppm and + // Use.cpp) and `D` is attached to a named module `M`. The compiler should + // reject it. But the current implementation couldn't detect the case since we + // don't record the information about the importee modules. + // + // But this might not be painful in practice. Since the design of C++20 Named + // Modules suggests us to use headers in global module fragment instead of + // module purview. + if (NewM && NewM->isHeaderLikeModule()) + NewM = nullptr; + if (OldM && OldM->isHeaderLikeModule()) + OldM = nullptr; + + if (!NewM && !OldM) + return true; + + // [basic.def.odr]p14.3 + // Each such definition shall not be attached to a named module + // ([module.unit]). + if ((NewM && NewM->isModulePurview()) || (OldM && OldM->isModulePurview())) + return true; + + // Then New and Old lives in the same TU if their share one same module unit. + if (NewM) + NewM = NewM->getTopLevelModule(); + if (OldM) + OldM = OldM->getTopLevelModule(); + return OldM == NewM; +} + static bool isUsingDecl(NamedDecl *D) { return isa<UsingShadowDecl>(D) || isa<UnresolvedUsingTypenameDecl>(D) || @@ -1773,7 +1877,7 @@ bool Sema::mightHaveNonExternalLinkage(const DeclaratorDecl *D) { // FIXME: This needs to be refactored; some other isInMainFile users want // these semantics. static bool isMainFileLoc(const Sema &S, SourceLocation Loc) { - if (S.TUKind != TU_Complete) + if (S.TUKind != TU_Complete || S.getLangOpts().IsHeaderFile) return false; return S.SourceMgr.isInMainFile(Loc); } @@ -1990,20 +2094,31 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx, } void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) { + DiagnoseUnusedNestedTypedefs( + D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); }); +} + +void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D, + DiagReceiverTy DiagReceiver) { if (D->getTypeForDecl()->isDependentType()) return; for (auto *TmpD : D->decls()) { if (const auto *T = dyn_cast<TypedefNameDecl>(TmpD)) - DiagnoseUnusedDecl(T); + DiagnoseUnusedDecl(T, DiagReceiver); else if(const auto *R = dyn_cast<RecordDecl>(TmpD)) - DiagnoseUnusedNestedTypedefs(R); + DiagnoseUnusedNestedTypedefs(R, DiagReceiver); } } +void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { + DiagnoseUnusedDecl( + D, [this](SourceLocation Loc, PartialDiagnostic PD) { Diag(Loc, PD); }); +} + /// DiagnoseUnusedDecl - Emit warnings about declarations that are not used /// unless they are marked attr(unused). -void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { +void Sema::DiagnoseUnusedDecl(const NamedDecl *D, DiagReceiverTy DiagReceiver) { if (!ShouldDiagnoseUnusedDecl(D)) return; @@ -2025,10 +2140,11 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { else DiagID = diag::warn_unused_variable; - Diag(D->getLocation(), DiagID) << D << Hint; + DiagReceiver(D->getLocation(), PDiag(DiagID) << D << Hint); } -void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) { +void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD, + DiagReceiverTy DiagReceiver) { // If it's not referenced, it can't be set. If it has the Cleanup attribute, // it's not really unused. if (!VD->isReferenced() || !VD->getDeclName() || VD->hasAttr<UnusedAttr>() || @@ -2074,10 +2190,11 @@ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) { return; unsigned DiagID = isa<ParmVarDecl>(VD) ? diag::warn_unused_but_set_parameter : diag::warn_unused_but_set_variable; - Diag(VD->getLocation(), DiagID) << VD; + DiagReceiver(VD->getLocation(), PDiag(DiagID) << VD); } -static void CheckPoppedLabel(LabelDecl *L, Sema &S) { +static void CheckPoppedLabel(LabelDecl *L, Sema &S, + Sema::DiagReceiverTy DiagReceiver) { // Verify that we have no forward references left. If so, there was a goto // or address of a label taken, but no definition of it. Label fwd // definitions are indicated with a null substmt which is also not a resolved @@ -2088,7 +2205,8 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S) { else Diagnose = L->getStmt() == nullptr; if (Diagnose) - S.Diag(L->getLocation(), diag::err_undeclared_label_use) << L; + DiagReceiver(L->getLocation(), S.PDiag(diag::err_undeclared_label_use) + << L); } void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { @@ -2098,6 +2216,24 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && "Scope shouldn't contain decls!"); + /// We visit the decls in non-deterministic order, but we want diagnostics + /// emitted in deterministic order. Collect any diagnostic that may be emitted + /// and sort the diagnostics before emitting them, after we visited all decls. + struct LocAndDiag { + SourceLocation Loc; + std::optional<SourceLocation> PreviousDeclLoc; + PartialDiagnostic PD; + }; + SmallVector<LocAndDiag, 16> DeclDiags; + auto addDiag = [&DeclDiags](SourceLocation Loc, PartialDiagnostic PD) { + DeclDiags.push_back(LocAndDiag{Loc, std::nullopt, std::move(PD)}); + }; + auto addDiagWithPrev = [&DeclDiags](SourceLocation Loc, + SourceLocation PreviousDeclLoc, + PartialDiagnostic PD) { + DeclDiags.push_back(LocAndDiag{Loc, PreviousDeclLoc, std::move(PD)}); + }; + for (auto *TmpD : S->decls()) { assert(TmpD && "This decl didn't get pushed??"); @@ -2106,11 +2242,11 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { // Diagnose unused variables in this scope. if (!S->hasUnrecoverableErrorOccurred()) { - DiagnoseUnusedDecl(D); + DiagnoseUnusedDecl(D, addDiag); if (const auto *RD = dyn_cast<RecordDecl>(D)) - DiagnoseUnusedNestedTypedefs(RD); + DiagnoseUnusedNestedTypedefs(RD, addDiag); if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - DiagnoseUnusedButSetDecl(VD); + DiagnoseUnusedButSetDecl(VD, addDiag); RefsMinusAssignments.erase(VD); } } @@ -2119,7 +2255,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { // If this was a forward reference to a label, verify it was defined. if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) - CheckPoppedLabel(LD, *this); + CheckPoppedLabel(LD, *this, addDiag); // Remove this name from our lexical scope, and warn on it if we haven't // already. @@ -2127,13 +2263,27 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { auto ShadowI = ShadowingDecls.find(D); if (ShadowI != ShadowingDecls.end()) { if (const auto *FD = dyn_cast<FieldDecl>(ShadowI->second)) { - Diag(D->getLocation(), diag::warn_ctor_parm_shadows_field) - << D << FD << FD->getParent(); - Diag(FD->getLocation(), diag::note_previous_declaration); + addDiagWithPrev(D->getLocation(), FD->getLocation(), + PDiag(diag::warn_ctor_parm_shadows_field) + << D << FD << FD->getParent()); } ShadowingDecls.erase(ShadowI); } } + + llvm::sort(DeclDiags, + [](const LocAndDiag &LHS, const LocAndDiag &RHS) -> bool { + // The particular order for diagnostics is not important, as long + // as the order is deterministic. Using the raw location is going + // to generally be in source order unless there are macro + // expansions involved. + return LHS.Loc.getRawEncoding() < RHS.Loc.getRawEncoding(); + }); + for (const LocAndDiag &D : DeclDiags) { + Diag(D.Loc, D.PD); + if (D.PreviousDeclLoc) + Diag(*D.PreviousDeclLoc, diag::note_previous_declaration); + } } /// Look for an Objective-C class in the translation unit. @@ -2949,7 +3099,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { continue; } else if (isa<OMPDeclareVariantAttr>(NewAttribute)) { // We allow to add OMP[Begin]DeclareVariantAttr to be added to - // declarations after defintions. + // declarations after definitions. ++I; continue; } @@ -3249,8 +3399,8 @@ static bool EquivalentArrayTypes(QualType Old, QualType New, static void mergeParamDeclTypes(ParmVarDecl *NewParam, const ParmVarDecl *OldParam, Sema &S) { - if (auto Oldnullability = OldParam->getType()->getNullability(S.Context)) { - if (auto Newnullability = NewParam->getType()->getNullability(S.Context)) { + if (auto Oldnullability = OldParam->getType()->getNullability()) { + if (auto Newnullability = NewParam->getType()->getNullability()) { if (*Oldnullability != *Newnullability) { S.Diag(NewParam->getLocation(), diag::warn_mismatched_nullability_attr) << DiagNullabilityKind( @@ -3960,7 +4110,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, // default argument promotion rules were already checked by // ASTContext::typesAreCompatible(). if (Old->hasPrototype() && !New->hasWrittenPrototype() && NewDeclIsDefn && - Old->getNumParams() != New->getNumParams()) { + Old->getNumParams() != New->getNumParams() && !Old->isImplicit()) { if (Old->hasInheritedPrototype()) Old = Old->getCanonicalDecl(); Diag(New->getLocation(), diag::err_conflicting_types) << New; @@ -4026,10 +4176,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, // The old declaration provided a function prototype, but the // new declaration does not. Merge in the prototype. assert(!OldProto->hasExceptionSpec() && "Exception spec in C"); - SmallVector<QualType, 16> ParamTypes(OldProto->param_types()); - NewQType = - Context.getFunctionType(NewFuncType->getReturnType(), ParamTypes, - OldProto->getExtProtoInfo()); + NewQType = Context.getFunctionType(NewFuncType->getReturnType(), + OldProto->getParamTypes(), + OldProto->getExtProtoInfo()); New->setType(NewQType); New->setHasInheritedPrototype(); @@ -4657,6 +4806,7 @@ bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) { if (!hasVisibleDefinition(Old) && (New->getFormalLinkage() == InternalLinkage || New->isInline() || + isa<VarTemplateSpecializationDecl>(New) || New->getDescribedVarTemplate() || New->getNumTemplateParameterLists() || New->getDeclContext()->isDependentContext())) { @@ -5840,7 +5990,9 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, switch (DS.getTypeSpecType()) { case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: - case DeclSpec::TST_underlyingType: + case DeclSpec::TST_typeof_unqualType: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait: +#include "clang/Basic/TransformTypeTraits.def" case DeclSpec::TST_atomic: { // Grab the type from the parser. TypeSourceInfo *TSI = nullptr; @@ -5864,6 +6016,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, } case DeclSpec::TST_decltype: + case DeclSpec::TST_typeof_unqualExpr: case DeclSpec::TST_typeofExpr: { Expr *E = DS.getRepAsExpr(); ExprResult Result = S.RebuildExprInCurrentInstantiation(E); @@ -6502,8 +6655,8 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) << 1 << static_cast<int>(D.getDeclSpec().getConstexprSpecifier()); - if (D.getName().Kind != UnqualifiedIdKind::IK_Identifier) { - if (D.getName().Kind == UnqualifiedIdKind::IK_DeductionGuideName) + if (D.getName().getKind() != UnqualifiedIdKind::IK_Identifier) { + if (D.getName().getKind() == UnqualifiedIdKind::IK_DeductionGuideName) Diag(D.getName().StartLocation, diag::err_deduction_guide_invalid_specifier) << "typedef"; @@ -6939,13 +7092,24 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, (!IsInline || (IsMicrosoftABI && IsTemplate)) && !IsStaticDataMember && !NewDecl->isLocalExternDecl() && !IsQualifiedFriend) { if (IsMicrosoftABI && IsDefinition) { - S.Diag(NewDecl->getLocation(), - diag::warn_redeclaration_without_import_attribute) - << NewDecl; - S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); - NewDecl->dropAttr<DLLImportAttr>(); - NewDecl->addAttr( - DLLExportAttr::CreateImplicit(S.Context, NewImportAttr->getRange())); + if (IsSpecialization) { + S.Diag( + NewDecl->getLocation(), + diag::err_attribute_dllimport_function_specialization_definition); + S.Diag(OldImportAttr->getLocation(), diag::note_attribute); + NewDecl->dropAttr<DLLImportAttr>(); + } else { + S.Diag(NewDecl->getLocation(), + diag::warn_redeclaration_without_import_attribute) + << NewDecl; + S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); + NewDecl->dropAttr<DLLImportAttr>(); + NewDecl->addAttr(DLLExportAttr::CreateImplicit( + S.Context, NewImportAttr->getRange())); + } + } else if (IsMicrosoftABI && IsSpecialization) { + assert(!IsDefinition); + // MSVC allows this. Keep the inherited attribute. } else { S.Diag(NewDecl->getLocation(), diag::warn_redeclaration_without_attribute_prev_attribute_ignored) @@ -7039,6 +7203,9 @@ static bool shouldConsiderLinkage(const VarDecl *VD) { return true; if (DC->isRecord()) return false; + if (DC->getDeclKind() == Decl::HLSLBuffer) + return false; + if (isa<RequiresExprBodyDecl>(DC)) return false; llvm_unreachable("Unexpected context"); @@ -7212,6 +7379,36 @@ static void copyAttrFromTypedefToDecl(Sema &S, Decl *D, const TypedefType *TT) { } } +// This function emits warning and a corresponding note based on the +// ReadOnlyPlacementAttr attribute. The warning checks that all global variable +// declarations of an annotated type must be const qualified. +void emitReadOnlyPlacementAttrWarning(Sema &S, const VarDecl *VD) { + QualType VarType = VD->getType().getCanonicalType(); + + // Ignore local declarations (for now) and those with const qualification. + // TODO: Local variables should not be allowed if their type declaration has + // ReadOnlyPlacementAttr attribute. To be handled in follow-up patch. + if (!VD || VD->hasLocalStorage() || VD->getType().isConstQualified()) + return; + + if (VarType->isArrayType()) { + // Retrieve element type for array declarations. + VarType = S.getASTContext().getBaseElementType(VarType); + } + + const RecordDecl *RD = VarType->getAsRecordDecl(); + + // Check if the record declaration is present and if it has any attributes. + if (RD == nullptr) + return; + + if (const auto *ConstDecl = RD->getAttr<ReadOnlyPlacementAttr>()) { + S.Diag(VD->getLocation(), diag::warn_var_decl_not_read_only) << RD; + S.Diag(ConstDecl->getLocation(), diag::note_enforce_read_only_placement); + return; + } +} + NamedDecl *Sema::ActOnVariableDeclarator( Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, @@ -7555,7 +7752,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_wrong_decl_kind) << static_cast<int>(D.getDeclSpec().getConstexprSpecifier()); - LLVM_FALLTHROUGH; + [[fallthrough]]; case ConstexprSpecKind::Constexpr: NewVD->setConstexpr(true); @@ -7876,6 +8073,8 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (IsMemberSpecialization && !NewVD->isInvalidDecl()) CompleteMemberSpecialization(NewVD, Previous); + emitReadOnlyPlacementAttrWarning(*this, NewVD); + return NewVD; } @@ -8003,7 +8202,7 @@ void Sema::CheckShadow(NamedDecl *D, NamedDecl *ShadowedDecl, if (shadowedVar->isExternC()) { // For shadowing external vars, make sure that we point to the global // declaration, not a locally scoped extern declaration. - for (auto I : shadowedVar->redecls()) + for (auto *I : shadowedVar->redecls()) if (I->isFileVarDecl()) { ShadowedDecl = I; break; @@ -8492,6 +8691,19 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { NewVD->setInvalidDecl(); return; } + + // Check that SVE types are only used in functions with SVE available. + if (T->isSVESizelessBuiltinType() && CurContext->isFunctionOrMethod()) { + const FunctionDecl *FD = cast<FunctionDecl>(CurContext); + llvm::StringMap<bool> CallerFeatureMap; + Context.getFunctionFeatureMap(CallerFeatureMap, FD); + if (!Builtin::evaluateRequiredTargetFeatures( + "sve", CallerFeatureMap)) { + Diag(NewVD->getLocation(), diag::err_sve_vector_in_non_sve_target) << T; + NewVD->setInvalidDecl(); + return; + } + } } /// Perform semantic checking on a newly-created variable @@ -9069,10 +9281,23 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { // reference if an implementation supports them in kernel parameters. if (S.getLangOpts().OpenCLCPlusPlus && !S.getOpenCLOptions().isAvailableOption( - "__cl_clang_non_portable_kernel_param_types", S.getLangOpts()) && - !PointeeType->isAtomicType() && !PointeeType->isVoidType() && - !PointeeType->isStandardLayoutType()) + "__cl_clang_non_portable_kernel_param_types", S.getLangOpts())) { + auto CXXRec = PointeeType.getCanonicalType()->getAsCXXRecordDecl(); + bool IsStandardLayoutType = true; + if (CXXRec) { + // If template type is not ODR-used its definition is only available + // in the template definition not its instantiation. + // FIXME: This logic doesn't work for types that depend on template + // parameter (PR58590). + if (!CXXRec->hasDefinition()) + CXXRec = CXXRec->getTemplateInstantiationPattern(); + if (!CXXRec || !CXXRec->hasDefinition() || !CXXRec->isStandardLayout()) + IsStandardLayoutType = false; + } + if (!PointeeType->isAtomicType() && !PointeeType->isVoidType() && + !IsStandardLayoutType) return InvalidKernelParam; + } return PtrKernelParam; } @@ -9419,7 +9644,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules || !NewFD->getOwningModule() || NewFD->getOwningModule()->isGlobalModule() || - NewFD->getOwningModule()->isModuleMapModule(); + NewFD->getOwningModule()->isHeaderLikeModule(); bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier(); @@ -9755,6 +9980,19 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setType(Context.getFunctionType( FPT->getReturnType(), FPT->getParamTypes(), FPT->getExtProtoInfo().withExceptionSpec(EST_BasicNoexcept))); + + // C++20 [dcl.inline]/7 + // If an inline function or variable that is attached to a named module + // is declared in a definition domain, it shall be defined in that + // domain. + // So, if the current declaration does not have a definition, we must + // check at the end of the TU (or when the PMF starts) to see that we + // have a definition at that point. + if (isInline && !D.isFunctionDefinition() && getLangOpts().CPlusPlus20 && + NewFD->hasOwningModule() && + NewFD->getOwningModule()->isModulePurview()) { + PendingInlineFuncDecls.insert(NewFD); + } } // Filter out previous declarations that don't match the scope. @@ -9900,6 +10138,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->dropAttr<SectionAttr>(); } + // Apply an implicit StrictGuardStackCheckAttr if #pragma strict_gs_check is + // active. + if (StrictGuardStackCheckStack.CurrentValue && D.isFunctionDefinition() && + !NewFD->hasAttr<StrictGuardStackCheckAttr>()) + NewFD->addAttr(StrictGuardStackCheckAttr::CreateImplicit( + Context, PragmaClangTextSection.PragmaLocation, + AttributeCommonInfo::AS_Pragma)); + // Apply an implicit CodeSegAttr from class declspec or // apply an implicit SectionAttr from #pragma code_seg if active. if (!NewFD->hasAttr<CodeSegAttr>()) { @@ -9911,14 +10157,49 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Handle attributes. ProcessDeclAttributes(S, NewFD, D); + const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>(); + if (NewTVA && !NewTVA->isDefaultVersion() && + !Context.getTargetInfo().hasFeature("fmv")) { + // Don't add to scope fmv functions declarations if fmv disabled + AddToScope = false; + return NewFD; + } if (getLangOpts().OpenCL) { // OpenCL v1.1 s6.5: Using an address space qualifier in a function return // type declaration will generate a compilation error. LangAS AddressSpace = NewFD->getReturnType().getAddressSpace(); if (AddressSpace != LangAS::Default) { - Diag(NewFD->getLocation(), - diag::err_opencl_return_value_with_address_space); + Diag(NewFD->getLocation(), diag::err_return_value_with_address_space); + NewFD->setInvalidDecl(); + } + } + + if (getLangOpts().HLSL) { + auto &TargetInfo = getASTContext().getTargetInfo(); + // Skip operator overload which not identifier. + // Also make sure NewFD is in translation-unit scope. + if (!NewFD->isInvalidDecl() && Name.isIdentifier() && + NewFD->getName() == TargetInfo.getTargetOpts().HLSLEntry && + S->getDepth() == 0) { + CheckHLSLEntryPoint(NewFD); + if (!NewFD->isInvalidDecl()) { + auto Env = TargetInfo.getTriple().getEnvironment(); + AttributeCommonInfo AL(NewFD->getBeginLoc()); + HLSLShaderAttr::ShaderType ShaderType = + static_cast<HLSLShaderAttr::ShaderType>( + hlsl::getStageFromEnvironment(Env)); + // To share code with HLSLShaderAttr, add HLSLShaderAttr to entry + // function. + if (HLSLShaderAttr *Attr = mergeHLSLShaderAttr(NewFD, AL, ShaderType)) + NewFD->addAttr(Attr); + } + } + // HLSL does not support specifying an address space on a function return + // type. + LangAS AddressSpace = NewFD->getReturnType().getAddressSpace(); + if (AddressSpace != LangAS::Default) { + Diag(NewFD->getLocation(), diag::err_return_value_with_address_space); NewFD->setInvalidDecl(); } } @@ -10091,7 +10372,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.setRedeclaration(true); } - assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || + assert((NewFD->isInvalidDecl() || NewFD->isMultiVersion() || + !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); @@ -10253,16 +10535,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype) << NewFD; - - // Turn this into a variadic function with no parameters. - const auto *FT = NewFD->getType()->castAs<FunctionType>(); - FunctionProtoType::ExtProtoInfo EPI( - Context.getDefaultCallingConvention(true, false)); - EPI.Variadic = true; - EPI.ExtInfo = FT->getExtInfo(); - - QualType R = Context.getFunctionType(FT->getReturnType(), None, EPI); - NewFD->setType(R); + NewFD->dropAttr<OverloadableAttr>(); } // If there's a #pragma GCC visibility in scope, and this isn't a class @@ -10344,7 +10617,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } llvm::SmallPtrSet<const Type *, 16> ValidTypes; - for (auto Param : NewFD->parameters()) + for (auto *Param : NewFD->parameters()) checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes); if (getLangOpts().OpenCLCPlusPlus) { @@ -10360,6 +10633,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } if (getLangOpts().CPlusPlus) { + // Precalculate whether this is a friend function template with a constraint + // that depends on an enclosing template, per [temp.friend]p9. + if (isFriend && FunctionTemplate && + FriendConstraintsDependOnEnclosingTemplate(NewFD)) + NewFD->setFriendConstraintRefersToEnclosingTemplate(true); + if (FunctionTemplate) { if (NewFD->isInvalidDecl()) FunctionTemplate->setInvalidDecl(); @@ -10482,7 +10761,7 @@ static Attr *getImplicitCodeSegAttrFromClass(Sema &S, const FunctionDecl *FD) { /// (from the current #pragma code-seg value). /// /// \param FD Function being declared. -/// \param IsDefinition Whether it is a definition or just a declarartion. +/// \param IsDefinition Whether it is a definition or just a declaration. /// \returns A CodeSegAttr or SectionAttr to apply to the function or /// nullptr if no attribute should be added. Attr *Sema::getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, @@ -10566,37 +10845,53 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) { PrevVD->getType()); } -/// Check the target attribute of the function for MultiVersion -/// validity. +/// Check the target or target_version attribute of the function for +/// MultiVersion validity. /// /// Returns true if there was an error, false otherwise. static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) { const auto *TA = FD->getAttr<TargetAttr>(); - assert(TA && "MultiVersion Candidate requires a target attribute"); - ParsedTargetAttr ParseInfo = TA->parse(); + const auto *TVA = FD->getAttr<TargetVersionAttr>(); + assert( + (TA || TVA) && + "MultiVersion candidate requires a target or target_version attribute"); const TargetInfo &TargetInfo = S.Context.getTargetInfo(); enum ErrType { Feature = 0, Architecture = 1 }; - if (!ParseInfo.Architecture.empty() && - !TargetInfo.validateCpuIs(ParseInfo.Architecture)) { - S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) - << Architecture << ParseInfo.Architecture; - return true; - } - - for (const auto &Feat : ParseInfo.Features) { - auto BareFeat = StringRef{Feat}.substr(1); - if (Feat[0] == '-') { + if (TA) { + ParsedTargetAttr ParseInfo = + S.getASTContext().getTargetInfo().parseTargetAttr(TA->getFeaturesStr()); + if (!ParseInfo.CPU.empty() && !TargetInfo.validateCpuIs(ParseInfo.CPU)) { S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) - << Feature << ("no-" + BareFeat).str(); + << Architecture << ParseInfo.CPU; return true; } + for (const auto &Feat : ParseInfo.Features) { + auto BareFeat = StringRef{Feat}.substr(1); + if (Feat[0] == '-') { + S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) + << Feature << ("no-" + BareFeat).str(); + return true; + } - if (!TargetInfo.validateCpuSupports(BareFeat) || - !TargetInfo.isValidFeatureName(BareFeat)) { - S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) - << Feature << BareFeat; - return true; + if (!TargetInfo.validateCpuSupports(BareFeat) || + !TargetInfo.isValidFeatureName(BareFeat)) { + S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) + << Feature << BareFeat; + return true; + } + } + } + + if (TVA) { + llvm::SmallVector<StringRef, 8> Feats; + TVA->getFeatures(Feats); + for (const auto &Feat : Feats) { + if (!TargetInfo.validateCpuSupports(Feat)) { + S.Diag(FD->getLocation(), diag::err_bad_multiversion_option) + << Feature << Feat; + return true; + } } } return false; @@ -10643,6 +10938,10 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S, if (MVKind != MultiVersionKind::Target) return Diagnose(S, A); break; + case attr::TargetVersion: + if (MVKind != MultiVersionKind::TargetVersion) + return Diagnose(S, A); + break; case attr::TargetClones: if (MVKind != MultiVersionKind::TargetClones) return Diagnose(S, A); @@ -10815,18 +11114,18 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, /// This sets NewFD->isInvalidDecl() to true if there was an error. /// /// Returns true if there was an error, false otherwise. -static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD, - MultiVersionKind MVKind, - const TargetAttr *TA) { +static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) { + MultiVersionKind MVKind = FD->getMultiVersionKind(); assert(MVKind != MultiVersionKind::None && "Function lacks multiversion attribute"); - - // Target only causes MV if it is default, otherwise this is a normal - // function. - if (MVKind == MultiVersionKind::Target && !TA->isDefaultVersion()) + const auto *TA = FD->getAttr<TargetAttr>(); + const auto *TVA = FD->getAttr<TargetVersionAttr>(); + // Target and target_version only causes MV if it is default, otherwise this + // is a normal function. + if ((TA && !TA->isDefaultVersion()) || (TVA && !TVA->isDefaultVersion())) return false; - if (MVKind == MultiVersionKind::Target && CheckMultiVersionValue(S, FD)) { + if ((TA || TVA) && CheckMultiVersionValue(S, FD)) { FD->setInvalidDecl(); return true; } @@ -10849,23 +11148,27 @@ static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) { return false; } -static bool CheckTargetCausesMultiVersioning( - Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, const TargetAttr *NewTA, - bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) { +static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, + FunctionDecl *NewFD, + bool &Redeclaration, + NamedDecl *&OldDecl, + LookupResult &Previous) { + const auto *NewTA = NewFD->getAttr<TargetAttr>(); + const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>(); const auto *OldTA = OldFD->getAttr<TargetAttr>(); - ParsedTargetAttr NewParsed = NewTA->parse(); - // Sort order doesn't matter, it just needs to be consistent. - llvm::sort(NewParsed.Features); - + const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>(); // If the old decl is NOT MultiVersioned yet, and we don't cause that // to change, this is a simple redeclaration. - if (!NewTA->isDefaultVersion() && - (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) + if ((NewTA && !NewTA->isDefaultVersion() && + (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr())) || + (NewTVA && !NewTVA->isDefaultVersion() && + (!OldTVA || OldTVA->getName() == NewTVA->getName()))) return false; // Otherwise, this decl causes MultiVersioning. if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true, - MultiVersionKind::Target)) { + NewTVA ? MultiVersionKind::TargetVersion + : MultiVersionKind::Target)) { NewFD->setInvalidDecl(); return true; } @@ -10876,7 +11179,9 @@ static bool CheckTargetCausesMultiVersioning( } // If this is 'default', permit the forward declaration. - if (!OldFD->isMultiVersion() && !OldTA && NewTA->isDefaultVersion()) { + if (!OldFD->isMultiVersion() && + ((NewTA && NewTA->isDefaultVersion() && !OldTA) || + (NewTVA && NewTVA->isDefaultVersion() && !OldTVA))) { Redeclaration = true; OldDecl = OldFD; OldFD->setIsMultiVersion(); @@ -10890,23 +11195,50 @@ static bool CheckTargetCausesMultiVersioning( return true; } - ParsedTargetAttr OldParsed = OldTA->parse(std::less<std::string>()); + if (NewTA) { + ParsedTargetAttr OldParsed = + S.getASTContext().getTargetInfo().parseTargetAttr( + OldTA->getFeaturesStr()); + llvm::sort(OldParsed.Features); + ParsedTargetAttr NewParsed = + S.getASTContext().getTargetInfo().parseTargetAttr( + NewTA->getFeaturesStr()); + // Sort order doesn't matter, it just needs to be consistent. + llvm::sort(NewParsed.Features); + if (OldParsed == NewParsed) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } - if (OldParsed == NewParsed) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); - S.Diag(OldFD->getLocation(), diag::note_previous_declaration); - NewFD->setInvalidDecl(); - return true; + if (NewTVA) { + llvm::SmallVector<StringRef, 8> Feats; + OldTVA->getFeatures(Feats); + llvm::sort(Feats); + llvm::SmallVector<StringRef, 8> NewFeats; + NewTVA->getFeatures(NewFeats); + llvm::sort(NewFeats); + + if (Feats == NewFeats) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } } for (const auto *FD : OldFD->redecls()) { const auto *CurTA = FD->getAttr<TargetAttr>(); + const auto *CurTVA = FD->getAttr<TargetVersionAttr>(); // We allow forward declarations before ANY multiversioning attributes, but // nothing after the fact. if (PreviousDeclsHaveMultiVersionAttribute(FD) && - (!CurTA || CurTA->isInherited())) { + ((NewTA && (!CurTA || CurTA->isInherited())) || + (NewTVA && (!CurTVA || CurTVA->isInherited())))) { S.Diag(FD->getLocation(), diag::err_multiversion_required_in_redecl) - << 0; + << (NewTA ? 0 : 2); S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); NewFD->setInvalidDecl(); return true; @@ -10937,11 +11269,11 @@ static bool MultiVersionTypesCompatible(MultiVersionKind Old, /// multiversioned declaration collection. static bool CheckMultiVersionAdditionalDecl( Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, - MultiVersionKind NewMVKind, const TargetAttr *NewTA, - const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec, - const TargetClonesAttr *NewClones, bool &Redeclaration, NamedDecl *&OldDecl, - LookupResult &Previous) { - + MultiVersionKind NewMVKind, const CPUDispatchAttr *NewCPUDisp, + const CPUSpecificAttr *NewCPUSpec, const TargetClonesAttr *NewClones, + bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) { + const auto *NewTA = NewFD->getAttr<TargetAttr>(); + const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>(); MultiVersionKind OldMVKind = OldFD->getMultiVersionKind(); // Disallow mixing of multiversioning types. if (!MultiVersionTypesCompatible(OldMVKind, NewMVKind)) { @@ -10953,9 +11285,15 @@ static bool CheckMultiVersionAdditionalDecl( ParsedTargetAttr NewParsed; if (NewTA) { - NewParsed = NewTA->parse(); + NewParsed = S.getASTContext().getTargetInfo().parseTargetAttr( + NewTA->getFeaturesStr()); llvm::sort(NewParsed.Features); } + llvm::SmallVector<StringRef, 8> NewFeats; + if (NewTVA) { + NewTVA->getFeatures(NewFeats); + llvm::sort(NewFeats); + } bool UseMemberUsingDeclRules = S.CurContext->isRecord() && !NewFD->getFriendObjectKind(); @@ -10963,16 +11301,30 @@ static bool CheckMultiVersionAdditionalDecl( bool MayNeedOverloadableChecks = AllowOverloadingOfFunction(Previous, S.Context, NewFD); - // Next, check ALL non-overloads to see if this is a redeclaration of a - // previous member of the MultiVersion set. + // Next, check ALL non-invalid non-overloads to see if this is a redeclaration + // of a previous member of the MultiVersion set. for (NamedDecl *ND : Previous) { FunctionDecl *CurFD = ND->getAsFunction(); - if (!CurFD) + if (!CurFD || CurFD->isInvalidDecl()) continue; if (MayNeedOverloadableChecks && S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) continue; + if (NewMVKind == MultiVersionKind::None && + OldMVKind == MultiVersionKind::TargetVersion) { + NewFD->addAttr(TargetVersionAttr::CreateImplicit( + S.Context, "default", NewFD->getSourceRange(), + AttributeCommonInfo::AS_GNU)); + NewFD->setIsMultiVersion(); + NewMVKind = MultiVersionKind::TargetVersion; + if (!NewTVA) { + NewTVA = NewFD->getAttr<TargetVersionAttr>(); + NewTVA->getFeatures(NewFeats); + llvm::sort(NewFeats); + } + } + switch (NewMVKind) { case MultiVersionKind::None: assert(OldMVKind == MultiVersionKind::TargetClones && @@ -10987,7 +11339,10 @@ static bool CheckMultiVersionAdditionalDecl( return false; } - ParsedTargetAttr CurParsed = CurTA->parse(std::less<std::string>()); + ParsedTargetAttr CurParsed = + S.getASTContext().getTargetInfo().parseTargetAttr( + CurTA->getFeaturesStr()); + llvm::sort(CurParsed.Features); if (CurParsed == NewParsed) { S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); S.Diag(CurFD->getLocation(), diag::note_previous_declaration); @@ -10996,6 +11351,27 @@ static bool CheckMultiVersionAdditionalDecl( } break; } + case MultiVersionKind::TargetVersion: { + const auto *CurTVA = CurFD->getAttr<TargetVersionAttr>(); + if (CurTVA->getName() == NewTVA->getName()) { + NewFD->setIsMultiVersion(); + Redeclaration = true; + OldDecl = ND; + return false; + } + llvm::SmallVector<StringRef, 8> CurFeats; + if (CurTVA) { + CurTVA->getFeatures(CurFeats); + llvm::sort(CurFeats); + } + if (CurFeats == NewFeats) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + break; + } case MultiVersionKind::TargetClones: { const auto *CurClones = CurFD->getAttr<TargetClonesAttr>(); Redeclaration = true; @@ -11078,7 +11454,8 @@ static bool CheckMultiVersionAdditionalDecl( // Else, this is simply a non-redecl case. Checking the 'value' is only // necessary in the Target case, since The CPUSpecific/Dispatch cases are // handled in the attribute adding step. - if (NewMVKind == MultiVersionKind::Target && + if ((NewMVKind == MultiVersionKind::TargetVersion || + NewMVKind == MultiVersionKind::Target) && CheckMultiVersionValue(S, NewFD)) { NewFD->setInvalidDecl(); return true; @@ -11116,16 +11493,20 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) { const auto *NewTA = NewFD->getAttr<TargetAttr>(); + const auto *NewTVA = NewFD->getAttr<TargetVersionAttr>(); const auto *NewCPUDisp = NewFD->getAttr<CPUDispatchAttr>(); const auto *NewCPUSpec = NewFD->getAttr<CPUSpecificAttr>(); const auto *NewClones = NewFD->getAttr<TargetClonesAttr>(); MultiVersionKind MVKind = NewFD->getMultiVersionKind(); // Main isn't allowed to become a multiversion function, however it IS - // permitted to have 'main' be marked with the 'target' optimization hint. + // permitted to have 'main' be marked with the 'target' optimization hint, + // for 'target_version' only default is allowed. if (NewFD->isMain()) { if (MVKind != MultiVersionKind::None && - !(MVKind == MultiVersionKind::Target && !NewTA->isDefaultVersion())) { + !(MVKind == MultiVersionKind::Target && !NewTA->isDefaultVersion()) && + !(MVKind == MultiVersionKind::TargetVersion && + NewTVA->isDefaultVersion())) { S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main); NewFD->setInvalidDecl(); return true; @@ -11140,18 +11521,34 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, // multiversioning, this isn't an error condition. if (MVKind == MultiVersionKind::None) return false; - return CheckMultiVersionFirstFunction(S, NewFD, MVKind, NewTA); + return CheckMultiVersionFirstFunction(S, NewFD); } FunctionDecl *OldFD = OldDecl->getAsFunction(); - if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) + if (!OldFD->isMultiVersion() && MVKind == MultiVersionKind::None) { + // No target_version attributes mean default + if (!NewTVA) { + const auto *OldTVA = OldFD->getAttr<TargetVersionAttr>(); + if (OldTVA) { + NewFD->addAttr(TargetVersionAttr::CreateImplicit( + S.Context, "default", NewFD->getSourceRange(), + AttributeCommonInfo::AS_GNU)); + NewFD->setIsMultiVersion(); + OldFD->setIsMultiVersion(); + OldDecl = OldFD; + Redeclaration = true; + return true; + } + } return false; + } // Multiversioned redeclarations aren't allowed to omit the attribute, except - // for target_clones. + // for target_clones and target_version. if (OldFD->isMultiVersion() && MVKind == MultiVersionKind::None && - OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones) { + OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones && + OldFD->getMultiVersionKind() != MultiVersionKind::TargetVersion) { S.Diag(NewFD->getLocation(), diag::err_multiversion_required_in_redecl) << (OldFD->getMultiVersionKind() != MultiVersionKind::Target); NewFD->setInvalidDecl(); @@ -11161,8 +11558,9 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, if (!OldFD->isMultiVersion()) { switch (MVKind) { case MultiVersionKind::Target: - return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA, - Redeclaration, OldDecl, Previous); + case MultiVersionKind::TargetVersion: + return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, Redeclaration, + OldDecl, Previous); case MultiVersionKind::TargetClones: if (OldFD->isUsed(false)) { NewFD->setInvalidDecl(); @@ -11170,6 +11568,7 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, } OldFD->setIsMultiVersion(); break; + case MultiVersionKind::CPUDispatch: case MultiVersionKind::CPUSpecific: case MultiVersionKind::None: @@ -11180,9 +11579,9 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, // At this point, we have a multiversion function decl (in OldFD) AND an // appropriate attribute in the current function decl. Resolve that these are // still compatible with previous declarations. - return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, MVKind, NewTA, - NewCPUDisp, NewCPUSpec, NewClones, - Redeclaration, OldDecl, Previous); + return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, MVKind, NewCPUDisp, + NewCPUSpec, NewClones, Redeclaration, + OldDecl, Previous); } /// Perform semantic checking of a new function declaration. @@ -11410,16 +11809,20 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) { CheckConstructor(Constructor); } else if (CXXDestructorDecl *Destructor = - dyn_cast<CXXDestructorDecl>(NewFD)) { - CXXRecordDecl *Record = Destructor->getParent(); - QualType ClassType = Context.getTypeDeclType(Record); - - // FIXME: Shouldn't we be able to perform this check even when the class - // type is dependent? Both gcc and edg can handle that. - if (!ClassType->isDependentType()) { - DeclarationName Name - = Context.DeclarationNames.getCXXDestructorName( - Context.getCanonicalType(ClassType)); + dyn_cast<CXXDestructorDecl>(NewFD)) { + // We check here for invalid destructor names. + // If we have a friend destructor declaration that is dependent, we can't + // diagnose right away because cases like this are still valid: + // template <class T> struct A { friend T::X::~Y(); }; + // struct B { struct Y { ~Y(); }; using X = Y; }; + // template struct A<B>; + if (NewFD->getFriendObjectKind() == Decl::FriendObjectKind::FOK_None || + !Destructor->getThisType()->isDependentType()) { + CXXRecordDecl *Record = Destructor->getParent(); + QualType ClassType = Context.getTypeDeclType(Record); + + DeclarationName Name = Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(ClassType)); if (NewFD->getDeclName() != Name) { Diag(NewFD->getLocation(), diag::err_destructor_name); NewFD->setInvalidDecl(); @@ -11756,6 +12159,34 @@ void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) { } } +void Sema::CheckHLSLEntryPoint(FunctionDecl *FD) { + auto &TargetInfo = getASTContext().getTargetInfo(); + auto const Triple = TargetInfo.getTriple(); + switch (Triple.getEnvironment()) { + default: + // FIXME: check all shader profiles. + break; + case llvm::Triple::EnvironmentType::Compute: + if (!FD->hasAttr<HLSLNumThreadsAttr>()) { + Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads) + << Triple.getEnvironmentName(); + FD->setInvalidDecl(); + } + break; + } + + for (const auto *Param : FD->parameters()) { + if (!Param->hasAttr<HLSLAnnotationAttr>()) { + // FIXME: Handle struct parameters where annotations are on struct fields. + // See: https://github.com/llvm/llvm-project/issues/57875 + Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation); + Diag(Param->getLocation(), diag::note_previous_decl) << Param; + FD->setInvalidDecl(); + } + } + // FIXME: Verify return type semantic annotation. +} + bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { // FIXME: Need strict checking. In C89, we need to check for // any assignment, increment, decrement, function-calls, or @@ -11822,7 +12253,7 @@ namespace { // Track and increment the index here. isInitList = true; InitFieldIndex.push_back(0); - for (auto Child : InitList->children()) { + for (auto *Child : InitList->children()) { CheckExpr(cast<Expr>(Child)); ++InitFieldIndex.back(); } @@ -12224,7 +12655,10 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, Type.getQualifiers()); QualType DeducedType; - if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) { + TemplateDeductionInfo Info(DeduceInit->getExprLoc()); + TemplateDeductionResult Result = + DeduceAutoType(TSI->getTypeLoc(), DeduceInit, DeducedType, Info); + if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) { if (!IsInitCapture) DiagnoseAutoDeductionFailure(VDecl, DeduceInit); else if (isa<InitListExpr>(Init)) @@ -12303,7 +12737,7 @@ void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init, InitType.hasNonTrivialToPrimitiveCopyCUnion()) && "shouldn't be called if type doesn't have a non-trivial C struct"); if (auto *ILE = dyn_cast<InitListExpr>(Init)) { - for (auto I : ILE->inits()) { + for (auto *I : ILE->inits()) { if (!I->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() && !I->getType().hasNonTrivialToPrimitiveCopyCUnion()) continue; @@ -12621,8 +13055,11 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } + // C99 6.7.8p5. If the declaration of an identifier has block scope, and + // the identifier has external or internal linkage, the declaration shall + // have no initializer for the identifier. + // C++14 [dcl.init]p5 is the same restriction for C++. if (VDecl->isLocalVarDecl() && VDecl->hasExternalStorage()) { - // C99 6.7.8p5. C++ has no such restriction, but that is a defect. Diag(VDecl->getLocation(), diag::err_block_extern_cant_init); VDecl->setInvalidDecl(); return; @@ -12648,6 +13085,16 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { VDecl->setInvalidDecl(); } + // C++ [module.import/6] external definitions are not permitted in header + // units. + if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() && + VDecl->isThisDeclarationADefinition() && + VDecl->getFormalLinkage() == Linkage::ExternalLinkage && + !VDecl->isInline()) { + Diag(VDecl->getLocation(), diag::err_extern_def_in_header_unit); + VDecl->setInvalidDecl(); + } + // If adding the initializer will turn this declaration into a definition, // and we already have a definition for this variable, diagnose or otherwise // handle the situation. @@ -12722,6 +13169,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // Perform the initialization. ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); + bool IsParenListInit = false; if (!VDecl->isInvalidDecl()) { InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); InitializationKind Kind = InitializationKind::CreateForInit( @@ -12764,6 +13212,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { } Init = Result.getAs<Expr>(); + IsParenListInit = !InitSeq.steps().empty() && + InitSeq.step_begin()->Kind == + InitializationSequence::SK_ParenthesizedListInit; } // Check for self-references within variable initializers. @@ -13012,7 +13463,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // class type. if (CXXDirectInit) { assert(DirectInit && "Call-style initializer must be direct init."); - VDecl->setInitStyle(VarDecl::CallInit); + VDecl->setInitStyle(IsParenListInit ? VarDecl::ParenListInit + : VarDecl::CallInit); } else if (DirectInit) { // This must be list-initialization. No other way is direct-initialization. VDecl->setInitStyle(VarDecl::ListInit); @@ -13177,7 +13629,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { // that has an in-class initializer, so we type-check this like // a declaration. // - LLVM_FALLTHROUGH; + [[fallthrough]]; case VarDecl::DeclarationOnly: // It's only a declaration. @@ -13247,8 +13699,12 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { // Provide a specific diagnostic for uninitialized variable // definitions with incomplete array type. if (Type->isIncompleteArrayType()) { - Diag(Var->getLocation(), - diag::err_typecheck_incomplete_array_needs_initializer); + if (Var->isConstexpr()) + Diag(Var->getLocation(), diag::err_constexpr_var_requires_const_init) + << Var; + else + Diag(Var->getLocation(), + diag::err_typecheck_incomplete_array_needs_initializer); Var->setInvalidDecl(); return; } @@ -13332,8 +13788,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { InitializationKind Kind = InitializationKind::CreateDefault(Var->getLocation()); - InitializationSequence InitSeq(*this, Entity, Kind, None); - ExprResult Init = InitSeq.Perform(*this, Entity, Kind, None); + InitializationSequence InitSeq(*this, Entity, Kind, std::nullopt); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, std::nullopt); if (Init.get()) { Var->setInit(MaybeCreateExprWithCleanups(Init.get())); @@ -13499,7 +13955,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { } // Cache the result of checking for constant initialization. - Optional<bool> CacheHasConstInit; + std::optional<bool> CacheHasConstInit; const Expr *CacheCulprit = nullptr; auto checkConstInit = [&]() mutable { if (!CacheHasConstInit) @@ -13770,6 +14226,26 @@ void Sema::CheckStaticLocalForDllExport(VarDecl *VD) { } } +void Sema::CheckThreadLocalForLargeAlignment(VarDecl *VD) { + assert(VD->getTLSKind()); + + // Perform TLS alignment check here after attributes attached to the variable + // which may affect the alignment have been processed. Only perform the check + // if the target has a maximum TLS alignment (zero means no constraints). + if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) { + // Protect the check so that it's not performed on dependent types and + // dependent alignments (we can't determine the alignment in that case). + if (!VD->hasDependentAlignment()) { + CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign); + if (Context.getDeclAlign(VD) > MaxAlignChars) { + Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) + << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD + << (unsigned)MaxAlignChars.getQuantity(); + } + } + } +} + /// FinalizeDeclaration - called by ParseDeclarationAfterDeclarator to perform /// any semantic actions necessary after any initializer has been attached. void Sema::FinalizeDeclaration(Decl *ThisDecl) { @@ -13813,25 +14289,12 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) { checkAttributesAfterMerging(*this, *VD); - // Perform TLS alignment check here after attributes attached to the variable - // which may affect the alignment have been processed. Only perform the check - // if the target has a maximum TLS alignment (zero means no constraints). - if (unsigned MaxAlign = Context.getTargetInfo().getMaxTLSAlign()) { - // Protect the check so that it's not performed on dependent types and - // dependent alignments (we can't determine the alignment in that case). - if (VD->getTLSKind() && !VD->hasDependentAlignment()) { - CharUnits MaxAlignChars = Context.toCharUnitsFromBits(MaxAlign); - if (Context.getDeclAlign(VD) > MaxAlignChars) { - Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) - << (unsigned)Context.getDeclAlign(VD).getQuantity() << VD - << (unsigned)MaxAlignChars.getQuantity(); - } - } - } - if (VD->isStaticLocal()) CheckStaticLocalForDllExport(VD); + if (VD->getTLSKind()) + CheckThreadLocalForLargeAlignment(VD); + // Perform check for initializers of device-side global variables. // CUDA allows empty constructors as initializers (see E.2.3.1, CUDA // 7.5). We must also apply the same checks to all __shared__ @@ -13917,7 +14380,7 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) { if (!MagicValueExpr) { continue; } - Optional<llvm::APSInt> MagicValueInt; + std::optional<llvm::APSInt> MagicValueInt; if (!(MagicValueInt = MagicValueExpr->getIntegerConstantExpr(Context))) { Diag(I->getRange().getBegin(), diag::err_type_tag_for_datatype_not_ice) @@ -14462,6 +14925,21 @@ void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) { Consumer.HandleInlineFunctionDefinition(D); } +static bool FindPossiblePrototype(const FunctionDecl *FD, + const FunctionDecl *&PossiblePrototype) { + for (const FunctionDecl *Prev = FD->getPreviousDecl(); Prev; + Prev = Prev->getPreviousDecl()) { + // Ignore any declarations that occur in function or method + // scope, because they aren't visible from the header. + if (Prev->getLexicalDeclContext()->isFunctionOrMethod()) + continue; + + PossiblePrototype = Prev; + return Prev->getType()->isFunctionProtoType(); + } + return false; +} + static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, const FunctionDecl *&PossiblePrototype) { @@ -14508,16 +14986,9 @@ ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, if (!FD->isExternallyVisible()) return false; - for (const FunctionDecl *Prev = FD->getPreviousDecl(); - Prev; Prev = Prev->getPreviousDecl()) { - // Ignore any declarations that occur in function or method - // scope, because they aren't visible from the header. - if (Prev->getLexicalDeclContext()->isFunctionOrMethod()) - continue; - - PossiblePrototype = Prev; - return Prev->getType()->isFunctionNoProtoType(); - } + // If we were able to find a potential prototype, don't warn. + if (FindPossiblePrototype(FD, PossiblePrototype)) + return false; return true; } @@ -14604,7 +15075,7 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, auto I = LambdaClass->field_begin(); for (const auto &C : LambdaClass->captures()) { if (C.capturesVariable()) { - VarDecl *VD = C.getCapturedVar(); + ValueDecl *VD = C.getCapturedVar(); if (VD->isInitCapture()) S.CurrentInstantiationScope->InstantiatedLocal(VD, VD); const bool ByRef = C.getCaptureKind() == LCK_ByRef; @@ -14646,8 +15117,12 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, // Do not push if it is a lambda because one is already pushed when building // the lambda in ActOnStartOfLambdaDefinition(). if (!isLambdaCallOperator(FD)) + // [expr.const]/p14.1 + // An expression or conversion is in an immediate function context if it is + // potentially evaluated and either: its innermost enclosing non-block scope + // is a function parameter scope of an immediate function. PushExpressionEvaluationContext( - FD->isConsteval() ? ExpressionEvaluationContext::ConstantEvaluated + FD->isConsteval() ? ExpressionEvaluationContext::ImmediateFunctionContext : ExprEvalContexts.back().Context); // Check for defining attributes before the check for redefinition. @@ -14661,6 +15136,16 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, FD->dropAttr<IFuncAttr>(); FD->setInvalidDecl(); } + if (const auto *Attr = FD->getAttr<TargetVersionAttr>()) { + if (!Context.getTargetInfo().hasFeature("fmv") && + !Attr->isDefaultVersion()) { + // If function multi versioning disabled skip parsing function body + // defined with non-default target_version attribute + if (SkipBody) + SkipBody->ShouldSkip = true; + return nullptr; + } + } if (auto *Ctor = dyn_cast<CXXConstructorDecl>(FD)) { if (Ctor->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && @@ -14757,7 +15242,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, } // Introduce our parameters into the function scope - for (auto Param : FD->parameters()) { + for (auto *Param : FD->parameters()) { Param->setOwningFunction(FD); // If this has an identifier, add it to the scope stack. @@ -14768,6 +15253,20 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, } } + // C++ [module.import/6] external definitions are not permitted in header + // units. Deleted and Defaulted functions are implicitly inline (but the + // inline state is not set at this point, so check the BodyKind explicitly). + // FIXME: Consider an alternate location for the test where the inlined() + // state is complete. + if (getLangOpts().CPlusPlusModules && currentModuleIsHeaderUnit() && + FD->getFormalLinkage() == Linkage::ExternalLinkage && + !FD->isInvalidDecl() && BodyKind != FnBodyKind::Delete && + BodyKind != FnBodyKind::Default && !FD->isInlined()) { + assert(FD->isThisDeclarationADefinition()); + Diag(FD->getLocation(), diag::err_extern_def_in_header_unit); + FD->setInvalidDecl(); + } + // Ensure that the function's exception specification is instantiated. if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>()) ResolveExceptionSpec(D->getLocation(), FPT); @@ -15081,6 +15580,12 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, } } + // We might not have found a prototype because we didn't wish to warn on + // the lack of a missing prototype. Try again without the checks for + // whether we want to warn on the missing prototype. + if (!PossiblePrototype) + (void)FindPossiblePrototype(FD, PossiblePrototype); + // If the function being defined does not have a prototype, then we may // need to diagnose it as changing behavior in C2x because we now know // whether the function accepts arguments or not. This only handles the @@ -15405,8 +15910,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, // Because typo correction is expensive, only do it if the implicit // function declaration is going to be treated as an error. // - // Perform the corection before issuing the main diagnostic, as some consumers - // use typo-correction callbacks to enhance the main diagnostic. + // Perform the correction before issuing the main diagnostic, as some + // consumers use typo-correction callbacks to enhance the main diagnostic. if (S && !ExternCPrev && (Diags.getDiagnosticLevel(diag_id, Loc) >= DiagnosticsEngine::Error)) { DeclFilterCCC<FunctionDecl> CCC{}; @@ -15459,8 +15964,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, - /*DeclsInPrototype=*/None, Loc, - Loc, D), + /*DeclsInPrototype=*/std::nullopt, + Loc, Loc, D), std::move(DS.getAttributes()), SourceLocation()); D.SetIdentifier(&II, Loc); @@ -15488,7 +15993,7 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction( FD->getDeclName().getCXXOverloadedOperator() != OO_Array_New) return; - Optional<unsigned> AlignmentParam; + std::optional<unsigned> AlignmentParam; bool IsNothrow = false; if (!FD->isReplaceableGlobalAllocationFunction(&AlignmentParam, &IsNothrow)) return; @@ -15529,7 +16034,7 @@ void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction( // specified by the value of this argument. if (AlignmentParam && !FD->hasAttr<AllocAlignAttr>()) { FD->addAttr(AllocAlignAttr::CreateImplicit( - Context, ParamIdx(AlignmentParam.value(), FD), FD->getLocation())); + Context, ParamIdx(*AlignmentParam, FD), FD->getLocation())); } // FIXME: @@ -15594,11 +16099,20 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->addAttr(CallbackAttr::CreateImplicit( Context, Encoding.data(), Encoding.size(), FD->getLocation())); - // Mark const if we don't care about errno and that is the only thing - // preventing the function from being const. This allows IRgen to use LLVM - // intrinsics for such functions. - if (!getLangOpts().MathErrno && !FD->hasAttr<ConstAttr>() && - Context.BuiltinInfo.isConstWithoutErrno(BuiltinID)) + // Mark const if we don't care about errno and/or floating point exceptions + // that are the only thing preventing the function from being const. This + // allows IRgen to use LLVM intrinsics for such functions. + bool NoExceptions = + getLangOpts().getDefaultExceptionMode() == LangOptions::FPE_Ignore; + bool ConstWithoutErrnoAndExceptions = + Context.BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID); + bool ConstWithoutExceptions = + Context.BuiltinInfo.isConstWithoutExceptions(BuiltinID); + if (!FD->hasAttr<ConstAttr>() && + (ConstWithoutErrnoAndExceptions || ConstWithoutExceptions) && + (!ConstWithoutErrnoAndExceptions || + (!getLangOpts().MathErrno && NoExceptions)) && + (!ConstWithoutExceptions || NoExceptions)) FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); // We make "fma" on GNU or Windows const because we know it does not set @@ -15674,6 +16188,24 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { default: break; } + + // Add lifetime attribute to std::move, std::fowrard et al. + switch (BuiltinID) { + case Builtin::BIaddressof: + case Builtin::BI__addressof: + case Builtin::BI__builtin_addressof: + case Builtin::BIas_const: + case Builtin::BIforward: + case Builtin::BImove: + case Builtin::BImove_if_noexcept: + if (ParmVarDecl *P = FD->getParamDecl(0u); + !P->hasAttr<LifetimeBoundAttr>()) + P->addAttr( + LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation())); + break; + default: + break; + } } AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD); @@ -16075,17 +16607,17 @@ static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC, /// /// \param SkipBody If non-null, will be set to indicate if the caller should /// skip the definition of this tag and treat it as if it were a declaration. -Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, CXXScopeSpec &SS, - IdentifierInfo *Name, SourceLocation NameLoc, - const ParsedAttributesView &Attrs, AccessSpecifier AS, - SourceLocation ModulePrivateLoc, - MultiTemplateParamsArg TemplateParameterLists, - bool &OwnedDecl, bool &IsDependent, - SourceLocation ScopedEnumKWLoc, - bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, - bool IsTypeSpecifier, bool IsTemplateParamOrArg, - SkipBodyInfo *SkipBody) { +DeclResult +Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, + const ParsedAttributesView &Attrs, AccessSpecifier AS, + SourceLocation ModulePrivateLoc, + MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, + bool &IsDependent, SourceLocation ScopedEnumKWLoc, + bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, + bool IsTypeSpecifier, bool IsTemplateParamOrArg, + OffsetOfKind OOK, UsingShadowDecl *&FoundUsingShadow, + SkipBodyInfo *SkipBody) { // If this is not a definition, it must have a name. IdentifierInfo *OrigName = Name; assert((Name != nullptr || TUK == TUK_Definition) && @@ -16111,7 +16643,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, TUK == TUK_Friend, isMemberSpecialization, Invalid)) { if (Kind == TTK_Enum) { Diag(KWLoc, diag::err_enum_template); - return nullptr; + return true; } if (TemplateParams->size() > 0) { @@ -16119,7 +16651,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // be a member of another template). if (Invalid) - return nullptr; + return true; OwnedDecl = false; DeclResult Result = CheckClassTemplate( @@ -16138,7 +16670,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (!TemplateParameterLists.empty() && isMemberSpecialization && CheckTemplateDeclScope(S, TemplateParameterLists.back())) - return nullptr; + return true; } // Figure out the underlying type if this a enum declaration. We need to do @@ -16210,7 +16742,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, else ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0)); QualType EnumTy = ED->getIntegerType(); - ED->setPromotionType(EnumTy->isPromotableIntegerType() + ED->setPromotionType(Context.isPromotableIntegerType(EnumTy) ? Context.getPromotedIntegerType(EnumTy) : EnumTy); } @@ -16254,26 +16786,26 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, DC = computeDeclContext(SS, false); if (!DC) { IsDependent = true; - return nullptr; + return true; } } else { DC = computeDeclContext(SS, true); if (!DC) { Diag(SS.getRange().getBegin(), diag::err_dependent_nested_name_spec) << SS.getRange(); - return nullptr; + return true; } } if (RequireCompleteDeclContext(SS, DC)) - return nullptr; + return true; SearchDC = DC; // Look-up name inside 'foo::'. LookupQualifiedName(Previous, DC); if (Previous.isAmbiguous()) - return nullptr; + return true; if (Previous.empty()) { // Name lookup did not find anything. However, if the @@ -16285,7 +16817,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Previous.wasNotFoundInCurrentInstantiation() && (TUK == TUK_Reference || TUK == TUK_Friend)) { IsDependent = true; - return nullptr; + return true; } // A tag 'foo::bar' must already exist. @@ -16302,7 +16834,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // -- every member of class T that is itself a type if (TUK != TUK_Reference && TUK != TUK_Friend && DiagnoseClassNameShadow(SearchDC, DeclarationNameInfo(Name, NameLoc))) - return nullptr; + return true; // If this is a named struct, check to see if there was a previous forward // declaration or definition. @@ -16366,7 +16898,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // Note: there used to be some attempt at recovery here. if (Previous.isAmbiguous()) - return nullptr; + return true; if (!getLangOpts().CPlusPlus && TUK != TUK_Reference) { // FIXME: This makes sure that we ignore the contexts associated @@ -16520,6 +17052,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // redefinition if either context is within the other. if (auto *Shadow = dyn_cast<UsingShadowDecl>(DirectPrevDecl)) { auto *OldTag = dyn_cast<TagDecl>(PrevDecl); + FoundUsingShadow = Shadow; if (SS.isEmpty() && TUK != TUK_Reference && TUK != TUK_Friend && isDeclInScope(Shadow, SearchDC, S, isMemberSpecialization) && !(OldTag && isAcceptableTagRedeclContext( @@ -16836,7 +17369,7 @@ CreateNewDecl: else ED->setIntegerType(QualType(EnumUnderlying.get<const Type *>(), 0)); QualType EnumTy = ED->getIntegerType(); - ED->setPromotionType(EnumTy->isPromotableIntegerType() + ED->setPromotionType(Context.isPromotableIntegerType(EnumTy) ? Context.getPromotedIntegerType(EnumTy) : EnumTy); assert(ED->isComplete() && "enum with type should be complete"); @@ -16858,10 +17391,14 @@ CreateNewDecl: cast_or_null<RecordDecl>(PrevDecl)); } + if (OOK != OOK_Outside && TUK == TUK_Definition && !getLangOpts().CPlusPlus) + Diag(New->getLocation(), diag::ext_type_defined_in_offsetof) + << (OOK == OOK_Macro) << New->getSourceRange(); + // C++11 [dcl.type]p3: // A type-specifier-seq shall not define a class or enumeration [...]. - if (getLangOpts().CPlusPlus && (IsTypeSpecifier || IsTemplateParamOrArg) && - TUK == TUK_Definition) { + if (!Invalid && getLangOpts().CPlusPlus && + (IsTypeSpecifier || IsTemplateParamOrArg) && TUK == TUK_Definition) { Diag(New->getLocation(), diag::err_type_defined_in_type_specifier) << Context.getTagDeclType(New); Invalid = true; @@ -17017,7 +17554,7 @@ CreateNewDecl: if (New->isBeingDefined()) if (auto RD = dyn_cast<RecordDecl>(New)) RD->completeDefinition(); - return nullptr; + return true; } else if (SkipBody && SkipBody->ShouldSkip) { return SkipBody->Previous; } else { @@ -17805,7 +18342,6 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, AllIvarDecls.push_back(Ivar); } -namespace { /// [class.dtor]p4: /// At the end of the definition of a class, overload resolution is /// performed among the prospective destructors declared in that class with @@ -17814,7 +18350,7 @@ namespace { /// /// We do the overload resolution here, then mark the selected constructor in the AST. /// Later CXXRecordDecl::getDestructor() will return the selected constructor. -void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) { +static void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) { if (!Record->hasUserDeclaredDestructor()) { return; } @@ -17872,7 +18408,145 @@ void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) { Record->addedSelectedDestructor(dyn_cast<CXXDestructorDecl>(OCS.begin()->Function)); } } -} // namespace + +/// [class.mem.special]p5 +/// Two special member functions are of the same kind if: +/// - they are both default constructors, +/// - they are both copy or move constructors with the same first parameter +/// type, or +/// - they are both copy or move assignment operators with the same first +/// parameter type and the same cv-qualifiers and ref-qualifier, if any. +static bool AreSpecialMemberFunctionsSameKind(ASTContext &Context, + CXXMethodDecl *M1, + CXXMethodDecl *M2, + Sema::CXXSpecialMember CSM) { + // We don't want to compare templates to non-templates: See + // https://github.com/llvm/llvm-project/issues/59206 + if (CSM == Sema::CXXDefaultConstructor) + return bool(M1->getDescribedFunctionTemplate()) == + bool(M2->getDescribedFunctionTemplate()); + if (!Context.hasSameType(M1->getParamDecl(0)->getType(), + M2->getParamDecl(0)->getType())) + return false; + if (!Context.hasSameType(M1->getThisType(), M2->getThisType())) + return false; + + return true; +} + +/// [class.mem.special]p6: +/// An eligible special member function is a special member function for which: +/// - the function is not deleted, +/// - the associated constraints, if any, are satisfied, and +/// - no special member function of the same kind whose associated constraints +/// [CWG2595], if any, are satisfied is more constrained. +static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record, + ArrayRef<CXXMethodDecl *> Methods, + Sema::CXXSpecialMember CSM) { + SmallVector<bool, 4> SatisfactionStatus; + + for (CXXMethodDecl *Method : Methods) { + const Expr *Constraints = Method->getTrailingRequiresClause(); + if (!Constraints) + SatisfactionStatus.push_back(true); + else { + ConstraintSatisfaction Satisfaction; + if (S.CheckFunctionConstraints(Method, Satisfaction)) + SatisfactionStatus.push_back(false); + else + SatisfactionStatus.push_back(Satisfaction.IsSatisfied); + } + } + + for (size_t i = 0; i < Methods.size(); i++) { + if (!SatisfactionStatus[i]) + continue; + CXXMethodDecl *Method = Methods[i]; + CXXMethodDecl *OrigMethod = Method; + if (FunctionDecl *MF = OrigMethod->getInstantiatedFromMemberFunction()) + OrigMethod = cast<CXXMethodDecl>(MF); + + const Expr *Constraints = OrigMethod->getTrailingRequiresClause(); + bool AnotherMethodIsMoreConstrained = false; + for (size_t j = 0; j < Methods.size(); j++) { + if (i == j || !SatisfactionStatus[j]) + continue; + CXXMethodDecl *OtherMethod = Methods[j]; + if (FunctionDecl *MF = OtherMethod->getInstantiatedFromMemberFunction()) + OtherMethod = cast<CXXMethodDecl>(MF); + + if (!AreSpecialMemberFunctionsSameKind(S.Context, OrigMethod, OtherMethod, + CSM)) + continue; + + const Expr *OtherConstraints = OtherMethod->getTrailingRequiresClause(); + if (!OtherConstraints) + continue; + if (!Constraints) { + AnotherMethodIsMoreConstrained = true; + break; + } + if (S.IsAtLeastAsConstrained(OtherMethod, {OtherConstraints}, OrigMethod, + {Constraints}, + AnotherMethodIsMoreConstrained)) { + // There was an error with the constraints comparison. Exit the loop + // and don't consider this function eligible. + AnotherMethodIsMoreConstrained = true; + } + if (AnotherMethodIsMoreConstrained) + break; + } + // FIXME: Do not consider deleted methods as eligible after implementing + // DR1734 and DR1496. + if (!AnotherMethodIsMoreConstrained) { + Method->setIneligibleOrNotSelected(false); + Record->addedEligibleSpecialMemberFunction(Method, 1 << CSM); + } + } +} + +static void ComputeSpecialMemberFunctionsEligiblity(Sema &S, + CXXRecordDecl *Record) { + SmallVector<CXXMethodDecl *, 4> DefaultConstructors; + SmallVector<CXXMethodDecl *, 4> CopyConstructors; + SmallVector<CXXMethodDecl *, 4> MoveConstructors; + SmallVector<CXXMethodDecl *, 4> CopyAssignmentOperators; + SmallVector<CXXMethodDecl *, 4> MoveAssignmentOperators; + + for (auto *Decl : Record->decls()) { + auto *MD = dyn_cast<CXXMethodDecl>(Decl); + if (!MD) { + auto *FTD = dyn_cast<FunctionTemplateDecl>(Decl); + if (FTD) + MD = dyn_cast<CXXMethodDecl>(FTD->getTemplatedDecl()); + } + if (!MD) + continue; + if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { + if (CD->isInvalidDecl()) + continue; + if (CD->isDefaultConstructor()) + DefaultConstructors.push_back(MD); + else if (CD->isCopyConstructor()) + CopyConstructors.push_back(MD); + else if (CD->isMoveConstructor()) + MoveConstructors.push_back(MD); + } else if (MD->isCopyAssignmentOperator()) { + CopyAssignmentOperators.push_back(MD); + } else if (MD->isMoveAssignmentOperator()) { + MoveAssignmentOperators.push_back(MD); + } + } + + SetEligibleMethods(S, Record, DefaultConstructors, + Sema::CXXDefaultConstructor); + SetEligibleMethods(S, Record, CopyConstructors, Sema::CXXCopyConstructor); + SetEligibleMethods(S, Record, MoveConstructors, Sema::CXXMoveConstructor); + SetEligibleMethods(S, Record, CopyAssignmentOperators, + Sema::CXXCopyAssignment); + SetEligibleMethods(S, Record, MoveAssignmentOperators, + Sema::CXXMoveAssignment); +} void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, ArrayRef<Decl *> Fields, SourceLocation LBrac, @@ -17900,9 +18574,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl); CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(EnclosingDecl); - if (CXXRecord && !CXXRecord->isDependentType()) - ComputeSelectedDestructor(*this, CXXRecord); - // Start counting up the number of named members; make sure to include // members of anonymous structs and unions in the total. unsigned NumNamedMembers = 0; @@ -18188,6 +18859,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Completed = true; } } + ComputeSelectedDestructor(*this, CXXRecord); + ComputeSpecialMemberFunctionsEligiblity(*this, CXXRecord); } } @@ -18910,7 +19583,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, } } - // If we have have an empty set of enumerators we still need one bit. + // If we have an empty set of enumerators we still need one bit. // From [dcl.enum]p8 // If the enumerator-list is empty, the values of the enumeration are as if // the enumeration had a single enumerator with value 0 @@ -18942,7 +19615,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, // target, promote that type instead of analyzing the enumerators. if (Enum->isComplete()) { BestType = Enum->getIntegerType(); - if (BestType->isPromotableIntegerType()) + if (Context.isPromotableIntegerType(BestType)) BestPromotionType = Context.getPromotedIntegerType(BestType); else BestPromotionType = BestType; @@ -19107,6 +19780,12 @@ Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr, return New; } +Decl *Sema::ActOnTopLevelStmtDecl(Stmt *Statement) { + auto *New = TopLevelStmtDecl::Create(Context, Statement); + Context.getTranslationUnitDecl()->addDecl(New); + return New; +} + void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, IdentifierInfo* AliasName, SourceLocation PragmaLoc, @@ -19129,7 +19808,7 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, else Diag(PrevDecl->getLocation(), diag::warn_redefine_extname_not_applied) << /*Variable*/(isa<FunctionDecl>(PrevDecl) ? 0 : 1) << PrevDecl; - // Otherwise, add a label atttibute to ExtnameUndeclaredIdentifiers. + // Otherwise, add a label attribute to ExtnameUndeclaredIdentifiers. } else (void)ExtnameUndeclaredIdentifiers.insert(std::make_pair(Name, Attr)); } @@ -19195,7 +19874,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD, if (LangOpts.OpenMPIsDevice) { // In OpenMP device mode we will not emit host only functions, or functions // we don't need due to their linkage. - Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl()); // DevTy may be changed later by // #pragma omp declare target to(*) device_type(*). @@ -19217,7 +19896,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD, // In OpenMP host compilation prior to 5.0 everything was an emitted host // function. In 5.0, no_host was introduced which might cause a function to // be ommitted. - Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = OMPDeclareTargetDeclAttr::getDeviceType(FD->getCanonicalDecl()); if (DevTy) if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 838fd48357fb..a303c7f57280 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -24,6 +24,7 @@ #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/DarwinSDKInfo.h" +#include "clang/Basic/HLSLRuntime.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" @@ -38,7 +39,6 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Assumptions.h" @@ -46,6 +46,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" +#include <optional> using namespace clang; using namespace sema; @@ -201,7 +202,7 @@ static unsigned getNumAttributeArgs(const ParsedAttr &AL) { /// A helper function to provide Attribute Location for the Attr types /// AND the ParsedAttr. template <typename AttrInfo> -static std::enable_if_t<std::is_base_of<Attr, AttrInfo>::value, SourceLocation> +static std::enable_if_t<std::is_base_of_v<Attr, AttrInfo>, SourceLocation> getAttrLoc(const AttrInfo &AL) { return AL.getLocation(); } @@ -216,7 +217,7 @@ template <typename AttrInfo> static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, uint32_t &Val, unsigned Idx = UINT_MAX, bool StrictlyUnsigned = false) { - Optional<llvm::APSInt> I = llvm::APSInt(32); + std::optional<llvm::APSInt> I = llvm::APSInt(32); if (Expr->isTypeDependent() || !(I = Expr->getIntegerConstantExpr(S.Context))) { if (Idx != UINT_MAX) @@ -308,7 +309,7 @@ static bool checkFunctionOrMethodParameterIndex( unsigned NumParams = (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam; - Optional<llvm::APSInt> IdxInt; + std::optional<llvm::APSInt> IdxInt; if (IdxExpr->isTypeDependent() || !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) { S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) @@ -1689,7 +1690,7 @@ void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, } if (!E->isValueDependent()) { - Optional<llvm::APSInt> I = llvm::APSInt(64); + std::optional<llvm::APSInt> I = llvm::APSInt(64); if (!(I = E->getIntegerConstantExpr(Context))) { if (OE) Diag(AttrLoc, diag::err_attribute_argument_n_type) @@ -1876,8 +1877,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { for (const auto *I : D->specific_attrs<OwnershipAttr>()) { // Cannot have two ownership attributes of different kinds for the same // index. - if (I->getOwnKind() != K && I->args_end() != - std::find(I->args_begin(), I->args_end(), Idx)) { + if (I->getOwnKind() != K && llvm::is_contained(I->args(), Idx)) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I; return; } else if (K == OwnershipAttr::Returns && @@ -2329,6 +2329,10 @@ static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { 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() && !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority)) return; @@ -2630,7 +2634,7 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } if (II->isStr("fuchsia")) { - Optional<unsigned> Min, Sub; + std::optional<unsigned> Min, Sub; if ((Min = Introduced.Version.getMinor()) || (Sub = Introduced.Version.getSubminor())) { S.Diag(AL.getLoc(), diag::warn_availability_fuchsia_unavailable_minor); @@ -2672,8 +2676,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (IOSToWatchOSMapping) { if (auto MappedVersion = IOSToWatchOSMapping->map( - Version, MinimumWatchOSVersion, None)) { - return MappedVersion.value(); + Version, MinimumWatchOSVersion, std::nullopt)) { + return *MappedVersion; } } @@ -2682,10 +2686,10 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (NewMajor >= 2) { if (Version.getMinor()) { if (Version.getSubminor()) - return VersionTuple(NewMajor, Version.getMinor().value(), - Version.getSubminor().value()); + return VersionTuple(NewMajor, *Version.getMinor(), + *Version.getSubminor()); else - return VersionTuple(NewMajor, Version.getMinor().value()); + return VersionTuple(NewMajor, *Version.getMinor()); } return VersionTuple(NewMajor); } @@ -2727,8 +2731,8 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return Version; if (IOSToTvOSMapping) { - if (auto MappedVersion = - IOSToTvOSMapping->map(Version, VersionTuple(0, 0), None)) { + if (auto MappedVersion = IOSToTvOSMapping->map( + Version, VersionTuple(0, 0), std::nullopt)) { return *MappedVersion; } } @@ -2791,24 +2795,25 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // attributes that are inferred from 'ios'. NewII = &S.Context.Idents.get("maccatalyst"); auto RemapMacOSVersion = - [&](const VersionTuple &V) -> Optional<VersionTuple> { + [&](const VersionTuple &V) -> std::optional<VersionTuple> { if (V.empty()) - return None; + return std::nullopt; // API_TO_BE_DEPRECATED is 100000. if (V.getMajor() == 100000) return VersionTuple(100000); // The minimum iosmac version is 13.1 - return MacOStoMacCatalystMapping->map(V, VersionTuple(13, 1), None); + return MacOStoMacCatalystMapping->map(V, VersionTuple(13, 1), + std::nullopt); }; - Optional<VersionTuple> NewIntroduced = - RemapMacOSVersion(Introduced.Version), - NewDeprecated = - RemapMacOSVersion(Deprecated.Version), - NewObsoleted = - RemapMacOSVersion(Obsoleted.Version); + std::optional<VersionTuple> NewIntroduced = + RemapMacOSVersion(Introduced.Version), + NewDeprecated = + RemapMacOSVersion(Deprecated.Version), + NewObsoleted = + RemapMacOSVersion(Obsoleted.Version); if (NewIntroduced || NewDeprecated || NewObsoleted) { auto VersionOrEmptyVersion = - [](const Optional<VersionTuple> &V) -> VersionTuple { + [](const std::optional<VersionTuple> &V) -> VersionTuple { return V ? *V : VersionTuple(); }; AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr( @@ -3032,7 +3037,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel; if (AL.getNumArgs() > 0) { Expr *E = AL.getArgAsExpr(0); - Optional<llvm::APSInt> Idx = llvm::APSInt(32); + std::optional<llvm::APSInt> Idx = llvm::APSInt(32); if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) << AL << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange(); @@ -3051,7 +3056,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos; if (AL.getNumArgs() > 1) { Expr *E = AL.getArgAsExpr(1); - Optional<llvm::APSInt> Idx = llvm::APSInt(32); + std::optional<llvm::APSInt> Idx = llvm::APSInt(32); if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) << AL << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange(); @@ -3146,7 +3151,7 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { if (LO.CPlusPlus && !LO.CPlusPlus20) S.Diag(AL.getLoc(), diag::ext_cxx20_attr) << AL; - // Since this this is spelled [[nodiscard]], get the optional string + // Since this is spelled [[nodiscard]], get the optional string // literal. If in C++ mode, but not in C++2a mode, diagnose as an // extension. // FIXME: C2x should support this feature as well, even as an extension. @@ -3391,7 +3396,7 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // handled later in the process, once we know how many exist. bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { enum FirstParam { Unsupported, Duplicate, Unknown }; - enum SecondParam { None, Architecture, Tune }; + enum SecondParam { None, CPU, Tune }; enum ThirdParam { Target, TargetClones }; if (AttrStr.contains("fpmath=")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) @@ -3403,24 +3408,22 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "tune=" << Target; - ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr); + ParsedTargetAttr ParsedAttrs = + Context.getTargetInfo().parseTargetAttr(AttrStr); - if (!ParsedAttrs.Architecture.empty() && - !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture)) + if (!ParsedAttrs.CPU.empty() && + !Context.getTargetInfo().isValidCPUName(ParsedAttrs.CPU)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unknown << Architecture << ParsedAttrs.Architecture << Target; + << Unknown << CPU << ParsedAttrs.CPU << Target; if (!ParsedAttrs.Tune.empty() && !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unknown << Tune << ParsedAttrs.Tune << Target; - if (ParsedAttrs.DuplicateArchitecture) - return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Duplicate << None << "arch=" << Target; - if (ParsedAttrs.DuplicateTune) + if (ParsedAttrs.Duplicate != "") return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Duplicate << None << "tune=" << Target; + << Duplicate << None << ParsedAttrs.Duplicate << Target; for (const auto &Feature : ParsedAttrs.Features) { auto CurFeature = StringRef(Feature).drop_front(); // remove + or -. @@ -3434,8 +3437,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { if (ParsedAttrs.BranchProtection.empty()) return false; if (!Context.getTargetInfo().validateBranchProtection( - ParsedAttrs.BranchProtection, ParsedAttrs.Architecture, BPI, - DiagMsg)) { + ParsedAttrs.BranchProtection, ParsedAttrs.CPU, BPI, DiagMsg)) { if (DiagMsg.empty()) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "branch-protection" << Target; @@ -3448,6 +3450,42 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { return false; } +// Check Target Version attrs +bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr, + bool &isDefault) { + enum FirstParam { Unsupported }; + enum SecondParam { None }; + enum ThirdParam { Target, TargetClones, TargetVersion }; + if (AttrStr.trim() == "default") + isDefault = true; + llvm::SmallVector<StringRef, 8> Features; + AttrStr.split(Features, "+"); + for (auto &CurFeature : Features) { + CurFeature = CurFeature.trim(); + if (CurFeature == "default") + continue; + if (!Context.getTargetInfo().validateCpuSupports(CurFeature)) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << CurFeature << TargetVersion; + } + return false; +} + +static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Str; + SourceLocation LiteralLoc; + bool isDefault = false; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || + S.checkTargetVersionAttr(LiteralLoc, Str, isDefault)) + return; + // Do not create default only target_version attribute + if (!isDefault) { + TargetVersionAttr *NewAttr = + ::new (S.Context) TargetVersionAttr(S.Context, AL, Str); + D->addAttr(NewAttr); + } +} + static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; SourceLocation LiteralLoc; @@ -3459,12 +3497,12 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(NewAttr); } -bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, - const StringLiteral *Literal, - bool &HasDefault, bool &HasCommas, - SmallVectorImpl<StringRef> &Strings) { +bool Sema::checkTargetClonesAttrString( + SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal, + bool &HasDefault, bool &HasCommas, bool &HasNotDefault, + SmallVectorImpl<SmallString<64>> &StringsBuffer) { enum FirstParam { Unsupported, Duplicate, Unknown }; - enum SecondParam { None, Architecture, Tune }; + enum SecondParam { None, CPU, Tune }; enum ThirdParam { Target, TargetClones }; HasCommas = HasCommas || Str.contains(','); // Warn on empty at the beginning of a string. @@ -3481,29 +3519,75 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, getLangOpts(), Context.getTargetInfo()); bool DefaultIsDupe = false; + bool HasCodeGenImpact = false; if (Cur.empty()) return Diag(CurLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "" << TargetClones; - if (Cur.startswith("arch=")) { - if (!Context.getTargetInfo().isValidCPUName( - Cur.drop_front(sizeof("arch=") - 1))) + if (Context.getTargetInfo().getTriple().isAArch64()) { + // AArch64 target clones specific + if (Cur == "default") { + DefaultIsDupe = HasDefault; + HasDefault = true; + if (llvm::is_contained(StringsBuffer, Cur) || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + else + StringsBuffer.push_back(Cur); + } else { + std::pair<StringRef, StringRef> CurParts = {{}, Cur}; + llvm::SmallVector<StringRef, 8> CurFeatures; + while (!CurParts.second.empty()) { + CurParts = CurParts.second.split('+'); + StringRef CurFeature = CurParts.first.trim(); + if (!Context.getTargetInfo().validateCpuSupports(CurFeature)) { + Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << CurFeature << TargetClones; + continue; + } + std::string Options; + if (Context.getTargetInfo().getFeatureDepOptions(CurFeature, Options)) + HasCodeGenImpact = true; + CurFeatures.push_back(CurFeature); + } + // Canonize TargetClones Attributes + llvm::sort(CurFeatures); + SmallString<64> Res; + for (auto &CurFeat : CurFeatures) { + if (!Res.equals("")) + Res.append("+"); + Res.append(CurFeat); + } + if (llvm::is_contained(StringsBuffer, Res) || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + else if (!HasCodeGenImpact) + // Ignore features in target_clone attribute that don't impact + // code generation + Diag(CurLoc, diag::warn_target_clone_no_impact_options); + else if (!Res.empty()) { + StringsBuffer.push_back(Res); + HasNotDefault = true; + } + } + } else { + // Other targets ( currently X86 ) + if (Cur.startswith("arch=")) { + if (!Context.getTargetInfo().isValidCPUName( + Cur.drop_front(sizeof("arch=") - 1))) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << CPU << Cur.drop_front(sizeof("arch=") - 1) + << TargetClones; + } else if (Cur == "default") { + DefaultIsDupe = HasDefault; + HasDefault = true; + } else if (!Context.getTargetInfo().isValidFeatureName(Cur)) return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << Architecture - << Cur.drop_front(sizeof("arch=") - 1) << TargetClones; - } else if (Cur == "default") { - DefaultIsDupe = HasDefault; - HasDefault = true; - } else if (!Context.getTargetInfo().isValidFeatureName(Cur)) - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Cur << TargetClones; - - if (llvm::is_contained(Strings, Cur) || DefaultIsDupe) - Diag(CurLoc, diag::warn_target_clone_duplicate_options); - // Note: Add even if there are duplicates, since it changes name mangling. - Strings.push_back(Cur); + << Unsupported << None << Cur << TargetClones; + if (llvm::is_contained(StringsBuffer, Cur) || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + // Note: Add even if there are duplicates, since it changes name mangling. + StringsBuffer.push_back(Cur); + } } - if (Str.rtrim().endswith(",")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "" << TargetClones; @@ -3511,6 +3595,10 @@ bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, } static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (S.Context.getTargetInfo().getTriple().isAArch64() && + !S.Context.getTargetInfo().hasFeature("fmv")) + return; + // Ensure we don't combine these with themselves, since that causes some // confusing behavior. if (const auto *Other = D->getAttr<TargetClonesAttr>()) { @@ -3522,7 +3610,8 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; SmallVector<StringRef, 2> Strings; - bool HasCommas = false, HasDefault = false; + SmallVector<SmallString<64>, 2> StringsBuffer; + bool HasCommas = false, HasDefault = false, HasNotDefault = false; for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { StringRef CurStr; @@ -3531,13 +3620,21 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.checkTargetClonesAttrString( LiteralLoc, CurStr, cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()), - HasDefault, HasCommas, Strings)) + HasDefault, HasCommas, HasNotDefault, StringsBuffer)) return; } + for (auto &SmallStr : StringsBuffer) + Strings.push_back(SmallStr.str()); if (HasCommas && AL.getNumArgs() > 1) S.Diag(AL.getLoc(), diag::warn_target_clone_mixed_values); + if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasDefault) { + // Add default attribute if there is no one + HasDefault = true; + Strings.push_back("default"); + } + if (!HasDefault) { S.Diag(AL.getLoc(), diag::err_target_clone_must_have_default); return; @@ -3554,6 +3651,10 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } + // No multiversion if we have default version only. + if (S.Context.getTargetInfo().getTriple().isAArch64() && !HasNotDefault) + return; + cast<FunctionDecl>(D)->setIsMultiVersion(); TargetClonesAttr *NewAttr = ::new (S.Context) TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size()); @@ -3730,6 +3831,11 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL; return; } + + if (S.getLangOpts().HLSL) { + S.Diag(AL.getLoc(), diag::err_hlsl_init_priority_unsupported); + return; + } if (S.getCurFunctionOrMethodDecl()) { S.Diag(AL.getLoc(), diag::err_init_priority_object_attr); @@ -3884,27 +3990,38 @@ static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3)) return; - // check if the function is variadic if the 3rd argument non-zero + // FirstArg == 0 is is always valid. if (FirstArg != 0) { - if (isFunctionOrMethodVariadic(D)) - ++NumArgs; // +1 for ... - else - S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL; - } - - // strftime requires FirstArg to be 0 because it doesn't read from any - // variable the input is just the current time + the format string. - if (Kind == StrftimeFormat) { - if (FirstArg != 0) { + if (Kind == StrftimeFormat) { + // If the kind is strftime, FirstArg must be 0 because strftime does not + // use any variadic arguments. S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter) - << FirstArgExpr->getSourceRange(); - return; + << FirstArgExpr->getSourceRange() + << FixItHint::CreateReplacement(FirstArgExpr->getSourceRange(), "0"); + return; + } else if (isFunctionOrMethodVariadic(D)) { + // Else, if the function is variadic, then FirstArg must be 0 or the + // "position" of the ... parameter. It's unusual to use 0 with variadic + // functions, so the fixit proposes the latter. + if (FirstArg != NumArgs + 1) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << 3 << FirstArgExpr->getSourceRange() + << FixItHint::CreateReplacement(FirstArgExpr->getSourceRange(), + std::to_string(NumArgs + 1)); + return; + } + } else { + // Inescapable GCC compatibility diagnostic. + S.Diag(D->getLocation(), diag::warn_gcc_requires_variadic_function) << AL; + if (FirstArg <= Idx) { + // Else, the function is not variadic, and FirstArg must be 0 or any + // parameter after the format parameter. We don't offer a fixit because + // there are too many possible good values. + S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) + << AL << 3 << FirstArgExpr->getSourceRange(); + return; + } } - // if 0 it disables parameter checking (to use with e.g. va_list) - } else if (FirstArg != 0 && FirstArg != NumArgs) { - S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds) - << AL << 3 << FirstArgExpr->getSourceRange(); - return; } FormatAttr *NewAttr = S.mergeFormatAttr(D, AL, II, Idx, FirstArg); @@ -4335,7 +4452,7 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, } const auto *VD = dyn_cast<VarDecl>(D); - if (VD && Context.getTargetInfo().isTLSSupported()) { + if (VD) { unsigned MaxTLSAlign = Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign()) .getQuantity(); @@ -4500,7 +4617,7 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, break; case 7: if (Str == "pointer") - DestWidth = S.Context.getTargetInfo().getPointerWidth(0); + DestWidth = S.Context.getTargetInfo().getPointerWidth(LangAS::Default); break; case 11: if (Str == "unwind_word") @@ -5388,7 +5505,7 @@ static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, if (E->isValueDependent()) return E; - Optional<llvm::APSInt> I = llvm::APSInt(64); + std::optional<llvm::APSInt> I = llvm::APSInt(64); if (!(I = E->getIntegerConstantExpr(S.Context))) { S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); @@ -5543,9 +5660,10 @@ static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName, const char *IntrinNames) { if (AliasName.startswith("__arm_")) AliasName = AliasName.substr(6); - const IntrinToName *It = std::lower_bound( - Map.begin(), Map.end(), BuiltinID, - [](const IntrinToName &L, unsigned Id) { return L.Id < Id; }); + const IntrinToName *It = + llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) { + return L.Id < Id; + }); if (It == Map.end() || It->Id != BuiltinID) return false; StringRef FullName(&IntrinNames[It->FullName]); @@ -6433,9 +6551,9 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc, } StringRef CurrentParam; - llvm::Optional<unsigned> SelfLocation; + std::optional<unsigned> SelfLocation; unsigned NewValueCount = 0; - llvm::Optional<unsigned> NewValueLocation; + std::optional<unsigned> NewValueLocation; do { std::tie(CurrentParam, Parameters) = Parameters.split(':'); @@ -6813,12 +6931,12 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { using llvm::Triple; Triple Target = S.Context.getTargetInfo().getTriple(); + auto Env = S.Context.getTargetInfo().getTriple().getEnvironment(); if (!llvm::is_contained({Triple::Compute, Triple::Mesh, Triple::Amplification, Triple::Library}, - Target.getEnvironment())) { + Env)) { uint32_t Pipeline = - (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() - - (uint32_t)llvm::Triple::Pixel; + static_cast<uint32_t>(hlsl::getStageFromEnvironment(Env)); S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage) << AL << Pipeline << "Compute, Amplification, Mesh or Library"; return; @@ -6885,8 +7003,35 @@ HLSLNumThreadsAttr *Sema::mergeHLSLNumThreadsAttr(Decl *D, static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) { using llvm::Triple; + auto Env = S.Context.getTargetInfo().getTriple().getEnvironment(); + if (Env != Triple::Compute && Env != Triple::Library) { + // FIXME: it is OK for a compute shader entry and pixel shader entry live in + // same HLSL file. Issue https://github.com/llvm/llvm-project/issues/57880. + ShaderStage Pipeline = hlsl::getStageFromEnvironment(Env); + S.Diag(AL.getLoc(), diag::err_hlsl_attr_unsupported_in_stage) + << AL << (uint32_t)Pipeline << "Compute"; + return; + } + + D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL)); +} + +static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) { + if (!T->hasUnsignedIntegerRepresentation()) + return false; + if (const auto *VT = T->getAs<VectorType>()) + return VT->getNumElements() <= 3; + return true; +} + +static void handleHLSLSV_DispatchThreadIDAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + using llvm::Triple; Triple Target = S.Context.getTargetInfo().getTriple(); - if (Target.getEnvironment() != Triple::Compute) { + // FIXME: it is OK for a compute shader entry and pixel shader entry live in + // same HLSL file.Issue https://github.com/llvm/llvm-project/issues/57880. + if (Target.getEnvironment() != Triple::Compute && + Target.getEnvironment() != Triple::Library) { uint32_t Pipeline = (uint32_t)S.Context.getTargetInfo().getTriple().getEnvironment() - (uint32_t)llvm::Triple::Pixel; @@ -6895,7 +7040,25 @@ static void handleHLSLSVGroupIndexAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - D->addAttr(::new (S.Context) HLSLSV_GroupIndexAttr(S.Context, AL)); + // FIXME: report warning and ignore semantic when cannot apply on the Decl. + // See https://github.com/llvm/llvm-project/issues/57916. + + // FIXME: support semantic on field. + // See https://github.com/llvm/llvm-project/issues/57889. + if (isa<FieldDecl>(D)) { + S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_ast_node) + << AL << "parameter"; + return; + } + + auto *VD = cast<ValueDecl>(D); + if (!isLegalTypeForHLSLSV_DispatchThreadID(VD->getType())) { + S.Diag(AL.getLoc(), diag::err_hlsl_attr_invalid_type) + << AL << "uint/uint2/uint3"; + return; + } + + D->addAttr(::new (S.Context) HLSLSV_DispatchThreadIDAttr(S.Context, AL)); } static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -6905,7 +7068,11 @@ static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; HLSLShaderAttr::ShaderType ShaderType; - if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType)) { + if (!HLSLShaderAttr::ConvertStrToShaderType(Str, ShaderType) || + // Library is added to help convert HLSLShaderAttr::ShaderType to + // llvm::Triple::EnviromentType. It is not a legal + // HLSLShaderAttr::ShaderType. + ShaderType == HLSLShaderAttr::Library) { S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str << ArgLoc; return; @@ -6931,6 +7098,78 @@ Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL, return HLSLShaderAttr::Create(Context, ShaderType, AL); } +static void handleHLSLResourceBindingAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + StringRef Space = "space0"; + StringRef Slot = ""; + + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *Loc = AL.getArgAsIdent(0); + StringRef Str = Loc->Ident->getName(); + SourceLocation ArgLoc = Loc->Loc; + + SourceLocation SpaceArgLoc; + if (AL.getNumArgs() == 2) { + Slot = Str; + if (!AL.isArgIdent(1)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + IdentifierLoc *Loc = AL.getArgAsIdent(1); + Space = Loc->Ident->getName(); + SpaceArgLoc = Loc->Loc; + } else { + Slot = Str; + } + + // Validate. + if (!Slot.empty()) { + switch (Slot[0]) { + case 'u': + case 'b': + case 's': + case 't': + break; + default: + S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_type) + << Slot.substr(0, 1); + return; + } + + StringRef SlotNum = Slot.substr(1); + unsigned Num = 0; + if (SlotNum.getAsInteger(10, Num)) { + S.Diag(ArgLoc, diag::err_hlsl_unsupported_register_number); + return; + } + } + + if (!Space.startswith("space")) { + S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; + return; + } + StringRef SpaceNum = Space.substr(5); + unsigned Num = 0; + if (SpaceNum.getAsInteger(10, Num)) { + S.Diag(SpaceArgLoc, diag::err_hlsl_expected_space) << Space; + return; + } + + // FIXME: check reg type match decl. Issue + // https://github.com/llvm/llvm-project/issues/57886. + HLSLResourceBindingAttr *NewAttr = + HLSLResourceBindingAttr::Create(S.getASTContext(), Slot, Space, AL); + if (NewAttr) + D->addAttr(NewAttr); +} + static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.LangOpts.CPlusPlus) { S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) @@ -7050,7 +7289,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0)); - Optional<llvm::APSInt> NumParams = llvm::APSInt(32); + std::optional<llvm::APSInt> NumParams = llvm::APSInt(32); if (!(NumParams = NumParamsExpr->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_type) << AL << AANT_ArgumentIntegerConstant @@ -7252,7 +7491,7 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD) { // Add preserve_access_index attribute to all fields and inner records. - for (auto D : RD->decls()) { + for (auto *D : RD->decls()) { if (D->hasAttr<BPFPreserveAccessIndexAttr>()) continue; @@ -7874,8 +8113,8 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SanitizerName != "coverage") S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; else if (isGlobalVar(D) && !isSanitizerAttributeAllowedOnGlobals(SanitizerName)) - S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << AL << ExpectedFunctionOrMethod; + S.Diag(D->getLocation(), diag::warn_attribute_type_not_supported_global) + << AL << SanitizerName; Sanitizers.push_back(SanitizerName); } @@ -8458,6 +8697,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_X86ForceAlignArgPointer: handleX86ForceAlignArgPointerAttr(S, D, AL); break; + case ParsedAttr::AT_ReadOnlyPlacement: + handleSimpleAttribute<ReadOnlyPlacementAttr>(S, D, AL); + break; case ParsedAttr::AT_DLLExport: case ParsedAttr::AT_DLLImport: handleDLLAttr(S, D, AL); @@ -8634,6 +8876,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_NoEscape: handleNoEscapeAttr(S, D, AL); break; + case ParsedAttr::AT_MaybeUndef: + handleSimpleAttribute<MaybeUndefAttr>(S, D, AL); + break; case ParsedAttr::AT_AssumeAligned: handleAssumeAlignedAttr(S, D, AL); break; @@ -8761,6 +9006,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_Target: handleTargetAttr(S, D, AL); break; + case ParsedAttr::AT_TargetVersion: + handleTargetVersionAttr(S, D, AL); + break; case ParsedAttr::AT_TargetClones: handleTargetClonesAttr(S, D, AL); break; @@ -8904,9 +9152,15 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_HLSLSV_GroupIndex: handleHLSLSVGroupIndexAttr(S, D, AL); break; + case ParsedAttr::AT_HLSLSV_DispatchThreadID: + handleHLSLSV_DispatchThreadIDAttr(S, D, AL); + break; case ParsedAttr::AT_HLSLShader: handleHLSLShaderAttr(S, D, AL); break; + case ParsedAttr::AT_HLSLResourceBinding: + handleHLSLResourceBindingAttr(S, D, AL); + break; case ParsedAttr::AT_AbiTag: handleAbiTagAttr(S, D, AL); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 221cbd14da97..348092fc62e8 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -17,6 +17,8 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ComparisonCategories.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" @@ -44,6 +46,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include <map> +#include <optional> #include <set> using namespace clang; @@ -86,7 +89,11 @@ bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) { /// determine whether this declaration can be used in the default /// argument expression. bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) { - const NamedDecl *Decl = DRE->getDecl(); + const ValueDecl *Decl = dyn_cast<ValueDecl>(DRE->getDecl()); + + if (!isa<VarDecl, BindingDecl>(Decl)) + return false; + if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) { // C++ [dcl.fct.default]p9: // [...] parameters of a function shall not be used in default @@ -100,7 +107,7 @@ bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) { return S.Diag(DRE->getBeginLoc(), diag::err_param_default_argument_references_param) << Param->getDeclName() << DefaultArg->getSourceRange(); - } else if (const auto *VDecl = dyn_cast<VarDecl>(Decl)) { + } else if (auto *VD = Decl->getPotentiallyDecomposedVarDecl()) { // C++ [dcl.fct.default]p7: // Local variables shall not be used in default argument // expressions. @@ -110,14 +117,14 @@ bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) { // expression in a default argument. // // C++20 [dcl.fct.default]p7 (DR as part of P0588R1, see also CWG 2346): - // Note: A local variable cannot be odr-used (6.3) in a default argument. + // Note: A local variable cannot be odr-used (6.3) in a default + // argument. // - if (VDecl->isLocalVarDecl() && !DRE->isNonOdrUse()) + if (VD->isLocalVarDecl() && !DRE->isNonOdrUse()) return S.Diag(DRE->getBeginLoc(), diag::err_param_default_argument_references_local) - << VDecl->getDeclName() << DefaultArg->getSourceRange(); + << Decl << DefaultArg->getSourceRange(); } - return false; } @@ -147,13 +154,20 @@ bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr( } bool CheckDefaultArgumentVisitor::VisitLambdaExpr(const LambdaExpr *Lambda) { - // C++11 [expr.lambda.prim]p13: - // A lambda-expression appearing in a default argument shall not - // implicitly or explicitly capture any entity. - if (Lambda->capture_begin() == Lambda->capture_end()) - return false; - - return S.Diag(Lambda->getBeginLoc(), diag::err_lambda_capture_default_arg); + // [expr.prim.lambda.capture]p9 + // a lambda-expression appearing in a default argument cannot implicitly or + // explicitly capture any local entity. Such a lambda-expression can still + // have an init-capture if any full-expression in its initializer satisfies + // the constraints of an expression appearing in a default argument. + bool Invalid = false; + for (const LambdaCapture &LC : Lambda->captures()) { + if (!Lambda->isInitCapture(&LC)) + return S.Diag(LC.getLocation(), diag::err_lambda_capture_default_arg); + // Init captures are always VarDecl. + auto *D = cast<VarDecl>(LC.getCapturedVar()); + Invalid |= Visit(D->getInit()); + } + return Invalid; } } // namespace @@ -744,11 +758,16 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // C++17 [dcl.dcl]/8: // The decl-specifier-seq shall contain only the type-specifier auto // and cv-qualifiers. - // C++2a [dcl.dcl]/8: + // C++20 [dcl.dcl]/8: // If decl-specifier-seq contains any decl-specifier other than static, // thread_local, auto, or cv-qualifiers, the program is ill-formed. + // C++2b [dcl.pre]/6: + // Each decl-specifier in the decl-specifier-seq shall be static, + // thread_local, auto (9.2.9.6 [dcl.spec.auto]), or a cv-qualifier. auto &DS = D.getDeclSpec(); { + // Note: While constrained-auto needs to be checked, we do so separately so + // we can emit a better diagnostic. SmallVector<StringRef, 8> BadSpecifiers; SmallVector<SourceLocation, 8> BadSpecifierLocs; SmallVector<StringRef, 8> CPlusPlus20Specifiers; @@ -775,6 +794,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, BadSpecifiers.push_back("inline"); BadSpecifierLocs.push_back(DS.getInlineSpecLoc()); } + if (!BadSpecifiers.empty()) { auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec); Err << (int)BadSpecifiers.size() @@ -835,6 +855,20 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, D.setInvalidType(); } + // Constrained auto is prohibited by [decl.pre]p6, so check that here. + if (DS.isConstrainedAuto()) { + TemplateIdAnnotation *TemplRep = DS.getRepAsTemplateId(); + assert(TemplRep->Kind == TNK_Concept_template && + "No other template kind should be possible for a constrained auto"); + + SourceRange TemplRange{TemplRep->TemplateNameLoc, + TemplRep->RAngleLoc.isValid() + ? TemplRep->RAngleLoc + : TemplRep->TemplateNameLoc}; + Diag(TemplRep->TemplateNameLoc, diag::err_decomp_decl_constraint) + << TemplRange << FixItHint::CreateRemoval(TemplRange); + } + // Build the BindingDecls. SmallVector<BindingDecl*, 8> Bindings; @@ -1229,7 +1263,7 @@ static bool checkTupleLikeDecomposition(Sema &S, if (E.isInvalid()) return true; - E = S.BuildCallExpr(nullptr, E.get(), Loc, None, Loc); + E = S.BuildCallExpr(nullptr, E.get(), Loc, std::nullopt, Loc); } else { // Otherwise, the initializer is get<i-1>(e), where get is looked up // in the associated namespaces. @@ -3084,7 +3118,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) { return; if (MD && !MD->isVirtual()) { - // If we have a non-virtual method, check if if hides a virtual method. + // If we have a non-virtual method, check if it hides a virtual method. // (In that case, it's most likely the method has the wrong type.) SmallVector<CXXMethodDecl *, 8> OverloadedMethods; FindHiddenVirtualMethods(MD, OverloadedMethods); @@ -3776,7 +3810,7 @@ namespace { void CheckInitListExpr(InitListExpr *ILE) { InitFieldIndex.push_back(0); - for (auto Child : ILE->children()) { + for (auto *Child : ILE->children()) { if (InitListExpr *SubList = dyn_cast<InitListExpr>(Child)) { CheckInitListExpr(SubList); } else { @@ -3847,7 +3881,7 @@ namespace { Expr *Callee = E->getCallee(); if (isa<MemberExpr>(Callee)) { HandleValue(Callee, false /*AddressOf*/); - for (auto Arg : E->arguments()) + for (auto *Arg : E->arguments()) Visit(Arg); return; } @@ -3872,7 +3906,7 @@ namespace { return Inherited::VisitCXXOperatorCallExpr(E); Visit(Callee); - for (auto Arg : E->arguments()) + for (auto *Arg : E->arguments()) HandleValue(Arg->IgnoreParenImpCasts(), false /*AddressOf*/); } @@ -4023,6 +4057,21 @@ ExprResult Sema::ActOnRequiresClause(ExprResult ConstraintExpr) { return ConstraintExpr; } +ExprResult Sema::ConvertMemberDefaultInitExpression(FieldDecl *FD, + Expr *InitExpr, + SourceLocation InitLoc) { + InitializedEntity Entity = + InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD); + InitializationKind Kind = + FD->getInClassInitStyle() == ICIS_ListInit + ? InitializationKind::CreateDirectList(InitExpr->getBeginLoc(), + InitExpr->getBeginLoc(), + InitExpr->getEndLoc()) + : InitializationKind::CreateCopy(InitExpr->getBeginLoc(), InitLoc); + InitializationSequence Seq(*this, Entity, Kind, InitExpr); + return Seq.Perform(*this, Entity, Kind, InitExpr); +} + /// This is invoked after parsing an in-class initializer for a /// non-static C++ class member, and after instantiating an in-class initializer /// in a class template. Such actions are deferred until the class is complete. @@ -4049,36 +4098,23 @@ void Sema::ActOnFinishCXXInClassMemberInitializer(Decl *D, return; } - ExprResult Init = InitExpr; - if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { - InitializedEntity Entity = - InitializedEntity::InitializeMemberFromDefaultMemberInitializer(FD); - InitializationKind Kind = - FD->getInClassInitStyle() == ICIS_ListInit - ? InitializationKind::CreateDirectList(InitExpr->getBeginLoc(), - InitExpr->getBeginLoc(), - InitExpr->getEndLoc()) - : InitializationKind::CreateCopy(InitExpr->getBeginLoc(), InitLoc); - InitializationSequence Seq(*this, Entity, Kind, InitExpr); - Init = Seq.Perform(*this, Entity, Kind, InitExpr); + ExprResult Init = CorrectDelayedTyposInExpr(InitExpr, /*InitDecl=*/nullptr, + /*RecoverUncorrectedTypos=*/true); + assert(Init.isUsable() && "Init should at least have a RecoveryExpr"); + if (!FD->getType()->isDependentType() && !Init.get()->isTypeDependent()) { + Init = ConvertMemberDefaultInitExpression(FD, Init.get(), InitLoc); + // C++11 [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + if (!Init.isInvalid()) + Init = ActOnFinishFullExpr(Init.get(), /*DiscarededValue=*/false); if (Init.isInvalid()) { FD->setInvalidDecl(); return; } } - // C++11 [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - Init = ActOnFinishFullExpr(Init.get(), InitLoc, /*DiscardedValue*/ false); - if (Init.isInvalid()) { - FD->setInvalidDecl(); - return; - } - - InitExpr = Init.get(); - - FD->setInClassInitializer(InitExpr); + FD->setInClassInitializer(Init.get()); } /// Find the direct and/or virtual base specifiers that @@ -4308,11 +4344,21 @@ Sema::BuildMemInitializer(Decl *ConstructorD, } if (getLangOpts().MSVCCompat && !getLangOpts().CPlusPlus20) { - auto UnqualifiedBase = R.getAsSingle<ClassTemplateDecl>(); - if (UnqualifiedBase) { - Diag(IdLoc, diag::ext_unqualified_base_class) - << SourceRange(IdLoc, Init->getSourceRange().getEnd()); - BaseType = UnqualifiedBase->getInjectedClassNameSpecialization(); + if (auto UnqualifiedBase = R.getAsSingle<ClassTemplateDecl>()) { + auto *TempSpec = cast<TemplateSpecializationType>( + UnqualifiedBase->getInjectedClassNameSpecialization()); + TemplateName TN = TempSpec->getTemplateName(); + for (auto const &Base : ClassDecl->bases()) { + auto BaseTemplate = + Base.getType()->getAs<TemplateSpecializationType>(); + if (BaseTemplate && Context.hasSameTemplateName( + BaseTemplate->getTemplateName(), TN)) { + Diag(IdLoc, diag::ext_unqualified_base_class) + << SourceRange(IdLoc, Init->getSourceRange().getEnd()); + BaseType = Base.getType(); + break; + } + } } } @@ -4362,17 +4408,13 @@ Sema::BuildMemInitializer(Decl *ConstructorD, } if (BaseType.isNull()) { - BaseType = Context.getTypeDeclType(TyD); + BaseType = getElaboratedType(ETK_None, SS, Context.getTypeDeclType(TyD)); MarkAnyDeclReferenced(TyD->getLocation(), TyD, /*OdrUse=*/false); - if (SS.isSet()) { - BaseType = Context.getElaboratedType(ETK_None, SS.getScopeRep(), - BaseType); - TInfo = Context.CreateTypeSourceInfo(BaseType); - ElaboratedTypeLoc TL = TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>(); - TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc); - TL.setElaboratedKeywordLoc(SourceLocation()); - TL.setQualifierLoc(SS.getWithLocInContext(Context)); - } + TInfo = Context.CreateTypeSourceInfo(BaseType); + ElaboratedTypeLoc TL = TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>(); + TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc); + TL.setElaboratedKeywordLoc(SourceLocation()); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); } } @@ -4468,10 +4510,10 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, MemInitResult Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, CXXRecordDecl *ClassDecl) { - SourceLocation NameLoc = TInfo->getTypeLoc().getLocalSourceRange().getBegin(); + SourceLocation NameLoc = TInfo->getTypeLoc().getSourceRange().getBegin(); if (!LangOpts.CPlusPlus11) return Diag(NameLoc, diag::err_delegating_ctor) - << TInfo->getTypeLoc().getLocalSourceRange(); + << TInfo->getTypeLoc().getSourceRange(); Diag(NameLoc, diag::warn_cxx98_compat_delegating_ctor); bool InitList = true; @@ -4532,12 +4574,11 @@ MemInitResult Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Expr *Init, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc) { - SourceLocation BaseLoc - = BaseTInfo->getTypeLoc().getLocalSourceRange().getBegin(); + SourceLocation BaseLoc = BaseTInfo->getTypeLoc().getBeginLoc(); if (!BaseType->isDependentType() && !BaseType->isRecordType()) return Diag(BaseLoc, diag::err_base_init_does_not_name_class) - << BaseType << BaseTInfo->getTypeLoc().getLocalSourceRange(); + << BaseType << BaseTInfo->getTypeLoc().getSourceRange(); // C++ [class.base.init]p2: // [...] Unless the mem-initializer-id names a nonstatic data @@ -4595,8 +4636,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Dependent = true; else return Diag(BaseLoc, diag::err_not_direct_base_or_virtual) - << BaseType << Context.getTypeDeclType(ClassDecl) - << BaseTInfo->getTypeLoc().getLocalSourceRange(); + << BaseType << Context.getTypeDeclType(ClassDecl) + << BaseTInfo->getTypeLoc().getSourceRange(); } } @@ -4670,10 +4711,10 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, } // Create a static_cast\<T&&>(expr). -static Expr *CastForMoving(Sema &SemaRef, Expr *E, QualType T = QualType()) { - if (T.isNull()) T = E->getType(); - QualType TargetType = SemaRef.BuildReferenceType( - T, /*SpelledAsLValue*/false, SourceLocation(), DeclarationName()); +static Expr *CastForMoving(Sema &SemaRef, Expr *E) { + QualType TargetType = + SemaRef.BuildReferenceType(E->getType(), /*SpelledAsLValue*/ false, + SourceLocation(), DeclarationName()); SourceLocation ExprLoc = E->getBeginLoc(); TypeSourceInfo *TargetLoc = SemaRef.Context.getTrivialTypeSourceInfo( TargetType, ExprLoc); @@ -4709,8 +4750,8 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, case IIK_Default: { InitializationKind InitKind = InitializationKind::CreateDefault(Constructor->getLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None); - BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, None); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, std::nullopt); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt); break; } @@ -4874,9 +4915,9 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind InitKind = InitializationKind::CreateDefault(Loc); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, None); + InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, std::nullopt); ExprResult MemberInit = - InitSeq.Perform(SemaRef, InitEntity, InitKind, None); + InitSeq.Perform(SemaRef, InitEntity, InitKind, std::nullopt); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) @@ -5644,7 +5685,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, continue; CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl); - assert(Dtor && "No dtor found for FieldClassDecl!"); + // Dtor might still be missing, e.g because it's invalid. + if (!Dtor) + continue; CheckDestructorAccess(Field->getLocation(), Dtor, PDiag(diag::err_access_dtor_field) << Field->getDeclName() @@ -5690,7 +5733,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, continue; CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl); - assert(Dtor && "No dtor found for BaseClassDecl!"); + // Dtor might still be missing, e.g because it's invalid. + if (!Dtor) + continue; // FIXME: caret should be on the start of the class name CheckDestructorAccess(Base.getBeginLoc(), Dtor, @@ -5727,7 +5772,9 @@ void Sema::MarkVirtualBaseDestructorsReferenced( continue; CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl); - assert(Dtor && "No dtor found for BaseClassDecl!"); + // Dtor might still be missing, e.g because it's invalid. + if (!Dtor) + continue; if (CheckDestructorAccess( ClassDecl->getLocation(), Dtor, PDiag(diag::err_access_dtor_vbase) @@ -6612,7 +6659,7 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, bool CopyCtorIsTrivial = false, CopyCtorIsTrivialForCall = false; bool DtorIsTrivialForCall = false; - // If a class has at least one non-deleted, trivial copy constructor, it + // If a class has at least one eligible, trivial copy constructor, it // is passed according to the C ABI. Otherwise, it is passed indirectly. // // Note: This permits classes with non-trivial copy or move ctors to be @@ -6627,7 +6674,8 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, } } else { for (const CXXConstructorDecl *CD : D->ctors()) { - if (CD->isCopyConstructor() && !CD->isDeleted()) { + if (CD->isCopyConstructor() && !CD->isDeleted() && + !CD->isIneligibleOrNotSelected()) { if (CD->isTrivial()) CopyCtorIsTrivial = true; if (CD->isTrivialForCall()) @@ -6947,7 +6995,8 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // Define defaulted constexpr virtual functions that override a base class // function right away. // FIXME: We can defer doing this until the vtable is marked as used. - if (M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods()) + if (CSM != CXXInvalid && !M->isDeleted() && M->isDefaulted() && + M->isConstexpr() && M->size_overridden_methods()) DefineDefaultedFunction(*this, M, M->getLocation()); if (!Incomplete) @@ -7178,6 +7227,11 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, bool ConstRHS, CXXConstructorDecl *InheritedCtor = nullptr, Sema::InheritedConstructorInfo *Inherited = nullptr) { + // Suppress duplicate constraint checking here, in case a constraint check + // caused us to decide to do this. Any truely recursive checks will get + // caught during these checks anyway. + Sema::SatisfactionStackResetRAII SSRAII{S}; + // If we're inheriting a constructor, see if we need to call it for this base // class. if (InheritedCtor) { @@ -7274,8 +7328,8 @@ static bool defaultedSpecialMemberIsConstexpr( // class is a constexpr function, and for (const auto &B : ClassDecl->bases()) { const RecordType *BaseType = B.getType()->getAs<RecordType>(); - if (!BaseType) continue; - + if (!BaseType) + continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg, InheritedCtor, Inherited)) @@ -7402,13 +7456,15 @@ void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) { if (DefKind.isSpecialMember() ? CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD), - DefKind.asSpecialMember()) + DefKind.asSpecialMember(), + FD->getDefaultLoc()) : CheckExplicitlyDefaultedComparison(S, FD, DefKind.asComparison())) FD->setInvalidDecl(); } bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, - CXXSpecialMember CSM) { + CXXSpecialMember CSM, + SourceLocation DefaultLoc) { CXXRecordDecl *RD = MD->getParent(); assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid && @@ -7470,6 +7526,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, ReturnType = Type->getReturnType(); QualType DeclType = Context.getTypeDeclType(RD); + DeclType = Context.getElaboratedType(ETK_None, nullptr, DeclType, nullptr); DeclType = Context.getAddrSpaceQualType(DeclType, MD->getMethodQualifiers().getAddressSpace()); QualType ExpectedReturnType = Context.getLValueReferenceType(DeclType); @@ -7544,6 +7601,17 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, // FIXME: This should not apply if the member is deleted. bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM, HasConstParam); + + // C++14 [dcl.constexpr]p6 (CWG DR647/CWG DR1358): + // If the instantiated template specialization of a constexpr function + // template or member function of a class template would fail to satisfy + // the requirements for a constexpr function or constexpr constructor, that + // specialization is still a constexpr function or constexpr constructor, + // even though a call to such a function cannot appear in a constant + // expression. + if (MD->isTemplateInstantiation() && MD->isConstexpr()) + Constexpr = true; + if ((getLangOpts().CPlusPlus20 || (getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD) : isa<CXXConstructorDecl>(MD))) && @@ -7575,10 +7643,8 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, FunctionProtoType::ExtProtoInfo EPI = Type->getExtProtoInfo(); EPI.ExceptionSpec.Type = EST_Unevaluated; EPI.ExceptionSpec.SourceDecl = MD; - MD->setType(Context.getFunctionType(ReturnType, - llvm::makeArrayRef(&ArgType, - ExpectedParams), - EPI)); + MD->setType(Context.getFunctionType( + ReturnType, llvm::ArrayRef(&ArgType, ExpectedParams), EPI)); } } @@ -7589,8 +7655,11 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, Diag(MD->getLocation(), diag::warn_defaulted_method_deleted) << CSM; if (ShouldDeleteForTypeMismatch) { Diag(MD->getLocation(), diag::note_deleted_type_mismatch) << CSM; - } else { - ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/true); + } else if (ShouldDeleteSpecialMember(MD, CSM, nullptr, + /*Diagnose*/ true) && + DefaultLoc.isValid()) { + Diag(DefaultLoc, diag::note_replace_equals_default_to_delete) + << FixItHint::CreateReplacement(DefaultLoc, "delete"); } } if (ShouldDeleteForTypeMismatch && !HadError) { @@ -7848,7 +7917,8 @@ private: OverloadCandidateSet CandidateSet( FD->getLocation(), OverloadCandidateSet::CSK_Operator, OverloadCandidateSet::OperatorRewriteInfo( - OO, /*AllowRewrittenCandidates=*/!SpaceshipCandidates)); + OO, FD->getLocation(), + /*AllowRewrittenCandidates=*/!SpaceshipCandidates)); /// C++2a [class.compare.default]p1 [P2002R0]: /// [...] the defaulted function itself is never a candidate for overload @@ -7987,7 +8057,7 @@ private: "invalid builtin comparison"); if (NeedsDeducing) { - Optional<ComparisonCategoryType> Cat = + std::optional<ComparisonCategoryType> Cat = getComparisonCategoryForBuiltinCmp(T); assert(Cat && "no category for builtin comparison?"); R.Category = *Cat; @@ -8642,10 +8712,11 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // C++2a [class.spaceship]p2 [P2002R0]: // Let R be the declared return type [...]. If R is auto, [...]. Otherwise, // R shall not contain a placeholder type. - if (DCK == DefaultedComparisonKind::ThreeWay && - FD->getDeclaredReturnType()->getContainedDeducedType() && - !Context.hasSameType(FD->getDeclaredReturnType(), - Context.getAutoDeductType())) { + if (QualType RT = FD->getDeclaredReturnType(); + DCK == DefaultedComparisonKind::ThreeWay && + RT->getContainedDeducedType() && + (!Context.hasSameType(RT, Context.getAutoDeductType()) || + RT->getContainedAutoType()->isConstrained())) { Diag(FD->getLocation(), diag::err_defaulted_comparison_deduced_return_type_not_auto) << (int)DCK << FD->getDeclaredReturnType() << Context.AutoDeductTy @@ -8664,10 +8735,8 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, bool First = FD == FD->getCanonicalDecl(); - // If we want to delete the function, then do so; there's nothing else to - // check in that case. - if (Info.Deleted) { - if (!First) { + if (!First) { + if (Info.Deleted) { // C++11 [dcl.fct.def.default]p4: // [For a] user-provided explicitly-defaulted function [...] if such a // function is implicitly defined as deleted, the program is ill-formed. @@ -8681,7 +8750,21 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, .visit(); return true; } + if (isa<CXXRecordDecl>(FD->getLexicalDeclContext())) { + // C++20 [class.compare.default]p1: + // [...] A definition of a comparison operator as defaulted that appears + // in a class shall be the first declaration of that function. + Diag(FD->getLocation(), diag::err_non_first_default_compare_in_class) + << (int)DCK; + Diag(FD->getCanonicalDecl()->getLocation(), + diag::note_previous_declaration); + return true; + } + } + // If we want to delete the function, then do so; there's nothing else to + // check in that case. + if (Info.Deleted) { SetDeclDeleted(FD, FD->getLocation()); if (!inTemplateInstantiation() && !FD->isImplicit()) { Diag(FD->getLocation(), diag::warn_defaulted_comparison_deleted) @@ -8689,6 +8772,9 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, DefaultedComparisonAnalyzer(*this, RD, FD, DCK, DefaultedComparisonAnalyzer::ExplainDeleted) .visit(); + if (FD->getDefaultLoc().isValid()) + Diag(FD->getDefaultLoc(), diag::note_replace_equals_default_to_delete) + << FixItHint::CreateReplacement(FD->getDefaultLoc(), "delete"); } return false; } @@ -10130,10 +10216,12 @@ void Sema::ActOnFinishCXXMemberSpecification( Diag(AL.getLoc(), diag::warn_attribute_after_definition_ignored) << AL; } - ActOnFields(S, RLoc, TagDecl, llvm::makeArrayRef( - // strict aliasing violation! - reinterpret_cast<Decl**>(FieldCollector->getCurFields()), - FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList); + ActOnFields(S, RLoc, TagDecl, + llvm::ArrayRef( + // strict aliasing violation! + reinterpret_cast<Decl **>(FieldCollector->getCurFields()), + FieldCollector->getCurNumFields()), + LBrac, RBrac, AttrList); CheckCompletedCXXClass(S, cast<CXXRecordDecl>(TagDecl)); } @@ -10699,7 +10787,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, EPI.Variadic = false; EPI.TypeQuals = Qualifiers(); EPI.RefQualifier = RQ_None; - return Context.getFunctionType(Context.VoidTy, None, EPI); + return Context.getFunctionType(Context.VoidTy, std::nullopt, EPI); } static void extendLeft(SourceRange &R, SourceRange Before) { @@ -10802,7 +10890,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, PastFunctionChunk = true; break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorChunk::Array: NeedsTypedef = true; extendRight(After, Chunk.getSourceRange()); @@ -10875,7 +10963,8 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, // of the errors above fired) and with the conversion type as the // return type. if (D.isInvalidType()) - R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo()); + R = Context.getFunctionType(ConvType, std::nullopt, + Proto->getExtProtoInfo()); // C++0x explicit conversion operators. if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus20) @@ -11037,6 +11126,7 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, // Check that the return type is written as a specialization of // the template specified as the deduction-guide's name. + // The template name may not be qualified. [temp.deduct.guide] ParsedType TrailingReturnType = Chunk.Fun.getTrailingReturnType(); TypeSourceInfo *TSI = nullptr; QualType RetTy = GetTypeFromParser(TrailingReturnType, &TSI); @@ -11044,13 +11134,17 @@ void Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, bool AcceptableReturnType = false; bool MightInstantiateToSpecialization = false; if (auto RetTST = - TSI->getTypeLoc().getAs<TemplateSpecializationTypeLoc>()) { + TSI->getTypeLoc().getAsAdjusted<TemplateSpecializationTypeLoc>()) { TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName(); bool TemplateMatches = Context.hasSameTemplateName(SpecifiedName, GuidedTemplate); - // FIXME: We should consider other template kinds (using, qualified), - // otherwise we will emit bogus diagnostics. - if (SpecifiedName.getKind() == TemplateName::Template && TemplateMatches) + auto TKind = SpecifiedName.getKind(); + // A Using TemplateName can't actually be valid (either it's qualified, or + // we're in the wrong scope). But we have diagnosed these problems + // already. + bool SimplyWritten = TKind == TemplateName::Template || + TKind == TemplateName::UsingTemplate; + if (SimplyWritten && TemplateMatches) AcceptableReturnType = true; else { // This could still instantiate to the right type, unless we know it @@ -11111,10 +11205,13 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc, /// ActOnStartNamespaceDef - This is called at the start of a namespace /// definition. -Decl *Sema::ActOnStartNamespaceDef( - Scope *NamespcScope, SourceLocation InlineLoc, SourceLocation NamespaceLoc, - SourceLocation IdentLoc, IdentifierInfo *II, SourceLocation LBrace, - const ParsedAttributesView &AttrList, UsingDirectiveDecl *&UD) { +Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, + SourceLocation InlineLoc, + SourceLocation NamespaceLoc, + SourceLocation IdentLoc, IdentifierInfo *II, + SourceLocation LBrace, + const ParsedAttributesView &AttrList, + UsingDirectiveDecl *&UD, bool IsNested) { SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc; // For anonymous namespace, take the location of the left brace. SourceLocation Loc = II ? IdentLoc : LBrace; @@ -11184,8 +11281,8 @@ Decl *Sema::ActOnStartNamespaceDef( &IsInline, PrevNS); } - NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline, - StartLoc, Loc, II, PrevNS); + NamespaceDecl *Namespc = NamespaceDecl::Create( + Context, CurContext, IsInline, StartLoc, Loc, II, PrevNS, IsNested); if (IsInvalid) Namespc->setInvalidDecl(); @@ -11446,12 +11543,11 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind, NamespaceDecl *Sema::getOrCreateStdNamespace() { if (!StdNamespace) { // The "std" namespace has not yet been defined, so build one implicitly. - StdNamespace = NamespaceDecl::Create(Context, - Context.getTranslationUnitDecl(), - /*Inline=*/false, - SourceLocation(), SourceLocation(), - &PP.getIdentifierTable().get("std"), - /*PrevDecl=*/nullptr); + StdNamespace = NamespaceDecl::Create( + Context, Context.getTranslationUnitDecl(), + /*Inline=*/false, SourceLocation(), SourceLocation(), + &PP.getIdentifierTable().get("std"), + /*PrevDecl=*/nullptr, /*Nested=*/false); getStdNamespace()->setImplicit(true); } @@ -11484,7 +11580,7 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) { Ty->getAs<TemplateSpecializationType>()) { Template = dyn_cast_or_null<ClassTemplateDecl>( TST->getTemplateName().getAsTemplateDecl()); - Arguments = TST->getArgs(); + Arguments = TST->template_arguments().begin(); } if (!Template) return false; @@ -11563,7 +11659,9 @@ QualType Sema::BuildStdInitializerList(QualType Element, SourceLocation Loc) { Args.addArgument(TemplateArgumentLoc(TemplateArgument(Element), Context.getTrivialTypeSourceInfo(Element, Loc))); - return Context.getCanonicalType( + return Context.getElaboratedType( + ElaboratedTypeKeyword::ETK_None, + NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()), CheckTemplateIdType(TemplateName(StdInitializerList), Loc, Args)); } @@ -11825,30 +11923,40 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation EnumLoc, - const DeclSpec &DS) { - switch (DS.getTypeSpecType()) { - case DeclSpec::TST_error: - // This will already have been diagnosed + SourceLocation IdentLoc, + IdentifierInfo &II, CXXScopeSpec *SS) { + assert(!SS->isInvalid() && "ScopeSpec is invalid"); + TypeSourceInfo *TSI = nullptr; + QualType EnumTy = GetTypeFromParser( + getTypeName(II, IdentLoc, S, SS, /*isClassName=*/false, + /*HasTrailingDot=*/false, + /*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false, + /*WantNontrivialTypeSourceInfo=*/true), + &TSI); + if (EnumTy.isNull()) { + Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS) + ? diag::err_using_enum_is_dependent + : diag::err_unknown_typename) + << II.getName() + << SourceRange(SS ? SS->getBeginLoc() : IdentLoc, IdentLoc); return nullptr; + } - case DeclSpec::TST_enum: - break; - - case DeclSpec::TST_typename: - Diag(DS.getTypeSpecTypeLoc(), diag::err_using_enum_is_dependent); + auto *Enum = dyn_cast_if_present<EnumDecl>(EnumTy->getAsTagDecl()); + if (!Enum) { + Diag(IdentLoc, diag::err_using_enum_not_enum) << EnumTy; return nullptr; - - default: - llvm_unreachable("unexpected DeclSpec type"); } - // As with enum-decls, we ignore attributes for now. - auto *Enum = cast<EnumDecl>(DS.getRepAsDecl()); if (auto *Def = Enum->getDefinition()) Enum = Def; - auto *UD = BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, - DS.getTypeSpecTypeNameLoc(), Enum); + if (TSI == nullptr) + TSI = Context.getTrivialTypeSourceInfo(EnumTy, IdentLoc); + + auto *UD = + BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, IdentLoc, TSI, Enum); + if (UD) PushOnScopeChains(UD, S, /*AddToContext*/ false); @@ -12540,6 +12648,7 @@ NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation EnumLoc, SourceLocation NameLoc, + TypeSourceInfo *EnumType, EnumDecl *ED) { bool Invalid = false; @@ -12566,7 +12675,7 @@ NamedDecl *Sema::BuildUsingEnumDeclaration(Scope *S, AccessSpecifier AS, Invalid = true; UsingEnumDecl *UD = UsingEnumDecl::Create(Context, CurContext, UsingLoc, - EnumLoc, NameLoc, ED); + EnumLoc, NameLoc, EnumType); UD->setAccess(AS); CurContext->addDecl(UD); @@ -12908,7 +13017,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename, // Salient point: SS doesn't have to name a base class as long as // lookup only finds members from base classes. Therefore we can - // diagnose here only if we can prove that that can't happen, + // diagnose here only if we can prove that can't happen, // i.e. if the class hierarchies provably don't intersect. // TODO: it would be nice if "definitely valid" results were cached @@ -12988,7 +13097,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, Previous.clear(); } - assert(Name.Kind == UnqualifiedIdKind::IK_Identifier && + assert(Name.getKind() == UnqualifiedIdKind::IK_Identifier && "name in alias declaration must be an identifier"); TypeAliasDecl *NewTD = TypeAliasDecl::Create(Context, CurContext, UsingLoc, Name.StartLocation, @@ -13443,7 +13552,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); - setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, None); + setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, std::nullopt); if (getLangOpts().CUDA) inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDefaultConstructor, @@ -13723,7 +13832,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { Destructor->setAccess(AS_public); Destructor->setDefaulted(); - setupImplicitSpecialMemberType(Destructor, Context.VoidTy, None); + setupImplicitSpecialMemberType(Destructor, Context.VoidTy, std::nullopt); if (getLangOpts().CUDA) inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDestructor, @@ -13884,7 +13993,8 @@ void Sema::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) { FunctionProtoType::ExtProtoInfo EPI = DtorType->getExtProtoInfo(); EPI.ExceptionSpec.Type = EST_Unevaluated; EPI.ExceptionSpec.SourceDecl = Destructor; - Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); + Destructor->setType( + Context.getFunctionType(Context.VoidTy, std::nullopt, EPI)); // FIXME: If the destructor has a body that could throw, and the newly created // spec doesn't allow exceptions, we should emit a warning, because this @@ -14332,6 +14442,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { return nullptr; QualType ArgType = Context.getTypeDeclType(ClassDecl); + ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr); LangAS AS = getDefaultCXXMethodAddrSpace(); if (AS != LangAS::Default) ArgType = Context.getAddrSpaceQualType(ArgType, AS); @@ -14410,13 +14521,10 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) { CXXRecordDecl *RD = CopyOp->getParent(); CXXMethodDecl *UserDeclaredOperation = nullptr; - // In Microsoft mode, assignment operations don't affect constructors and - // vice versa. if (RD->hasUserDeclaredDestructor()) { UserDeclaredOperation = RD->getDestructor(); } else if (!isa<CXXConstructorDecl>(CopyOp) && - RD->hasUserDeclaredCopyConstructor() && - !S.getLangOpts().MSVCCompat) { + RD->hasUserDeclaredCopyConstructor()) { // Find any user-declared copy constructor. for (auto *I : RD->ctors()) { if (I->isCopyConstructor()) { @@ -14426,8 +14534,7 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) { } assert(UserDeclaredOperation); } else if (isa<CXXConstructorDecl>(CopyOp) && - RD->hasUserDeclaredCopyAssignment() && - !S.getLangOpts().MSVCCompat) { + RD->hasUserDeclaredCopyAssignment()) { // Find any user-declared move assignment operator. for (auto *I : RD->methods()) { if (I->isCopyAssignmentOperator()) { @@ -14612,7 +14719,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, MemberBuilder From(OtherRef, OtherRefType, /*IsArrow=*/false, MemberLookup); - MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/true, MemberLookup); + MemberBuilder To(This, getCurrentThisType(), /*IsArrow=*/!LangOpts.HLSL, + MemberLookup); // Build the copy of this field. StmtResult Copy = buildSingleCopyAssign(*this, Loc, FieldType, @@ -14630,9 +14738,16 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, if (!Invalid) { // Add a "return *this;" - ExprResult ThisObj = CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc)); + Expr *ThisExpr = nullptr; + if (!LangOpts.HLSL) { + ExprResult ThisObj = + CreateBuiltinUnaryOp(Loc, UO_Deref, This.build(*this, Loc)); + ThisExpr = ThisObj.get(); + } else { + ThisExpr = This.build(*this, Loc); + } - StmtResult Return = BuildReturnStmt(Loc, ThisObj.get()); + StmtResult Return = BuildReturnStmt(Loc, ThisExpr); if (Return.isInvalid()) Invalid = true; else @@ -14670,6 +14785,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { // constructor rules. QualType ArgType = Context.getTypeDeclType(ClassDecl); + ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr); LangAS AS = getDefaultCXXMethodAddrSpace(); if (AS != LangAS::Default) ArgType = Context.getAddrSpaceQualType(ArgType, AS); @@ -15042,6 +15158,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = ClassType; + ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr); bool Const = ClassDecl->implicitCopyConstructorHasConstParam(); if (Const) ArgType = ArgType.withConst(); @@ -15165,7 +15282,8 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, : CopyConstructor->getLocation(); Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody( - ActOnCompoundStmt(Loc, Loc, None, /*isStmtExpr=*/false).getAs<Stmt>()); + ActOnCompoundStmt(Loc, Loc, std::nullopt, /*isStmtExpr=*/false) + .getAs<Stmt>()); CopyConstructor->markUsed(Context); } @@ -15185,6 +15303,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = ClassType; + ArgType = Context.getElaboratedType(ETK_None, nullptr, ArgType, nullptr); LangAS AS = getDefaultCXXMethodAddrSpace(); if (AS != LangAS::Default) ArgType = Context.getAddrSpaceQualType(ClassType, AS); @@ -15290,8 +15409,9 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, ? MoveConstructor->getEndLoc() : MoveConstructor->getLocation(); Sema::CompoundScopeRAII CompoundScope(*this); - MoveConstructor->setBody(ActOnCompoundStmt( - Loc, Loc, None, /*isStmtExpr=*/ false).getAs<Stmt>()); + MoveConstructor->setBody( + ActOnCompoundStmt(Loc, Loc, std::nullopt, /*isStmtExpr=*/false) + .getAs<Stmt>()); MoveConstructor->markUsed(Context); } @@ -15316,7 +15436,8 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( CXXRecordDecl *Lambda = Conv->getParent(); FunctionDecl *CallOp = Lambda->getLambdaCallOperator(); - FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker(CC); + FunctionDecl *Invoker = + CallOp->isStatic() ? CallOp : Lambda->getLambdaStaticInvoker(CC); if (auto *TemplateArgs = Conv->getTemplateSpecializationArgs()) { CallOp = InstantiateFunctionDeclaration( @@ -15324,10 +15445,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( if (!CallOp) return; - Invoker = InstantiateFunctionDeclaration( - Invoker->getDescribedFunctionTemplate(), TemplateArgs, CurrentLocation); - if (!Invoker) - return; + if (CallOp != Invoker) { + Invoker = InstantiateFunctionDeclaration( + Invoker->getDescribedFunctionTemplate(), TemplateArgs, + CurrentLocation); + if (!Invoker) + return; + } } if (CallOp->isInvalidDecl()) @@ -15340,17 +15464,19 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( // to the PendingInstantiations. MarkFunctionReferenced(CurrentLocation, CallOp); - // Fill in the __invoke function with a dummy implementation. IR generation - // will fill in the actual details. Update its type in case it contained - // an 'auto'. - Invoker->markUsed(Context); - Invoker->setReferenced(); - Invoker->setType(Conv->getReturnType()->getPointeeType()); - Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation())); + if (Invoker != CallOp) { + // Fill in the __invoke function with a dummy implementation. IR generation + // will fill in the actual details. Update its type in case it contained + // an 'auto'. + Invoker->markUsed(Context); + Invoker->setReferenced(); + Invoker->setType(Conv->getReturnType()->getPointeeType()); + Invoker->setBody(new (Context) CompoundStmt(Conv->getLocation())); + } // Construct the body of the conversion function { return __invoke; }. - Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(), - VK_LValue, Conv->getLocation()); + Expr *FunctionRef = BuildDeclRefExpr(Invoker, Invoker->getType(), VK_LValue, + Conv->getLocation()); assert(FunctionRef && "Can't refer to __invoke function?"); Stmt *Return = BuildReturnStmt(Conv->getLocation(), FunctionRef).get(); Conv->setBody(CompoundStmt::Create(Context, Return, FPOptionsOverride(), @@ -15360,16 +15486,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Conv); - L->CompletedImplicitDefinition(Invoker); + if (Invoker != CallOp) + L->CompletedImplicitDefinition(Invoker); } } - - void Sema::DefineImplicitLambdaToBlockPointerConversion( - SourceLocation CurrentLocation, - CXXConversionDecl *Conv) -{ + SourceLocation CurrentLocation, CXXConversionDecl *Conv) { assert(!Conv->getParent()->isGenericLambda()); SynthesizedFunctionScope Scope(*this, Conv); @@ -15429,7 +15552,7 @@ static bool hasOneRealArgument(MultiExprArg Args) { if (!Args[1]->isDefaultArgument()) return false; - LLVM_FALLTHROUGH; + [[fallthrough]]; case 1: return !Args[0]->isDefaultArgument(); } @@ -15498,7 +15621,10 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, SourceRange ParenRange) { if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) { Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow); - if (DiagnoseUseOfDecl(Constructor, ConstructLoc)) + // The only way to get here is if we did overlaod resolution to find the + // shadow decl, so we don't need to worry about re-checking the trailing + // requires clause. + if (DiagnoseUseOfOverloadedDecl(Constructor, ConstructLoc)) return ExprError(); } @@ -15542,70 +15668,6 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, Constructor); } -ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { - assert(Field->hasInClassInitializer()); - - // If we already have the in-class initializer nothing needs to be done. - if (Field->getInClassInitializer()) - return CXXDefaultInitExpr::Create(Context, Loc, Field, CurContext); - - // If we might have already tried and failed to instantiate, don't try again. - if (Field->isInvalidDecl()) - return ExprError(); - - // Maybe we haven't instantiated the in-class initializer. Go check the - // pattern FieldDecl to see if it has one. - CXXRecordDecl *ParentRD = cast<CXXRecordDecl>(Field->getParent()); - - if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) { - CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern(); - DeclContext::lookup_result Lookup = - ClassPattern->lookup(Field->getDeclName()); - - FieldDecl *Pattern = nullptr; - for (auto L : Lookup) { - if (isa<FieldDecl>(L)) { - Pattern = cast<FieldDecl>(L); - break; - } - } - assert(Pattern && "We must have set the Pattern!"); - - if (!Pattern->hasInClassInitializer() || - InstantiateInClassInitializer(Loc, Field, Pattern, - getTemplateInstantiationArgs(Field))) { - // Don't diagnose this again. - Field->setInvalidDecl(); - return ExprError(); - } - return CXXDefaultInitExpr::Create(Context, Loc, Field, CurContext); - } - - // DR1351: - // If the brace-or-equal-initializer of a non-static data member - // invokes a defaulted default constructor of its class or of an - // enclosing class in a potentially evaluated subexpression, the - // program is ill-formed. - // - // This resolution is unworkable: the exception specification of the - // default constructor can be needed in an unevaluated context, in - // particular, in the operand of a noexcept-expression, and we can be - // unable to compute an exception specification for an enclosed class. - // - // Any attempt to resolve the exception specification of a defaulted default - // constructor before the initializer is lexically complete will ultimately - // come here at which point we can diagnose it. - RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext(); - Diag(Loc, diag::err_default_member_initializer_not_yet_parsed) - << OutermostClass << Field; - Diag(Field->getEndLoc(), - diag::note_default_member_initializer_not_yet_parsed); - // Recover by marking the field invalid, unless we're in a SFINAE context. - if (!isSFINAEContext()) - Field->setInvalidDecl(); - return ExprError(); -} - void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { if (VD->isInvalidDecl()) return; // If initializing the variable failed, don't also diagnose problems with @@ -15690,19 +15752,16 @@ bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, VariadicCallType CallType = Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; SmallVector<Expr *, 8> AllArgs; - bool Invalid = GatherArgumentsForCall(Loc, Constructor, - Proto, 0, - llvm::makeArrayRef(Args, NumArgs), - AllArgs, - CallType, AllowExplicit, - IsListInitialization); + bool Invalid = GatherArgumentsForCall( + Loc, Constructor, Proto, 0, llvm::ArrayRef(Args, NumArgs), AllArgs, + CallType, AllowExplicit, IsListInitialization); ConvertedArgs.append(AllArgs.begin(), AllArgs.end()); DiagnoseSentinelCalls(Constructor, Loc, AllArgs); CheckConstructorCall(Constructor, DeclInitType, - llvm::makeArrayRef(AllArgs.data(), AllArgs.size()), - Proto, Loc); + llvm::ArrayRef(AllArgs.data(), AllArgs.size()), Proto, + Loc); return Invalid; } @@ -15901,18 +15960,28 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { if (Op == OO_New || Op == OO_Array_New) return CheckOperatorNewDeclaration(*this, FnDecl); - // C++ [over.oper]p6: - // An operator function shall either be a non-static member - // function or be a non-member function and have at least one - // parameter whose type is a class, a reference to a class, an - // enumeration, or a reference to an enumeration. + // C++ [over.oper]p7: + // An operator function shall either be a member function or + // be a non-member function and have at least one parameter + // whose type is a class, a reference to a class, an enumeration, + // or a reference to an enumeration. + // Note: Before C++23, a member function could not be static. The only member + // function allowed to be static is the call operator function. if (CXXMethodDecl *MethodDecl = dyn_cast<CXXMethodDecl>(FnDecl)) { - if (MethodDecl->isStatic()) - return Diag(FnDecl->getLocation(), - diag::err_operator_overload_static) << FnDecl->getDeclName(); + if (MethodDecl->isStatic()) { + if (Op == OO_Call || Op == OO_Subscript) + Diag(FnDecl->getLocation(), + (LangOpts.CPlusPlus2b + ? diag::warn_cxx20_compat_operator_overload_static + : diag::ext_operator_overload_static)) + << FnDecl; + else + return Diag(FnDecl->getLocation(), diag::err_operator_overload_static) + << FnDecl; + } } else { bool ClassOrEnumParam = false; - for (auto Param : FnDecl->parameters()) { + for (auto *Param : FnDecl->parameters()) { QualType ParamType = Param->getType().getNonReferenceType(); if (ParamType->isDependentType() || ParamType->isRecordType() || ParamType->isEnumeralType()) { @@ -15935,7 +16004,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // operator (CWG2507) allow default arguments. if (Op != OO_Call) { ParmVarDecl *FirstDefaultedParam = nullptr; - for (auto Param : FnDecl->parameters()) { + for (auto *Param : FnDecl->parameters()) { if (Param->hasDefaultArg()) { FirstDefaultedParam = Param; break; @@ -16008,7 +16077,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { << FnDecl->getDeclName(); } - // Some operators must be non-static member functions. + // Some operators must be member functions. if (MustBeMemberOperator && !isa<CXXMethodDecl>(FnDecl)) { return Diag(FnDecl->getLocation(), diag::err_operator_overload_must_be_member) @@ -16241,7 +16310,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { // A parameter-declaration-clause containing a default argument is not // equivalent to any of the permitted forms. - for (auto Param : FnDecl->parameters()) { + for (auto *Param : FnDecl->parameters()) { if (Param->hasDefaultArg()) { Diag(Param->getDefaultArgRange().getBegin(), diag::err_literal_operator_default_argument) @@ -16559,6 +16628,137 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, AssertMessage, RParenLoc, false); } +/// Convert \V to a string we can present to the user in a diagnostic +/// \T is the type of the expression that has been evaluated into \V +static bool ConvertAPValueToString(const APValue &V, QualType T, + SmallVectorImpl<char> &Str) { + if (!V.hasValue()) + return false; + + switch (V.getKind()) { + case APValue::ValueKind::Int: + if (T->isBooleanType()) { + // Bools are reduced to ints during evaluation, but for + // diagnostic purposes we want to print them as + // true or false. + int64_t BoolValue = V.getInt().getExtValue(); + assert((BoolValue == 0 || BoolValue == 1) && + "Bool type, but value is not 0 or 1"); + llvm::raw_svector_ostream OS(Str); + OS << (BoolValue ? "true" : "false"); + } else if (T->isCharType()) { + // Same is true for chars. + Str.push_back('\''); + Str.push_back(V.getInt().getExtValue()); + Str.push_back('\''); + } else + V.getInt().toString(Str); + + break; + + case APValue::ValueKind::Float: + V.getFloat().toString(Str); + break; + + case APValue::ValueKind::LValue: + if (V.isNullPointer()) { + llvm::raw_svector_ostream OS(Str); + OS << "nullptr"; + } else + return false; + break; + + case APValue::ValueKind::ComplexFloat: { + llvm::raw_svector_ostream OS(Str); + OS << '('; + V.getComplexFloatReal().toString(Str); + OS << " + "; + V.getComplexFloatImag().toString(Str); + OS << "i)"; + } break; + + case APValue::ValueKind::ComplexInt: { + llvm::raw_svector_ostream OS(Str); + OS << '('; + V.getComplexIntReal().toString(Str); + OS << " + "; + V.getComplexIntImag().toString(Str); + OS << "i)"; + } break; + + default: + return false; + } + + return true; +} + +/// Some Expression types are not useful to print notes about, +/// e.g. literals and values that have already been expanded +/// before such as int-valued template parameters. +static bool UsefulToPrintExpr(const Expr *E) { + E = E->IgnoreParenImpCasts(); + // Literals are pretty easy for humans to understand. + if (isa<IntegerLiteral, FloatingLiteral, CharacterLiteral, CXXBoolLiteralExpr, + CXXNullPtrLiteralExpr, FixedPointLiteral, ImaginaryLiteral>(E)) + return false; + + // These have been substituted from template parameters + // and appear as literals in the static assert error. + if (isa<SubstNonTypeTemplateParmExpr>(E)) + return false; + + // -5 is also simple to understand. + if (const auto *UnaryOp = dyn_cast<UnaryOperator>(E)) + return UsefulToPrintExpr(UnaryOp->getSubExpr()); + + // Ignore nested binary operators. This could be a FIXME for improvements + // to the diagnostics in the future. + if (isa<BinaryOperator>(E)) + return false; + + return true; +} + +/// Try to print more useful information about a failed static_assert +/// with expression \E +void Sema::DiagnoseStaticAssertDetails(const Expr *E) { + if (const auto *Op = dyn_cast<BinaryOperator>(E)) { + const Expr *LHS = Op->getLHS()->IgnoreParenImpCasts(); + const Expr *RHS = Op->getRHS()->IgnoreParenImpCasts(); + + // Ignore comparisons of boolean expressions with a boolean literal. + if ((isa<CXXBoolLiteralExpr>(LHS) && RHS->getType()->isBooleanType()) || + (isa<CXXBoolLiteralExpr>(RHS) && LHS->getType()->isBooleanType())) + return; + + // Don't print obvious expressions. + if (!UsefulToPrintExpr(LHS) && !UsefulToPrintExpr(RHS)) + return; + + struct { + const clang::Expr *Cond; + Expr::EvalResult Result; + SmallString<12> ValueString; + bool Print; + } DiagSide[2] = {{LHS, Expr::EvalResult(), {}, false}, + {RHS, Expr::EvalResult(), {}, false}}; + for (unsigned I = 0; I < 2; I++) { + const Expr *Side = DiagSide[I].Cond; + + Side->EvaluateAsRValue(DiagSide[I].Result, Context, true); + + DiagSide[I].Print = ConvertAPValueToString( + DiagSide[I].Result.Val, Side->getType(), DiagSide[I].ValueString); + } + if (DiagSide[0].Print && DiagSide[1].Print) { + Diag(Op->getExprLoc(), diag::note_expr_evaluates_to) + << DiagSide[0].ValueString << Op->getOpcodeStr() + << DiagSide[1].ValueString << Op->getSourceRange(); + } + } +} + Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, StringLiteral *AssertMessage, @@ -16583,10 +16783,20 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, AssertExpr = FullAssertExpr.get(); llvm::APSInt Cond; + Expr *BaseExpr = AssertExpr; + AllowFoldKind FoldKind = NoFold; + + if (!getLangOpts().CPlusPlus) { + // In C mode, allow folding as an extension for better compatibility with + // C++ in terms of expressions like static_assert("test") or + // static_assert(nullptr). + FoldKind = AllowFold; + } + if (!Failed && VerifyIntegerConstantExpression( - AssertExpr, &Cond, - diag::err_static_assert_expression_is_not_constant) - .isInvalid()) + BaseExpr, &Cond, + diag::err_static_assert_expression_is_not_constant, + FoldKind).isInvalid()) Failed = true; if (!Failed && !Cond) { @@ -16617,6 +16827,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed) << InnerCondDescription << !AssertMessage << Msg.str() << InnerCond->getSourceRange(); + DiagnoseStaticAssertDetails(InnerCond); } else { Diag(StaticAssertLoc, diag::err_static_assert_failed) << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); @@ -16650,7 +16861,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); QualType T = TSInfo->getType(); - SourceRange TypeRange = TSInfo->getTypeLoc().getLocalSourceRange(); + SourceRange TypeRange = TSInfo->getTypeLoc().getSourceRange(); // C++03 [class.friend]p2: // An elaborated-type-specifier shall be used in a friend declaration @@ -16716,12 +16927,10 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, /// Handle a friend tag declaration where the scope specifier was /// templated. -Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, - unsigned TagSpec, SourceLocation TagLoc, - CXXScopeSpec &SS, IdentifierInfo *Name, - SourceLocation NameLoc, - const ParsedAttributesView &Attr, - MultiTemplateParamsArg TempParamLists) { +DeclResult Sema::ActOnTemplatedFriendTag( + Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, + const ParsedAttributesView &Attr, MultiTemplateParamsArg TempParamLists) { TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); bool IsMemberSpecialization = false; @@ -16734,7 +16943,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, if (TemplateParams->size() > 0) { // This is a declaration of a class template. if (Invalid) - return nullptr; + return true; return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, TemplateParams, AS_public, @@ -16749,7 +16958,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, } } - if (Invalid) return nullptr; + if (Invalid) return true; bool isAllExplicitSpecializations = true; for (unsigned I = TempParamLists.size(); I-- > 0; ) { @@ -16768,15 +16977,16 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, if (SS.isEmpty()) { bool Owned = false; bool IsDependent = false; - return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, - Attr, AS_public, + UsingShadowDecl* FoundUsing = nullptr; + return ActOnTag(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, + AS_public, /*ModulePrivateLoc=*/SourceLocation(), MultiTemplateParamsArg(), Owned, IsDependent, /*ScopedEnumKWLoc=*/SourceLocation(), /*ScopedEnumUsesClassTag=*/false, /*UnderlyingType=*/TypeResult(), /*IsTypeSpecifier=*/false, - /*IsTemplateParamOrArg=*/false); + /*IsTemplateParamOrArg=*/false, /*OOK=*/OOK_Outside, FoundUsing); } NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); @@ -16785,7 +16995,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, QualType T = CheckTypenameType(Keyword, TagLoc, QualifierLoc, *Name, NameLoc); if (T.isNull()) - return nullptr; + return true; TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); if (isa<DependentNameType>(T)) { @@ -17353,6 +17563,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { FD->setDefaulted(); FD->setExplicitlyDefaulted(); + FD->setDefaultLoc(DefaultLoc); // Defer checking functions that are defaulted in a dependent context. if (FD->isDependentContext()) @@ -17392,7 +17603,8 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { } else { auto *MD = cast<CXXMethodDecl>(FD); - if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember())) + if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember(), + DefaultLoc)) MD->setInvalidDecl(); else DefineDefaultedFunction(*this, MD, DefaultLoc); @@ -17817,7 +18029,7 @@ bool Sema::DefineUsedVTables() { // definition. bool IsExplicitInstantiationDeclaration = ClassTSK == TSK_ExplicitInstantiationDeclaration; - for (auto R : Class->redecls()) { + for (auto *R : Class->redecls()) { TemplateSpecializationKind TSK = cast<CXXRecordDecl>(R)->getTemplateSpecializationKind(); if (TSK == TSK_ExplicitInstantiationDeclaration) @@ -17929,9 +18141,9 @@ void Sema::SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation) { InitializationKind InitKind = InitializationKind::CreateDefault(ObjCImplementation->getLocation()); - InitializationSequence InitSeq(*this, InitEntity, InitKind, None); + InitializationSequence InitSeq(*this, InitEntity, InitKind, std::nullopt); ExprResult MemberInit = - InitSeq.Perform(*this, InitEntity, InitKind, None); + InitSeq.Perform(*this, InitEntity, InitKind, std::nullopt); MemberInit = MaybeCreateExprWithCleanups(MemberInit); // Note, MemberInit could actually come back empty if no initialization // is required (e.g., because it would call a trivial default constructor) @@ -18032,8 +18244,8 @@ void Sema::CheckDelegatingCtorCycles() { llvm::SmallPtrSet<CXXConstructorDecl*, 4> Valid, Invalid, Current; for (DelegatingCtorDeclsType::iterator - I = DelegatingCtorDecls.begin(ExternalSource), - E = DelegatingCtorDecls.end(); + I = DelegatingCtorDecls.begin(ExternalSource.get()), + E = DelegatingCtorDecls.end(); I != E; ++I) DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); @@ -18123,7 +18335,7 @@ bool Sema::checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method) { case EST_NoexceptTrue: if (!Finder.TraverseStmt(Proto->getNoexceptExpr())) return true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case EST_Dynamic: for (const auto &E : Proto->exceptions()) { @@ -18149,27 +18361,27 @@ bool Sema::checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method) { else if (const auto *G = dyn_cast<PtGuardedByAttr>(A)) Arg = G->getArg(); else if (const auto *AA = dyn_cast<AcquiredAfterAttr>(A)) - Args = llvm::makeArrayRef(AA->args_begin(), AA->args_size()); + Args = llvm::ArrayRef(AA->args_begin(), AA->args_size()); else if (const auto *AB = dyn_cast<AcquiredBeforeAttr>(A)) - Args = llvm::makeArrayRef(AB->args_begin(), AB->args_size()); + Args = llvm::ArrayRef(AB->args_begin(), AB->args_size()); else if (const auto *ETLF = dyn_cast<ExclusiveTrylockFunctionAttr>(A)) { Arg = ETLF->getSuccessValue(); - Args = llvm::makeArrayRef(ETLF->args_begin(), ETLF->args_size()); + Args = llvm::ArrayRef(ETLF->args_begin(), ETLF->args_size()); } else if (const auto *STLF = dyn_cast<SharedTrylockFunctionAttr>(A)) { Arg = STLF->getSuccessValue(); - Args = llvm::makeArrayRef(STLF->args_begin(), STLF->args_size()); + Args = llvm::ArrayRef(STLF->args_begin(), STLF->args_size()); } else if (const auto *LR = dyn_cast<LockReturnedAttr>(A)) Arg = LR->getArg(); else if (const auto *LE = dyn_cast<LocksExcludedAttr>(A)) - Args = llvm::makeArrayRef(LE->args_begin(), LE->args_size()); + Args = llvm::ArrayRef(LE->args_begin(), LE->args_size()); else if (const auto *RC = dyn_cast<RequiresCapabilityAttr>(A)) - Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size()); + Args = llvm::ArrayRef(RC->args_begin(), RC->args_size()); else if (const auto *AC = dyn_cast<AcquireCapabilityAttr>(A)) - Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size()); + Args = llvm::ArrayRef(AC->args_begin(), AC->args_size()); else if (const auto *AC = dyn_cast<TryAcquireCapabilityAttr>(A)) - Args = llvm::makeArrayRef(AC->args_begin(), AC->args_size()); + Args = llvm::ArrayRef(AC->args_begin(), AC->args_size()); else if (const auto *RC = dyn_cast<ReleaseCapabilityAttr>(A)) - Args = llvm::makeArrayRef(RC->args_begin(), RC->args_size()); + Args = llvm::ArrayRef(RC->args_begin(), RC->args_size()); if (Arg && !Finder.TraverseStmt(Arg)) return true; diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index a574a5539330..fdfc6d312b38 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -782,7 +782,7 @@ ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S, // scope until later (after the instance variable block), but we want the // diagnostics to occur right after we parse the type parameter list. llvm::SmallDenseMap<IdentifierInfo *, ObjCTypeParamDecl *> knownParams; - for (auto typeParam : typeParams) { + for (auto *typeParam : typeParams) { auto known = knownParams.find(typeParam->getIdentifier()); if (known != knownParams.end()) { Diag(typeParam->getLocation(), diag::err_objc_type_param_redecl) @@ -803,7 +803,7 @@ ObjCTypeParamList *Sema::actOnObjCTypeParamList(Scope *S, } void Sema::popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList) { - for (auto typeParam : *typeParamList) { + for (auto *typeParam : *typeParamList) { if (!typeParam->isInvalidDecl()) { S->RemoveDecl(typeParam); IdResolver.RemoveDecl(typeParam); @@ -978,7 +978,7 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface( ArrayRef<ParsedType> SuperTypeArgs, SourceRange SuperTypeArgsRange, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, - const ParsedAttributesView &AttrList) { + const ParsedAttributesView &AttrList, SkipBodyInfo *SkipBody) { assert(ClassName && "Missing class identifier"); // Check for another declaration kind with the same name. @@ -1029,7 +1029,7 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface( // Clone the type parameter list. SmallVector<ObjCTypeParamDecl *, 4> clonedTypeParams; - for (auto typeParam : *prevTypeParamList) { + for (auto *typeParam : *prevTypeParamList) { clonedTypeParams.push_back( ObjCTypeParamDecl::Create( Context, @@ -1057,10 +1057,16 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface( if (PrevIDecl) { // Class already seen. Was it a definition? if (ObjCInterfaceDecl *Def = PrevIDecl->getDefinition()) { - Diag(AtInterfaceLoc, diag::err_duplicate_class_def) - << PrevIDecl->getDeclName(); - Diag(Def->getLocation(), diag::note_previous_definition); - IDecl->setInvalidDecl(); + if (SkipBody && !hasVisibleDefinition(Def)) { + SkipBody->CheckSameAsPrevious = true; + SkipBody->New = IDecl; + SkipBody->Previous = Def; + } else { + Diag(AtInterfaceLoc, diag::err_duplicate_class_def) + << PrevIDecl->getDeclName(); + Diag(Def->getLocation(), diag::note_previous_definition); + IDecl->setInvalidDecl(); + } } } @@ -1075,7 +1081,9 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface( // Start the definition of this class. If we're in a redefinition case, there // may already be a definition, so we'll end up adding to it. - if (!IDecl->hasDefinition()) + if (SkipBody && SkipBody->CheckSameAsPrevious) + IDecl->startDuplicateDefinitionForComparison(); + else if (!IDecl->hasDefinition()) IDecl->startDefinition(); if (SuperName) { @@ -1213,7 +1221,7 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface( SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, - const ParsedAttributesView &AttrList) { + const ParsedAttributesView &AttrList, SkipBodyInfo *SkipBody) { bool err = false; // FIXME: Deal with AttrList. assert(ProtocolName && "Missing protocol identifier"); @@ -1221,23 +1229,29 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface( forRedeclarationInCurContext()); ObjCProtocolDecl *PDecl = nullptr; if (ObjCProtocolDecl *Def = PrevDecl? PrevDecl->getDefinition() : nullptr) { - // If we already have a definition, complain. - Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName; - Diag(Def->getLocation(), diag::note_previous_definition); - // Create a new protocol that is completely distinct from previous // declarations, and do not make this protocol available for name lookup. // That way, we'll end up completely ignoring the duplicate. // FIXME: Can we turn this into an error? PDecl = ObjCProtocolDecl::Create(Context, CurContext, ProtocolName, ProtocolLoc, AtProtoInterfaceLoc, - /*PrevDecl=*/nullptr); + /*PrevDecl=*/Def); + + if (SkipBody && !hasVisibleDefinition(Def)) { + SkipBody->CheckSameAsPrevious = true; + SkipBody->New = PDecl; + SkipBody->Previous = Def; + } else { + // If we already have a definition, complain. + Diag(ProtocolLoc, diag::warn_duplicate_protocol_def) << ProtocolName; + Diag(Def->getLocation(), diag::note_previous_definition); + } // If we are using modules, add the decl to the context in order to // serialize something meaningful. if (getLangOpts().Modules) PushOnScopeChains(PDecl, TUScope); - PDecl->startDefinition(); + PDecl->startDuplicateDefinitionForComparison(); } else { if (PrevDecl) { // Check for circular dependencies among protocol declarations. This can @@ -1502,7 +1516,7 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers( llvm::SmallPtrSet<ObjCProtocolDecl*, 8> knownProtocols; Context.CollectInheritedProtocols(baseClass, knownProtocols); bool allProtocolsDeclared = true; - for (auto proto : protocols) { + for (auto *proto : protocols) { if (knownProtocols.count(static_cast<ObjCProtocolDecl *>(proto)) == 0) { allProtocolsDeclared = false; break; @@ -2355,21 +2369,17 @@ static bool CheckMethodOverrideReturn(Sema &S, !S.Context.hasSameNullabilityTypeQualifier(MethodImpl->getReturnType(), MethodDecl->getReturnType(), false)) { - auto nullabilityMethodImpl = - *MethodImpl->getReturnType()->getNullability(S.Context); - auto nullabilityMethodDecl = - *MethodDecl->getReturnType()->getNullability(S.Context); - S.Diag(MethodImpl->getLocation(), - diag::warn_conflicting_nullability_attr_overriding_ret_types) - << DiagNullabilityKind( - nullabilityMethodImpl, - ((MethodImpl->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) - != 0)) - << DiagNullabilityKind( - nullabilityMethodDecl, - ((MethodDecl->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) - != 0)); - S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration); + auto nullabilityMethodImpl = *MethodImpl->getReturnType()->getNullability(); + auto nullabilityMethodDecl = *MethodDecl->getReturnType()->getNullability(); + S.Diag(MethodImpl->getLocation(), + diag::warn_conflicting_nullability_attr_overriding_ret_types) + << DiagNullabilityKind(nullabilityMethodImpl, + ((MethodImpl->getObjCDeclQualifier() & + Decl::OBJC_TQ_CSNullability) != 0)) + << DiagNullabilityKind(nullabilityMethodDecl, + ((MethodDecl->getObjCDeclQualifier() & + Decl::OBJC_TQ_CSNullability) != 0)); + S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration); } if (S.Context.hasSameUnqualifiedType(MethodImpl->getReturnType(), @@ -2447,14 +2457,12 @@ static bool CheckMethodOverrideParam(Sema &S, !S.Context.hasSameNullabilityTypeQualifier(ImplTy, IfaceTy, true)) { S.Diag(ImplVar->getLocation(), diag::warn_conflicting_nullability_attr_overriding_param_types) - << DiagNullabilityKind( - *ImplTy->getNullability(S.Context), - ((ImplVar->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) - != 0)) - << DiagNullabilityKind( - *IfaceTy->getNullability(S.Context), - ((IfaceVar->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) - != 0)); + << DiagNullabilityKind(*ImplTy->getNullability(), + ((ImplVar->getObjCDeclQualifier() & + Decl::OBJC_TQ_CSNullability) != 0)) + << DiagNullabilityKind(*IfaceTy->getNullability(), + ((IfaceVar->getObjCDeclQualifier() & + Decl::OBJC_TQ_CSNullability) != 0)); S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration); } if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy)) @@ -3754,7 +3762,7 @@ Sema::SelectorsForTypoCorrection(Selector Sel, /// DiagnoseDuplicateIvars - /// Check for duplicate ivars in the entire class at the start of -/// \@implementation. This becomes necesssary because class extension can +/// \@implementation. This becomes necessary because class extension can /// add ivars to a class in random order which will not be known until /// class's \@implementation is seen. void Sema::DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, @@ -3855,7 +3863,7 @@ static void DiagnoseVariableSizedIvars(Sema &S, ObjCContainerDecl *OCD) { // Check if variable sized ivar is in interface and visible to subclasses. if (!isa<ObjCInterfaceDecl>(OCD)) { - for (auto ivar : Ivars) { + for (auto *ivar : Ivars) { if (!ivar->isInvalidDecl() && IsVariableSizedType(ivar->getType())) { S.Diag(ivar->getLocation(), diag::warn_variable_sized_ivar_visibility) << ivar->getDeclName() << ivar->getType(); @@ -3990,7 +3998,7 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, // they are overridden by an explicit method that is encountered // later. if (auto *OID = dyn_cast<ObjCImplementationDecl>(CurContext)) { - for (auto PropImpl : OID->property_impls()) { + for (auto *PropImpl : OID->property_impls()) { if (auto *Getter = PropImpl->getGetterMethodDecl()) if (Getter->isSynthesizedAccessorStub()) OID->addDecl(Getter); @@ -4432,6 +4440,11 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, ResultTypeCompatibilityKind RTC) { if (!ObjCMethod) return; + auto IsMethodInCurrentClass = [CurrentClass](const ObjCMethodDecl *M) { + // Checking canonical decl works across modules. + return M->getClassInterface()->getCanonicalDecl() == + CurrentClass->getCanonicalDecl(); + }; // Search for overridden methods and merge information down from them. OverrideSearch overrides(*this, ObjCMethod); // Keep track if the method overrides any method in the class's base classes, @@ -4443,8 +4456,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, for (ObjCMethodDecl *overridden : overrides) { if (!hasOverriddenMethodsInBaseOrProtocol) { if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) || - CurrentClass != overridden->getClassInterface() || - overridden->isOverriding()) { + !IsMethodInCurrentClass(overridden) || overridden->isOverriding()) { CheckObjCMethodDirectOverrides(ObjCMethod, overridden); hasOverriddenMethodsInBaseOrProtocol = true; } else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) { @@ -4469,7 +4481,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, OverrideSearch overrides(*this, overridden); for (ObjCMethodDecl *SuperOverridden : overrides) { if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) || - CurrentClass != SuperOverridden->getClassInterface()) { + !IsMethodInCurrentClass(SuperOverridden)) { CheckObjCMethodDirectOverrides(ObjCMethod, SuperOverridden); hasOverriddenMethodsInBaseOrProtocol = true; overridden->setOverriding(true); @@ -4533,8 +4545,8 @@ static QualType mergeTypeNullabilityForRedecl(Sema &S, SourceLocation loc, QualType prevType, bool prevUsesCSKeyword) { // Determine the nullability of both types. - auto nullability = type->getNullability(S.Context); - auto prevNullability = prevType->getNullability(S.Context); + auto nullability = type->getNullability(); + auto prevNullability = prevType->getNullability(); // Easy case: both have nullability. if (nullability.has_value() == prevNullability.has_value()) { diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index d8344cfd01f9..a5a57c38bb48 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -21,6 +21,7 @@ #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include <optional> namespace clang { @@ -1289,6 +1290,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::StmtExprClass: case Expr::ConvertVectorExprClass: case Expr::VAArgExprClass: + case Expr::CXXParenListInitExprClass: return canSubStmtsThrow(*this, S); case Expr::CompoundLiteralExprClass: @@ -1494,6 +1496,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::OMPTaskLoopSimdDirectiveClass: case Stmt::OMPTaskwaitDirectiveClass: case Stmt::OMPTaskyieldDirectiveClass: + case Stmt::OMPErrorDirectiveClass: case Stmt::OMPTeamsDirectiveClass: case Stmt::OMPTeamsDistributeDirectiveClass: case Stmt::OMPTeamsDistributeParallelForDirectiveClass: @@ -1545,7 +1548,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { // For 'if constexpr', consider only the non-discarded case. // FIXME: We should add a DiscardedStmt marker to the AST. - if (Optional<const Stmt *> Case = IS->getNondiscardedCase(Context)) + if (std::optional<const Stmt *> Case = IS->getNondiscardedCase(Context)) return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT; CanThrowResult Then = canThrow(IS->getThen()); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0f79978b0911..2842add2cc4a 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -56,6 +56,7 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/TypeSize.h" +#include <optional> using namespace clang; using namespace sema; @@ -136,7 +137,7 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) { /// Determine whether a FunctionDecl was ever declared with an /// explicit storage class. static bool hasAnyExplicitStorageClass(const FunctionDecl *D) { - for (auto I : D->redecls()) { + for (auto *I : D->redecls()) { if (I->getStorageClass() != SC_None) return true; } @@ -222,7 +223,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess, bool AvoidPartialAvailabilityChecks, - ObjCInterfaceDecl *ClassReceiver) { + ObjCInterfaceDecl *ClassReceiver, + bool SkipTrailingRequiresClause) { SourceLocation Loc = Locs.front(); if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, @@ -281,9 +283,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, // See if this is a function with constraints that need to be satisfied. // Check this before deducing the return type, as it might instantiate the // definition. - if (FD->getTrailingRequiresClause()) { + if (!SkipTrailingRequiresClause && FD->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckFunctionConstraints(FD, Satisfaction, Loc)) + if (CheckFunctionConstraints(FD, Satisfaction, Loc, + /*ForOverloadResolution*/ true)) // A diagnostic will have already been generated (non-constant // constraint expression, for example) return true; @@ -349,7 +352,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, // [OpenMP 5.0], 2.19.7.3. declare mapper Directive, Restrictions // List-items in map clauses on this construct may only refer to the declared // variable var and entities that could be referenced by a procedure defined - // at the same location + // at the same location. + // [OpenMP 5.2] Also allow iterator declared variables. if (LangOpts.OpenMP && isa<VarDecl>(D) && !isOpenMPDeclareMapperVarDeclAllowed(cast<VarDecl>(D))) { Diag(Loc, diag::err_omp_declare_mapper_wrong_var) @@ -837,7 +841,7 @@ ExprResult Sema::UsualUnaryConversions(Expr *E) { E = ImpCastExprToType(E, PTy, CK_IntegralCast).get(); return E; } - if (Ty->isPromotableIntegerType()) { + if (Context.isPromotableIntegerType(Ty)) { QualType PT = Context.getPromotedIntegerType(Ty); E = ImpCastExprToType(E, PT, CK_IntegralCast).get(); return E; @@ -976,7 +980,7 @@ void Sema::checkVariadicArgument(const Expr *E, VariadicCallType CT) { DiagRuntimeBehavior( E->getBeginLoc(), nullptr, PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg) << Ty << CT); - LLVM_FALLTHROUGH; + [[fallthrough]]; case VAK_Valid: if (Ty->isRecordType()) { // This is unlikely to be what the user intended. If the class has a @@ -1056,7 +1060,7 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, return ExprError(); ExprResult Call = BuildCallExpr(TUScope, TrapFn.get(), E->getBeginLoc(), - None, E->getEndLoc()); + std::nullopt, E->getEndLoc()); if (Call.isInvalid()) return ExprError(); @@ -1088,7 +1092,7 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true; if (SkipCast) return false; if (IntTy->isIntegerType()) { - QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType(); + QualType fpTy = ComplexTy->castAs<ComplexType>()->getElementType(); IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating); IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy, CK_FloatingRealToComplex); @@ -1100,60 +1104,59 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr, return false; } +// This handles complex/complex, complex/float, or float/complex. +// When both operands are complex, the shorter operand is converted to the +// type of the longer, and that is the type of the result. This corresponds +// to what is done when combining two real floating-point operands. +// The fun begins when size promotion occur across type domains. +// From H&S 6.3.4: When one operand is complex and the other is a real +// floating-point type, the less precise type is converted, within it's +// real or complex domain, to the precision of the other type. For example, +// when combining a "long double" with a "double _Complex", the +// "double _Complex" is promoted to "long double _Complex". +static QualType handleComplexFloatConversion(Sema &S, ExprResult &Shorter, + QualType ShorterType, + QualType LongerType, + bool PromotePrecision) { + bool LongerIsComplex = isa<ComplexType>(LongerType.getCanonicalType()); + QualType Result = + LongerIsComplex ? LongerType : S.Context.getComplexType(LongerType); + + if (PromotePrecision) { + if (isa<ComplexType>(ShorterType.getCanonicalType())) { + Shorter = + S.ImpCastExprToType(Shorter.get(), Result, CK_FloatingComplexCast); + } else { + if (LongerIsComplex) + LongerType = LongerType->castAs<ComplexType>()->getElementType(); + Shorter = S.ImpCastExprToType(Shorter.get(), LongerType, CK_FloatingCast); + } + } + return Result; +} + /// Handle arithmetic conversion with complex types. Helper function of /// UsualArithmeticConversions() -static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS, - ExprResult &RHS, QualType LHSType, - QualType RHSType, - bool IsCompAssign) { +static QualType handleComplexConversion(Sema &S, ExprResult &LHS, + ExprResult &RHS, QualType LHSType, + QualType RHSType, bool IsCompAssign) { // if we have an integer operand, the result is the complex type. if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType, - /*skipCast*/false)) + /*SkipCast=*/false)) return LHSType; if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType, - /*skipCast*/IsCompAssign)) + /*SkipCast=*/IsCompAssign)) return RHSType; - // This handles complex/complex, complex/float, or float/complex. - // When both operands are complex, the shorter operand is converted to the - // type of the longer, and that is the type of the result. This corresponds - // to what is done when combining two real floating-point operands. - // The fun begins when size promotion occur across type domains. - // From H&S 6.3.4: When one operand is complex and the other is a real - // floating-point type, the less precise type is converted, within it's - // real or complex domain, to the precision of the other type. For example, - // when combining a "long double" with a "double _Complex", the - // "double _Complex" is promoted to "long double _Complex". - // Compute the rank of the two types, regardless of whether they are complex. int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType); - - auto *LHSComplexType = dyn_cast<ComplexType>(LHSType); - auto *RHSComplexType = dyn_cast<ComplexType>(RHSType); - QualType LHSElementType = - LHSComplexType ? LHSComplexType->getElementType() : LHSType; - QualType RHSElementType = - RHSComplexType ? RHSComplexType->getElementType() : RHSType; - - QualType ResultType = S.Context.getComplexType(LHSElementType); - if (Order < 0) { + if (Order < 0) // Promote the precision of the LHS if not an assignment. - ResultType = S.Context.getComplexType(RHSElementType); - if (!IsCompAssign) { - if (LHSComplexType) - LHS = - S.ImpCastExprToType(LHS.get(), ResultType, CK_FloatingComplexCast); - else - LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, CK_FloatingCast); - } - } else if (Order > 0) { - // Promote the precision of the RHS. - if (RHSComplexType) - RHS = S.ImpCastExprToType(RHS.get(), ResultType, CK_FloatingComplexCast); - else - RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast); - } - return ResultType; + return handleComplexFloatConversion(S, LHS, LHSType, RHSType, + /*PromotePrecision=*/!IsCompAssign); + // Promote the precision of the RHS unless it is already the same as the LHS. + return handleComplexFloatConversion(S, RHS, RHSType, LHSType, + /*PromotePrecision=*/Order > 0); } /// Handle arithmetic conversion from integer to float. Helper function @@ -1539,18 +1542,16 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. - QualType LHSType = - Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType(); - QualType RHSType = - Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType(); + QualType LHSType = LHS.get()->getType().getUnqualifiedType(); + QualType RHSType = RHS.get()->getType().getUnqualifiedType(); // For conversion purposes, we ignore any atomic qualifier on the LHS. if (const AtomicType *AtomicLHS = LHSType->getAs<AtomicType>()) LHSType = AtomicLHS->getValueType(); // If both types are identical, no conversion is needed. - if (LHSType == RHSType) - return LHSType; + if (Context.hasSameType(LHSType, RHSType)) + return Context.getCommonSugaredType(LHSType, RHSType); // If either side is a non-arithmetic type (e.g. a pointer), we are done. // The caller can deal with this (e.g. pointer + int). @@ -1559,7 +1560,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // Apply unary and bitfield promotions to the LHS's type. QualType LHSUnpromotedType = LHSType; - if (LHSType->isPromotableIntegerType()) + if (Context.isPromotableIntegerType(LHSType)) LHSType = Context.getPromotedIntegerType(LHSType); QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get()); if (!LHSBitfieldPromoteTy.isNull()) @@ -1568,8 +1569,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast); // If both types are identical, no conversion is needed. - if (LHSType == RHSType) - return LHSType; + if (Context.hasSameType(LHSType, RHSType)) + return Context.getCommonSugaredType(LHSType, RHSType); // At this point, we have two different arithmetic types. @@ -1580,8 +1581,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // Handle complex types first (C99 6.3.1.8p1). if (LHSType->isComplexType() || RHSType->isComplexType()) - return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, - ACK == ACK_CompAssign); + return handleComplexConversion(*this, LHS, RHS, LHSType, RHSType, + ACK == ACK_CompAssign); // Now handle "real" floating types (i.e. float, double, long double). if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType()) @@ -1624,10 +1625,9 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, Types[i] = nullptr; } - ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, - ControllingExpr, - llvm::makeArrayRef(Types, NumAssocs), - ArgExprs); + ExprResult ER = + CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, ControllingExpr, + llvm::ArrayRef(Types, NumAssocs), ArgExprs); delete [] Types; return ER; } @@ -1839,7 +1839,7 @@ static ExprResult BuildCookedLiteralOperatorCall(Sema &S, Scope *Scope, OpNameInfo.setCXXLiteralOperatorNameLoc(UDSuffixLoc); LookupResult R(S, OpName, UDSuffixLoc, Sema::LookupOrdinaryName); - if (S.LookupLiteralOperator(Scope, R, llvm::makeArrayRef(ArgTy, Args.size()), + if (S.LookupLiteralOperator(Scope, R, llvm::ArrayRef(ArgTy, Args.size()), /*AllowRaw*/ false, /*AllowTemplate*/ false, /*AllowStringTemplatePack*/ false, /*DiagnoseMissing*/ true) == Sema::LOLR_Error) @@ -1964,8 +1964,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { TemplateArgument Arg(Lit); TemplateArgumentLocInfo ArgInfo(Lit); ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); - return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(), - &ExplicitArgs); + return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, + StringTokLocs.back(), &ExplicitArgs); } case LOLR_StringTemplatePack: { @@ -1985,8 +1985,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); } - return BuildLiteralOperatorCall(R, OpNameInfo, None, StringTokLocs.back(), - &ExplicitArgs); + return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, + StringTokLocs.back(), &ExplicitArgs); } case LOLR_Raw: case LOLR_ErrorNoDiagnostic: @@ -2082,9 +2082,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, NestedNameSpecifierLoc NNS, NamedDecl *FoundD, SourceLocation TemplateKWLoc, const TemplateArgumentListInfo *TemplateArgs) { - bool RefersToCapturedVariable = - isa<VarDecl>(D) && - NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc()); + bool RefersToCapturedVariable = isa<VarDecl, BindingDecl>(D) && + NeedToCaptureVariable(D, NameInfo.getLoc()); DeclRefExpr *E = DeclRefExpr::Create( Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty, @@ -2626,7 +2625,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // a template name, but we happen to have always already looked up the name // before we get here if it must be a template name. if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr, - None, &TE)) { + std::nullopt, &TE)) { if (TE && KeywordReplacement) { auto &State = getTypoExprState(TE); auto BestTC = State.Consumer->getNextCorrection(); @@ -2738,6 +2737,10 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, ExprResult Sema::BuildQualifiedDeclarationNameExpr( CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI) { + if (NameInfo.getName().isDependentName()) + return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), + NameInfo, /*TemplateArgs=*/nullptr); + DeclContext *DC = computeDeclContext(SS, false); if (!DC) return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), @@ -2947,7 +2950,7 @@ ExprResult Sema::BuildIvarRefExpr(Scope *S, SourceLocation Loc, !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) getCurFunction()->recordUseOfWeak(Result); } - if (getLangOpts().ObjCAutoRefCount) + if (getLangOpts().ObjCAutoRefCount && !isUnevaluatedContext()) if (const BlockDecl *BD = CurContext->getInnermostBlockDecl()) ImplicitlyRetainedSelfLocs.push_back({Loc, BD}); @@ -3187,8 +3190,9 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, /// as an expression. This is only actually called for lookups that /// were not overloaded, and it doesn't promise that the declaration /// will in fact be used. -static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) { - if (D->isInvalidDecl()) +static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D, + bool AcceptInvalid) { + if (D->isInvalidDecl() && !AcceptInvalid) return true; if (isa<TypedefNameDecl>(D)) { @@ -3234,7 +3238,8 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // result, because in the overloaded case the results can only be // functions and function templates. if (R.isSingleResult() && !ShouldLookupResultBeMultiVersionOverload(R) && - CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl())) + CheckDeclInExpr(*this, R.getNameLoc(), R.getFoundDecl(), + AcceptInvalidDecl)) return ExprError(); // Otherwise, just build an unresolved lookup expression. Suppress @@ -3252,8 +3257,9 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return ULE; } -static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, - ValueDecl *var); +static void diagnoseUncapturableValueReferenceOrBinding(Sema &S, + SourceLocation loc, + ValueDecl *var); /// Complete semantic analysis for a reference to the given declaration. ExprResult Sema::BuildDeclarationNameExpr( @@ -3265,7 +3271,7 @@ ExprResult Sema::BuildDeclarationNameExpr( "Cannot refer unambiguously to a function template"); SourceLocation Loc = NameInfo.getLoc(); - if (CheckDeclInExpr(*this, Loc, D)) { + if (CheckDeclInExpr(*this, Loc, D, AcceptInvalidDecl)) { // Recovery from invalid cases (e.g. D is an invalid Decl). // We use the dependent type for the RecoveryExpr to prevent bogus follow-up // diagnostics, as invalid decls use int as a fallback type. @@ -3391,7 +3397,7 @@ ExprResult Sema::BuildDeclarationNameExpr( valueKind = VK_PRValue; break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Decl::ImplicitParam: case Decl::ParmVar: { @@ -3411,20 +3417,11 @@ ExprResult Sema::BuildDeclarationNameExpr( break; } - case Decl::Binding: { + case Decl::Binding: // These are always lvalues. valueKind = VK_LValue; type = type.getNonReferenceType(); - // FIXME: Support lambda-capture of BindingDecls, once CWG actually - // decides how that's supposed to work. - auto *BD = cast<BindingDecl>(VD); - if (BD->getDeclContext() != CurContext) { - auto *DD = dyn_cast_or_null<VarDecl>(BD->getDecomposedDecl()); - if (DD && DD->hasLocalStorage()) - diagnoseUncapturableValueReference(*this, Loc, BD); - } break; - } case Decl::Function: { if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) { @@ -3497,7 +3494,7 @@ ExprResult Sema::BuildDeclarationNameExpr( valueKind = VK_LValue; break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Decl::CXXConversion: case Decl::CXXDestructor: @@ -3506,9 +3503,16 @@ ExprResult Sema::BuildDeclarationNameExpr( break; } - return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD, - /*FIXME: TemplateKWLoc*/ SourceLocation(), - TemplateArgs); + auto *E = + BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD, + /*FIXME: TemplateKWLoc*/ SourceLocation(), TemplateArgs); + // Clang AST consumers assume a DeclRefExpr refers to a valid decl. We + // wrap a DeclRefExpr referring to an invalid decl with a dependent-type + // RecoveryExpr to avoid follow-up semantic analysis (thus prevent bogus + // diagnostics). + if (VD->isInvalidDecl() && E) + return CreateRecoveryExpr(E->getBeginLoc(), E->getEndLoc(), {E}); + return E; } static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source, @@ -3856,7 +3860,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); } - return BuildLiteralOperatorCall(R, OpNameInfo, None, TokLoc, + return BuildLiteralOperatorCall(R, OpNameInfo, std::nullopt, TokLoc, &ExplicitArgs); } case LOLR_StringTemplatePack: @@ -3949,16 +3953,6 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } else { QualType Ty; - // 'long long' is a C99 or C++11 feature. - if (!getLangOpts().C99 && Literal.isLongLong) { - if (getLangOpts().CPlusPlus) - Diag(Tok.getLocation(), - getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); - else - Diag(Tok.getLocation(), diag::ext_c99_longlong); - } - // 'z/uz' literals are a C++2b feature. if (Literal.isSizeT) Diag(Tok.getLocation(), getLangOpts().CPlusPlus @@ -4125,6 +4119,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { else if (AllowUnsigned) Ty = Context.UnsignedLongLongTy; Width = LongLongSize; + + // 'long long' is a C99 or C++11 feature, whether the literal + // explicitly specified 'long long' or we needed the extra width. + if (getLangOpts().CPlusPlus) + Diag(Tok.getLocation(), getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_longlong + : diag::ext_cxx11_longlong); + else if (!getLangOpts().C99) + Diag(Tok.getLocation(), diag::ext_c99_longlong); } } @@ -4504,7 +4507,6 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::ConstantMatrix: case Type::Record: case Type::Enum: - case Type::Elaborated: case Type::TemplateSpecialization: case Type::ObjCObject: case Type::ObjCInterface: @@ -4513,6 +4515,9 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::Pipe: case Type::BitInt: llvm_unreachable("type class is never variably-modified!"); + case Type::Elaborated: + T = cast<ElaboratedType>(Ty)->getNamedType(); + break; case Type::Adjusted: T = cast<AdjustedType>(Ty)->getOriginalType(); break; @@ -5011,7 +5016,7 @@ ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, return nullptr; } - if (Optional<llvm::APSInt> Idx = + if (std::optional<llvm::APSInt> Idx = IndexExpr->getIntegerConstantExpr(Context)) { if ((*Idx < 0 || *Idx >= Dim)) { Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_outside_range) @@ -5415,6 +5420,10 @@ ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, } else { CurContext->addDecl(VD); } + + /// Act on the iterator variable declaration. + ActOnOpenMPIteratorVarDecl(VD); + Expr *Begin = D.Range.Begin; if (!IsDeclTyDependent && Begin && !Begin->isTypeDependent()) { ExprResult BeginRes = @@ -5434,7 +5443,8 @@ ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, IsCorrect = false; continue; } - Optional<llvm::APSInt> Result = Step->getIntegerConstantExpr(Context); + std::optional<llvm::APSInt> Result = + Step->getIntegerConstantExpr(Context); // OpenMP 5.0, 2.1.6 Iterators, Restrictions // If the step expression of a range-specification equals zero, the // behavior is unspecified. @@ -5856,8 +5866,10 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, } bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, - ParmVarDecl *Param) { + ParmVarDecl *Param, Expr *RewrittenInit, + bool SkipImmediateInvocations) { if (Param->hasUnparsedDefaultArg()) { + assert(!RewrittenInit && "Should not have a rewritten init expression yet"); // If we've already cleared out the location for the default argument, // that means we're parsing it right now. if (!UnparsedDefaultArgLocs.count(Param)) { @@ -5874,11 +5886,14 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, return true; } - if (Param->hasUninstantiatedDefaultArg() && - InstantiateDefaultArgument(CallLoc, FD, Param)) - return true; + if (Param->hasUninstantiatedDefaultArg()) { + assert(!RewrittenInit && "Should not have a rewitten init expression yet"); + if (InstantiateDefaultArgument(CallLoc, FD, Param)) + return true; + } - assert(Param->hasInit() && "default argument but no initializer?"); + Expr *Init = RewrittenInit ? RewrittenInit : Param->getInit(); + assert(Init && "default argument but no initializer?"); // If the default expression creates temporaries, we need to // push them to the current stack of expression temporaries so they'll @@ -5887,34 +5902,258 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, // bound temporaries; see the comment in PR5810. // We don't need to do that with block decls, though, because // blocks in default argument expression can never capture anything. - if (auto Init = dyn_cast<ExprWithCleanups>(Param->getInit())) { + if (auto *InitWithCleanup = dyn_cast<ExprWithCleanups>(Init)) { // Set the "needs cleanups" bit regardless of whether there are // any explicit objects. - Cleanup.setExprNeedsCleanups(Init->cleanupsHaveSideEffects()); - + Cleanup.setExprNeedsCleanups(InitWithCleanup->cleanupsHaveSideEffects()); // Append all the objects to the cleanup list. Right now, this // should always be a no-op, because blocks in default argument // expressions should never be able to capture anything. - assert(!Init->getNumObjects() && + assert(!InitWithCleanup->getNumObjects() && "default argument expression has capturing blocks?"); } - - // We already type-checked the argument, so we know it works. - // Just mark all of the declarations in this potentially-evaluated expression - // as being "referenced". EnterExpressionEvaluationContext EvalContext( *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); - MarkDeclarationsReferencedInExpr(Param->getDefaultArg(), - /*SkipLocalVariables=*/true); + ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer = + SkipImmediateInvocations; + MarkDeclarationsReferencedInExpr(Init, /*SkipLocalVariables*/ true); return false; } +struct ImmediateCallVisitor : public RecursiveASTVisitor<ImmediateCallVisitor> { + bool HasImmediateCalls = false; + + bool shouldVisitImplicitCode() const { return true; } + + bool VisitCallExpr(CallExpr *E) { + if (const FunctionDecl *FD = E->getDirectCallee()) + HasImmediateCalls |= FD->isConsteval(); + return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E); + } + + // SourceLocExpr are not immediate invocations + // but CXXDefaultInitExpr/CXXDefaultArgExpr containing a SourceLocExpr + // need to be rebuilt so that they refer to the correct SourceLocation and + // DeclContext. + bool VisitSourceLocExpr(SourceLocExpr *E) { + HasImmediateCalls = true; + return RecursiveASTVisitor<ImmediateCallVisitor>::VisitStmt(E); + } + + // A nested lambda might have parameters with immediate invocations + // in their default arguments. + // The compound statement is not visited (as it does not constitute a + // subexpression). + // FIXME: We should consider visiting and transforming captures + // with init expressions. + bool VisitLambdaExpr(LambdaExpr *E) { + return VisitCXXMethodDecl(E->getCallOperator()); + } + + // Blocks don't support default parameters, and, as for lambdas, + // we don't consider their body a subexpression. + bool VisitBlockDecl(BlockDecl *B) { return false; } + + bool VisitCompoundStmt(CompoundStmt *B) { return false; } + + bool VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + return TraverseStmt(E->getExpr()); + } + + bool VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + return TraverseStmt(E->getExpr()); + } +}; + +struct EnsureImmediateInvocationInDefaultArgs + : TreeTransform<EnsureImmediateInvocationInDefaultArgs> { + EnsureImmediateInvocationInDefaultArgs(Sema &SemaRef) + : TreeTransform(SemaRef) {} + + // Lambda can only have immediate invocations in the default + // args of their parameters, which is transformed upon calling the closure. + // The body is not a subexpression, so we have nothing to do. + // FIXME: Immediate calls in capture initializers should be transformed. + ExprResult TransformLambdaExpr(LambdaExpr *E) { return E; } + ExprResult TransformBlockExpr(BlockExpr *E) { return E; } + + // Make sure we don't rebuild the this pointer as it would + // cause it to incorrectly point it to the outermost class + // in the case of nested struct initialization. + ExprResult TransformCXXThisExpr(CXXThisExpr *E) { return E; } +}; + ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, - FunctionDecl *FD, ParmVarDecl *Param) { + FunctionDecl *FD, ParmVarDecl *Param, + Expr *Init) { assert(Param->hasDefaultArg() && "can't build nonexistent default arg"); - if (CheckCXXDefaultArgExpr(CallLoc, FD, Param)) + + bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer(); + + std::optional<ExpressionEvaluationContextRecord::InitializationContext> + InitializationContext = + OutermostDeclarationWithDelayedImmediateInvocations(); + if (!InitializationContext.has_value()) + InitializationContext.emplace(CallLoc, Param, CurContext); + + if (!Init && !Param->hasUnparsedDefaultArg()) { + // Mark that we are replacing a default argument first. + // If we are instantiating a template we won't have to + // retransform immediate calls. + EnterExpressionEvaluationContext EvalContext( + *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); + + if (Param->hasUninstantiatedDefaultArg()) { + if (InstantiateDefaultArgument(CallLoc, FD, Param)) + return ExprError(); + } + // CWG2631 + // An immediate invocation that is not evaluated where it appears is + // evaluated and checked for whether it is a constant expression at the + // point where the enclosing initializer is used in a function call. + ImmediateCallVisitor V; + if (!NestedDefaultChecking) + V.TraverseDecl(Param); + if (V.HasImmediateCalls) { + ExprEvalContexts.back().DelayedDefaultInitializationContext = { + CallLoc, Param, CurContext}; + EnsureImmediateInvocationInDefaultArgs Immediate(*this); + ExprResult Res = Immediate.TransformInitializer(Param->getInit(), + /*NotCopy=*/false); + if (Res.isInvalid()) + return ExprError(); + Res = ConvertParamDefaultArgument(Param, Res.get(), + Res.get()->getBeginLoc()); + if (Res.isInvalid()) + return ExprError(); + Init = Res.get(); + } + } + + if (CheckCXXDefaultArgExpr( + CallLoc, FD, Param, Init, + /*SkipImmediateInvocations=*/NestedDefaultChecking)) return ExprError(); - return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext); + + return CXXDefaultArgExpr::Create(Context, InitializationContext->Loc, Param, + Init, InitializationContext->Context); +} + +ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { + assert(Field->hasInClassInitializer()); + + // If we might have already tried and failed to instantiate, don't try again. + if (Field->isInvalidDecl()) + return ExprError(); + + auto *ParentRD = cast<CXXRecordDecl>(Field->getParent()); + + std::optional<ExpressionEvaluationContextRecord::InitializationContext> + InitializationContext = + OutermostDeclarationWithDelayedImmediateInvocations(); + if (!InitializationContext.has_value()) + InitializationContext.emplace(Loc, Field, CurContext); + + Expr *Init = nullptr; + + bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer(); + + EnterExpressionEvaluationContext EvalContext( + *this, ExpressionEvaluationContext::PotentiallyEvaluated, Field); + + if (!Field->getInClassInitializer()) { + // Maybe we haven't instantiated the in-class initializer. Go check the + // pattern FieldDecl to see if it has one. + if (isTemplateInstantiation(ParentRD->getTemplateSpecializationKind())) { + CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern(); + DeclContext::lookup_result Lookup = + ClassPattern->lookup(Field->getDeclName()); + + FieldDecl *Pattern = nullptr; + for (auto *L : Lookup) { + if ((Pattern = dyn_cast<FieldDecl>(L))) + break; + } + assert(Pattern && "We must have set the Pattern!"); + if (!Pattern->hasInClassInitializer() || + InstantiateInClassInitializer(Loc, Field, Pattern, + getTemplateInstantiationArgs(Field))) { + Field->setInvalidDecl(); + return ExprError(); + } + } + } + + // CWG2631 + // An immediate invocation that is not evaluated where it appears is + // evaluated and checked for whether it is a constant expression at the + // point where the enclosing initializer is used in a [...] a constructor + // definition, or an aggregate initialization. + ImmediateCallVisitor V; + if (!NestedDefaultChecking) + V.TraverseDecl(Field); + if (V.HasImmediateCalls) { + ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field, + CurContext}; + ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer = + NestedDefaultChecking; + + EnsureImmediateInvocationInDefaultArgs Immediate(*this); + + ExprResult Res = + Immediate.TransformInitializer(Field->getInClassInitializer(), + /*CXXDirectInit=*/false); + if (!Res.isInvalid()) + Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc); + if (Res.isInvalid()) { + Field->setInvalidDecl(); + return ExprError(); + } + Init = Res.get(); + } + + if (Field->getInClassInitializer()) { + Expr *E = Init ? Init : Field->getInClassInitializer(); + if (!NestedDefaultChecking) + MarkDeclarationsReferencedInExpr(E, /*SkipLocalVariables=*/false); + // C++11 [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + ExprResult Res = ActOnFinishFullExpr(E, /*DiscardedValue=*/false); + if (Res.isInvalid()) { + Field->setInvalidDecl(); + return ExprError(); + } + Init = Res.get(); + + return CXXDefaultInitExpr::Create(Context, InitializationContext->Loc, + Field, InitializationContext->Context, + Init); + } + + // DR1351: + // If the brace-or-equal-initializer of a non-static data member + // invokes a defaulted default constructor of its class or of an + // enclosing class in a potentially evaluated subexpression, the + // program is ill-formed. + // + // This resolution is unworkable: the exception specification of the + // default constructor can be needed in an unevaluated context, in + // particular, in the operand of a noexcept-expression, and we can be + // unable to compute an exception specification for an enclosed class. + // + // Any attempt to resolve the exception specification of a defaulted default + // constructor before the initializer is lexically complete will ultimately + // come here at which point we can diagnose it. + RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext(); + Diag(Loc, diag::err_default_member_initializer_not_yet_parsed) + << OutermostClass << Field; + Diag(Field->getEndLoc(), + diag::note_default_member_initializer_not_yet_parsed); + // Recover by marking the field invalid, unless we're in a SFINAE context. + if (!isSFINAEContext()) + Field->setInvalidDecl(); + return ExprError(); } Sema::VariadicCallType @@ -6287,9 +6526,10 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc, return; } - Optional<CharUnits> ArgSize = + std::optional<CharUnits> ArgSize = getASTContext().getTypeSizeInCharsIfKnown(ArgCAT); - Optional<CharUnits> ParmSize = getASTContext().getTypeSizeInCharsIfKnown(CAT); + std::optional<CharUnits> ParmSize = + getASTContext().getTypeSizeInCharsIfKnown(CAT); if (ArgSize && ParmSize && *ArgSize < *ParmSize) { Diag(CallLoc, diag::warn_static_array_too_small) << ArgExpr->getSourceRange() << (unsigned)ArgSize->getQuantity() @@ -6762,8 +7002,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, nullptr, DRE->isNonOdrUse()); } } - } else if (isa<MemberExpr>(NakedFn)) - NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl(); + } else if (auto *ME = dyn_cast<MemberExpr>(NakedFn)) + NDecl = ME->getMemberDecl(); if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(NDecl)) { if (CallingNDeclIndirectly && !checkAddressOfFunctionIsAvailable( @@ -7035,7 +7275,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, TheCall = dyn_cast<CallExpr>(Result.get()); bool CorrectedTypos = TheCall != TheOldCall; if (!TheCall) return Result; - Args = llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()); + Args = llvm::ArrayRef(TheCall->getArgs(), TheCall->getNumArgs()); // A new call expression node was created if some typos were corrected. // However it may not have been constructed with enough storage. In this @@ -8165,23 +8405,6 @@ static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) { return true; } -/// Handle when one or both operands are void type. -static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS, - ExprResult &RHS) { - Expr *LHSExpr = LHS.get(); - Expr *RHSExpr = RHS.get(); - - if (!LHSExpr->getType()->isVoidType()) - S.Diag(RHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void) - << RHSExpr->getSourceRange(); - if (!RHSExpr->getType()->isVoidType()) - S.Diag(LHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void) - << LHSExpr->getSourceRange(); - LHS = S.ImpCastExprToType(LHS.get(), S.Context.VoidTy, CK_ToVoid); - RHS = S.ImpCastExprToType(RHS.get(), S.Context.VoidTy, CK_ToVoid); - return S.Context.VoidTy; -} - /// Return false if the NullExpr can be promoted to PointerTy, /// true otherwise. static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr, @@ -8205,7 +8428,7 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, if (S.Context.hasSameType(LHSTy, RHSTy)) { // Two identical pointers types are always compatible. - return LHSTy; + return S.Context.getCommonSugaredType(LHSTy, RHSTy); } QualType lhptee, rhptee; @@ -8275,7 +8498,9 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual); rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual); - QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee); + QualType CompositeTy = S.Context.mergeTypes( + lhptee, rhptee, /*OfBlockPointer=*/false, /*Unqualified=*/false, + /*BlockReturnType=*/false, /*IsConditionalOperator=*/true); if (CompositeTy.isNull()) { // In this situation, we assume void* type. No especially good @@ -8707,7 +8932,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // And if they're both bfloat (which isn't arithmetic), that's fine too. if (LHSTy->isBFloat16Type() && RHSTy->isBFloat16Type()) { - return LHSTy; + return Context.getCommonSugaredType(LHSTy, RHSTy); } // If both operands are the same structure or union type, the result is that @@ -8717,16 +8942,37 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (LHSRT->getDecl() == RHSRT->getDecl()) // "If both the operands have structure or union type, the result has // that type." This implies that CV qualifiers are dropped. - return LHSTy.getUnqualifiedType(); + return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(), + RHSTy.getUnqualifiedType()); // FIXME: Type of conditional expression must be complete in C mode. } // 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). if (LHSTy->isVoidType() || RHSTy->isVoidType()) { - return checkConditionalVoidType(*this, LHS, RHS); + QualType ResTy; + if (LHSTy->isVoidType() && RHSTy->isVoidType()) { + ResTy = Context.getCommonSugaredType(LHSTy, RHSTy); + } else if (RHSTy->isVoidType()) { + ResTy = RHSTy; + Diag(RHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void) + << RHS.get()->getSourceRange(); + } else { + ResTy = LHSTy; + Diag(LHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void) + << LHS.get()->getSourceRange(); + } + LHS = ImpCastExprToType(LHS.get(), ResTy, CK_ToVoid); + RHS = ImpCastExprToType(RHS.get(), ResTy, CK_ToVoid); + return ResTy; } + // C2x 6.5.15p7: + // ... if both the second and third operands have nullptr_t type, the + // result also has that type. + if (LHSTy->isNullPtrType() && Context.hasSameType(LHSTy, RHSTy)) + return ResTy; + // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has // the type of the other operand." if (!checkConditionalNullPointer(*this, RHS, LHSTy)) return LHSTy; @@ -8763,7 +9009,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // Allow ?: operations in which both operands have the same // built-in sizeless type. if (LHSTy->isSizelessBuiltinType() && Context.hasSameType(LHSTy, RHSTy)) - return LHSTy; + return Context.getCommonSugaredType(LHSTy, RHSTy); // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is not a pointer type. In this case, the user most @@ -9061,8 +9307,8 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin, if (!ResTy->isAnyPointerType()) return ResTy; - auto GetNullability = [&Ctx](QualType Ty) { - Optional<NullabilityKind> Kind = Ty->getNullability(Ctx); + auto GetNullability = [](QualType Ty) { + std::optional<NullabilityKind> Kind = Ty->getNullability(); if (Kind) { // For our purposes, treat _Nullable_result as _Nullable. if (*Kind == NullabilityKind::NullableResult) @@ -9099,7 +9345,7 @@ static QualType computeConditionalNullability(QualType ResTy, bool IsBin, return ResTy; // Strip all nullability from ResTy. - while (ResTy->getNullability(Ctx)) + while (ResTy->getNullability()) ResTy = ResTy.getSingleStepDesugaredType(Ctx); // Create a new AttributedType with the new nullability kind. @@ -9236,7 +9482,8 @@ static bool IsInvalidCmseNSCallConversion(Sema &S, QualType FromType, // This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3]. // FIXME: add a couple examples in this comment. static Sema::AssignConvertType -checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { +checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType, + SourceLocation Loc) { assert(LHSType.isCanonical() && "LHS not canonicalized!"); assert(RHSType.isCanonical() && "RHS not canonicalized!"); @@ -9305,6 +9552,13 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { return Sema::FunctionVoidPointer; } + if (!S.Diags.isIgnored( + diag::warn_typecheck_convert_incompatible_function_pointer_strict, + Loc) && + RHSType->isFunctionPointerType() && LHSType->isFunctionPointerType() && + !S.IsFunctionConversion(RHSType, LHSType, RHSType)) + return Sema::IncompatibleFunctionPointerStrict; + // C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or // unqualified versions of compatible types, ... QualType ltrans = QualType(lhptee, 0), rtrans = QualType(rhptee, 0); @@ -9656,7 +9910,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, Kind = CK_NoOp; else Kind = CK_BitCast; - return checkPointerTypesForAssignment(*this, LHSType, RHSType); + return checkPointerTypesForAssignment(*this, LHSType, RHSType, + RHS.get()->getBeginLoc()); } // int -> T* @@ -9984,6 +10239,24 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, return Incompatible; } + // This check seems unnatural, however it is necessary to ensure the proper + // conversion of functions/arrays. If the conversion were done for all + // DeclExpr's (created by ActOnIdExpression), it would mess up the unary + // expressions that suppress this implicit conversion (&, sizeof). This needs + // to happen before we check for null pointer conversions because C does not + // undergo the same implicit conversions as C++ does above (by the calls to + // TryImplicitConversion() and PerformImplicitConversion()) which insert the + // lvalue to rvalue cast before checking for null pointer constraints. This + // addresses code like: nullptr_t val; int *ptr; ptr = val; + // + // Suppress this for references: C++ 8.5.3p5. + if (!LHSType->isReferenceType()) { + // FIXME: We potentially allocate here even if ConvertRHS is false. + RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose); + if (RHS.isInvalid()) + return Incompatible; + } + // C99 6.5.16.1p1: the left operand is a pointer and the right is // a null pointer constant. if ((LHSType->isPointerType() || LHSType->isObjCObjectPointerType() || @@ -10008,18 +10281,6 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, return Compatible; } - // This check seems unnatural, however it is necessary to ensure the proper - // conversion of functions/arrays. If the conversion were done for all - // DeclExpr's (created by ActOnIdExpression), it would mess up the unary - // expressions that suppress this implicit conversion (&, sizeof). - // - // Suppress this for references: C++ 8.5.3p5. - if (!LHSType->isReferenceType()) { - // FIXME: We potentially allocate here even if ConvertRHS is false. - RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose); - if (RHS.isInvalid()) - return Incompatible; - } CastKind Kind; Sema::AssignConvertType result = CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS); @@ -10434,7 +10695,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, // If the vector types are identical, return. if (Context.hasSameType(LHSType, RHSType)) - return LHSType; + return Context.getCommonSugaredType(LHSType, RHSType); // If we have compatible AltiVec and GCC vector types, use the AltiVec type. if (LHSVecType && RHSVecType && @@ -11249,7 +11510,7 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, QualType LHSTy = Context.isPromotableBitField(LHS.get()); if (LHSTy.isNull()) { LHSTy = LHS.get()->getType(); - if (LHSTy->isPromotableIntegerType()) + if (Context.isPromotableIntegerType(LHSTy)) LHSTy = Context.getPromotedIntegerType(LHSTy); } *CompLHSTy = LHSTy; @@ -12268,7 +12529,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, // We can't use `CK_IntegralCast` when the underlying type is 'bool', so we // promote the boolean type, and all other promotable integer types, to // avoid this. - if (IntType->isPromotableIntegerType()) + if (S.Context.isPromotableIntegerType(IntType)) IntType = S.Context.getPromotedIntegerType(IntType); LHS = S.ImpCastExprToType(LHS.get(), IntType, CK_IntegralCast); @@ -12285,7 +12546,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, if (Type.isNull()) return S.InvalidOperands(Loc, LHS, RHS); - Optional<ComparisonCategoryType> CCT = + std::optional<ComparisonCategoryType> CCT = getComparisonCategoryForBuiltinCmp(Type); if (!CCT) return S.InvalidOperands(Loc, LHS, RHS); @@ -12429,7 +12690,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, QualType CompositeTy = LHS.get()->getType(); assert(!CompositeTy->isReferenceType()); - Optional<ComparisonCategoryType> CCT = + std::optional<ComparisonCategoryType> CCT = getComparisonCategoryForBuiltinCmp(CompositeTy); if (!CCT) return InvalidOperands(Loc, LHS, RHS); @@ -12574,34 +12835,54 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, return computeResultTy(); } - if (getLangOpts().CPlusPlus) { - // C++ [expr.eq]p4: - // Two operands of type std::nullptr_t or one operand of type - // std::nullptr_t and the other a null pointer constant compare equal. - if (!IsOrdered && LHSIsNull && RHSIsNull) { - if (LHSType->isNullPtrType()) { - RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); - return computeResultTy(); - } - if (RHSType->isNullPtrType()) { - LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); - return computeResultTy(); - } - } - // Comparison of Objective-C pointers and block pointers against nullptr_t. - // These aren't covered by the composite pointer type rules. - if (!IsOrdered && RHSType->isNullPtrType() && - (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) { + // C++ [expr.eq]p4: + // Two operands of type std::nullptr_t or one operand of type + // std::nullptr_t and the other a null pointer constant compare + // equal. + // C2x 6.5.9p5: + // If both operands have type nullptr_t or one operand has type nullptr_t + // and the other is a null pointer constant, they compare equal. + if (!IsOrdered && LHSIsNull && RHSIsNull) { + if (LHSType->isNullPtrType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); } - if (!IsOrdered && LHSType->isNullPtrType() && - (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) { + if (RHSType->isNullPtrType()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); } + } + + if (!getLangOpts().CPlusPlus && !IsOrdered && (LHSIsNull || RHSIsNull)) { + // C2x 6.5.9p6: + // Otherwise, at least one operand is a pointer. If one is a pointer and + // the other is a null pointer constant, the null pointer constant is + // converted to the type of the pointer. + if (LHSIsNull && RHSType->isPointerType()) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); + return computeResultTy(); + } + if (RHSIsNull && LHSType->isPointerType()) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); + return computeResultTy(); + } + } + + // Comparison of Objective-C pointers and block pointers against nullptr_t. + // These aren't covered by the composite pointer type rules. + if (!IsOrdered && RHSType->isNullPtrType() && + (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); + return computeResultTy(); + } + if (!IsOrdered && LHSType->isNullPtrType() && + (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); + return computeResultTy(); + } + if (getLangOpts().CPlusPlus) { if (IsRelational && ((LHSType->isNullPtrType() && RHSType->isPointerType()) || (RHSType->isNullPtrType() && LHSType->isPointerType()))) { @@ -13152,7 +13433,7 @@ QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS, assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix"); if (Context.hasSameType(LHSType, RHSType)) - return LHSType; + return Context.getCommonSugaredType(LHSType, RHSType); // Type conversion may change LHS/RHS. Keep copies to the original results, in // case we have to return InvalidOperands. @@ -13196,13 +13477,19 @@ QualType Sema::CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS, if (LHSMatType->getNumColumns() != RHSMatType->getNumRows()) return InvalidOperands(Loc, LHS, RHS); - if (!Context.hasSameType(LHSMatType->getElementType(), - RHSMatType->getElementType())) + if (Context.hasSameType(LHSMatType, RHSMatType)) + return Context.getCommonSugaredType( + LHS.get()->getType().getUnqualifiedType(), + RHS.get()->getType().getUnqualifiedType()); + + QualType LHSELTy = LHSMatType->getElementType(), + RHSELTy = RHSMatType->getElementType(); + if (!Context.hasSameType(LHSELTy, RHSELTy)) return InvalidOperands(Loc, LHS, RHS); - return Context.getConstantMatrixType(LHSMatType->getElementType(), - LHSMatType->getNumRows(), - RHSMatType->getNumColumns()); + return Context.getConstantMatrixType( + Context.getCommonSugaredType(LHSELTy, RHSELTy), + LHSMatType->getNumRows(), RHSMatType->getNumColumns()); } return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign); } @@ -13937,19 +14224,6 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, // type is deprecated unless the assignment is either a discarded-value // expression or an unevaluated operand ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr); - } else { - // C++20 [expr.ass]p6: - // [Compound-assignment] expressions are deprecated if E1 has - // volatile-qualified type and op is not one of the bitwise - // operators |, &, ˆ. - switch (Opc) { - case BO_OrAssign: - case BO_AndAssign: - case BO_XorAssign: - break; - default: - Diag(Loc, diag::warn_deprecated_compound_assign_volatile) << LHSType; - } } } @@ -13964,8 +14238,10 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, return getLangOpts().CPlusPlus ? LHSType : LHSType.getAtomicUnqualifiedType(); } -// Only ignore explicit casts to void. -static bool IgnoreCommaOperand(const Expr *E) { +// Scenarios to ignore if expression E is: +// 1. an explicit cast expression into void +// 2. a function call expression that returns void +static bool IgnoreCommaOperand(const Expr *E, const ASTContext &Context) { E = E->IgnoreParens(); if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { @@ -13980,6 +14256,8 @@ static bool IgnoreCommaOperand(const Expr *E) { } } + if (const auto *CE = dyn_cast<CallExpr>(E)) + return CE->getCallReturnType(Context)->isVoidType(); return false; } @@ -14021,7 +14299,7 @@ void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) { } // Only allow some expressions on LHS to not warn. - if (IgnoreCommaOperand(LHS)) + if (IgnoreCommaOperand(LHS, Context)) return; Diag(Loc, diag::warn_comma_operator); @@ -14486,7 +14764,8 @@ static void RecordModifiableNonNullParam(Sema &S, const Expr *Exp) { /// CheckIndirectionOperand - Type check unary indirection (prefix '*'). static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, - SourceLocation OpLoc) { + SourceLocation OpLoc, + bool IsAfterAmp = false) { if (Op->isTypeDependent()) return S.Context.DependentTy; @@ -14523,18 +14802,18 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, return QualType(); } - // Note that per both C89 and C99, indirection is always legal, even if Result - // is an incomplete type or void. It would be possible to warn about - // dereferencing a void pointer, but it's completely well-defined, and such a - // warning is unlikely to catch any mistakes. In C++, indirection is not valid - // for pointers to 'void' but is fine for any other pointer type: - // - // C++ [expr.unary.op]p1: - // [...] the expression to which [the unary * operator] is applied shall - // be a pointer to an object type, or a pointer to a function type - if (S.getLangOpts().CPlusPlus && Result->isVoidType()) - S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer) - << OpTy << Op->getSourceRange(); + if (Result->isVoidType()) { + // C++ [expr.unary.op]p1: + // [...] the expression to which [the unary * operator] is applied shall + // be a pointer to an object type, or a pointer to a function type + LangOptions LO = S.getLangOpts(); + if (LO.CPlusPlus) + S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer_cpp) + << OpTy << Op->getSourceRange(); + else if (!(LO.C99 && IsAfterAmp) && !S.isUnevaluatedContext()) + S.Diag(OpLoc, diag::ext_typecheck_indirection_through_void_pointer) + << OpTy << Op->getSourceRange(); + } // Dereferences are usually l-values... VK = VK_LValue; @@ -14968,7 +15247,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, break; case BO_And: checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); - LLVM_FALLTHROUGH; + [[fallthrough]]; case BO_Xor: case BO_Or: ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); @@ -15020,7 +15299,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BO_AndAssign: case BO_OrAssign: // fallthrough DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc, true); - LLVM_FALLTHROUGH; + [[fallthrough]]; case BO_XorAssign: CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); CompLHSTy = CompResultTy; @@ -15163,38 +15442,21 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc, Bop->getSourceRange()); } -/// Returns true if the given expression can be evaluated as a constant -/// 'true'. -static bool EvaluatesAsTrue(Sema &S, Expr *E) { - bool Res; - return !E->isValueDependent() && - E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && Res; -} - -/// Returns true if the given expression can be evaluated as a constant -/// 'false'. -static bool EvaluatesAsFalse(Sema &S, Expr *E) { - bool Res; - return !E->isValueDependent() && - E->EvaluateAsBooleanCondition(Res, S.getASTContext()) && !Res; -} - /// Look for '&&' in the left hand of a '||' expr. static void DiagnoseLogicalAndInLogicalOrLHS(Sema &S, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(LHSExpr)) { if (Bop->getOpcode() == BO_LAnd) { - // If it's "a && b || 0" don't warn since the precedence doesn't matter. - if (EvaluatesAsFalse(S, RHSExpr)) - return; - // If it's "1 && a || b" don't warn since the precedence doesn't matter. - if (!EvaluatesAsTrue(S, Bop->getLHS())) + // If it's "string_literal && a || b" don't warn since the precedence + // doesn't matter. + if (!isa<StringLiteral>(Bop->getLHS()->IgnoreParenImpCasts())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop); } else if (Bop->getOpcode() == BO_LOr) { if (BinaryOperator *RBop = dyn_cast<BinaryOperator>(Bop->getRHS())) { - // If it's "a || b && 1 || c" we didn't warn earlier for - // "a || b && 1", but warn now. - if (RBop->getOpcode() == BO_LAnd && EvaluatesAsTrue(S, RBop->getRHS())) + // If it's "a || b && string_literal || c" we didn't warn earlier for + // "a || b && string_literal", but warn now. + if (RBop->getOpcode() == BO_LAnd && + isa<StringLiteral>(RBop->getRHS()->IgnoreParenImpCasts())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, RBop); } } @@ -15206,11 +15468,9 @@ static void DiagnoseLogicalAndInLogicalOrRHS(Sema &S, SourceLocation OpLoc, Expr *LHSExpr, Expr *RHSExpr) { if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(RHSExpr)) { if (Bop->getOpcode() == BO_LAnd) { - // If it's "0 || a && b" don't warn since the precedence doesn't matter. - if (EvaluatesAsFalse(S, LHSExpr)) - return; - // If it's "a || b && 1" don't warn since the precedence doesn't matter. - if (!EvaluatesAsTrue(S, Bop->getRHS())) + // If it's "a || b && string_literal" don't warn since the precedence + // doesn't matter. + if (!isa<StringLiteral>(Bop->getRHS()->IgnoreParenImpCasts())) return EmitDiagnosticForLogicalAndInLogicalOr(S, OpLoc, Bop); } } @@ -15516,15 +15776,15 @@ static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) { if (T.isNull() || T->isDependentType()) return false; - if (!T->isPromotableIntegerType()) + if (!Ctx.isPromotableIntegerType(T)) return true; return Ctx.getIntWidth(T) >= Ctx.getIntWidth(Ctx.IntTy); } ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, - UnaryOperatorKind Opc, - Expr *InputExpr) { + UnaryOperatorKind Opc, Expr *InputExpr, + bool IsAfterAmp) { ExprResult Input = InputExpr; ExprValueKind VK = VK_PRValue; ExprObjectKind OK = OK_Ordinary; @@ -15546,7 +15806,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } } - if (getLangOpts().HLSL) { + if (getLangOpts().HLSL && OpLoc.isValid()) { if (Opc == UO_AddrOf) return ExprError(Diag(OpLoc, diag::err_hlsl_operator_unsupported) << 0); if (Opc == UO_Deref) @@ -15574,7 +15834,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UO_Deref: { Input = DefaultFunctionArrayLvalueConversion(Input.get()); if (Input.isInvalid()) return ExprError(); - resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc); + resultType = + CheckIndirectionOperand(*this, Input.get(), VK, OpLoc, IsAfterAmp); break; } case UO_Plus: @@ -15603,6 +15864,8 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType->castAs<VectorType>()->getVectorKind() != VectorType::AltiVecBool)) break; + else if (resultType->isVLSTBuiltinType()) // SVE vectors allow + and - + break; else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6 Opc == UO_Plus && resultType->isPointerType()) @@ -15792,7 +16055,8 @@ bool Sema::isQualifiedMemberAccess(Expr *E) { } ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, - UnaryOperatorKind Opc, Expr *Input) { + UnaryOperatorKind Opc, Expr *Input, + bool IsAfterAmp) { // First things first: handle placeholders so that the // overloaded-operator check considers the right type. if (const BuiltinType *pty = Input->getType()->getAsPlaceholderType()) { @@ -15831,13 +16095,14 @@ ExprResult Sema::BuildUnaryOp(Scope *S, SourceLocation OpLoc, return CreateOverloadedUnaryOp(OpLoc, Opc, Functions, Input); } - return CreateBuiltinUnaryOp(OpLoc, Opc, Input); + return CreateBuiltinUnaryOp(OpLoc, Opc, Input, IsAfterAmp); } // Unary Operators. 'Tok' is the token for the operator. -ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, - tok::TokenKind Op, Expr *Input) { - return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input); +ExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, + Expr *Input, bool IsAfterAmp) { + return BuildUnaryOp(S, OpLoc, ConvertTokenKindToUnaryOpcode(Op), Input, + IsAfterAmp); } /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". @@ -15845,8 +16110,13 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl) { TheDecl->markUsed(Context); // Create the AST node. The address of a label always has type 'void*'. - return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl, - Context.getPointerType(Context.VoidTy)); + auto *Res = new (Context) AddrLabelExpr( + OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy)); + + if (getCurFunction()) + getCurFunction()->AddrLabels.push_back(Res); + + return Res; } void Sema::ActOnStartStmtExpr() { @@ -16203,7 +16473,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, FunctionProtoType::ExtProtoInfo EPI; EPI.HasTrailingReturn = false; EPI.TypeQuals.addConst(); - T = Context.getFunctionType(Context.DependentTy, None, EPI); + T = Context.getFunctionType(Context.DependentTy, std::nullopt, EPI); Sig = Context.getTrivialTypeSourceInfo(T); } @@ -16290,7 +16560,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); // Put the parameter variables in scope. - for (auto AI : CurBlock->TheDecl->parameters()) { + for (auto *AI : CurBlock->TheDecl->parameters()) { AI->setOwningFunction(CurBlock->TheDecl); // If this has an identifier, add it to the scope stack. @@ -16353,10 +16623,10 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (isa<FunctionNoProtoType>(FTy)) { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = Ext; - BlockTy = Context.getFunctionType(RetTy, None, EPI); + BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI); - // Otherwise, if we don't need to change anything about the function type, - // preserve its sugar structure. + // Otherwise, if we don't need to change anything about the function type, + // preserve its sugar structure. } else if (FTy->getReturnType() == RetTy && (!NoReturn || FTy->getNoReturnAttr())) { BlockTy = BSI->FunctionType; @@ -16374,7 +16644,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, } else { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = FunctionType::ExtInfo().withNoReturn(NoReturn); - BlockTy = Context.getFunctionType(RetTy, None, EPI); + BlockTy = Context.getFunctionType(RetTy, std::nullopt, EPI); } DiagnoseUnusedParameters(BD->parameters()); @@ -16409,8 +16679,9 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, for (Capture &Cap : BSI->Captures) { if (Cap.isInvalid() || Cap.isThisCapture()) continue; - - VarDecl *Var = Cap.getVariable(); + // Cap.getVariable() is always a VarDecl because + // blocks cannot capture structured bindings or other ValueDecl kinds. + auto *Var = cast<VarDecl>(Cap.getVariable()); Expr *CopyExpr = nullptr; if (getLangOpts().CPlusPlus && Cap.isCopyCapture()) { if (const RecordType *Record = @@ -16603,7 +16874,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, // Check for va_arg where arguments of the given type will be promoted // (i.e. this va_arg is guaranteed to have undefined behavior). QualType PromoteType; - if (TInfo->getType()->isPromotableIntegerType()) { + if (Context.isPromotableIntegerType(TInfo->getType())) { PromoteType = Context.getPromotedIntegerType(TInfo->getType()); // [cstdarg.syn]p1 defers the C++ behavior to what the C standard says, // and C2x 7.16.1.1p2 says, in part: @@ -16664,7 +16935,7 @@ ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) { // The type of __null will be int or long, depending on the size of // pointers on the target. QualType Ty; - unsigned pw = Context.getTargetInfo().getPointerWidth(0); + unsigned pw = Context.getTargetInfo().getPointerWidth(LangAS::Default); if (pw == Context.getTargetInfo().getIntWidth()) Ty = Context.IntTy; else if (pw == Context.getTargetInfo().getLongWidth()) @@ -16902,6 +17173,12 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); MayHaveConvFixit = true; break; + case IncompatibleFunctionPointerStrict: + DiagKind = + diag::warn_typecheck_convert_incompatible_function_pointer_strict; + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + MayHaveConvFixit = true; + break; case IncompatibleFunctionPointer: if (getLangOpts().CPlusPlus) { DiagKind = diag::err_typecheck_convert_incompatible_function_pointer; @@ -17492,6 +17769,7 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) { ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { if (isUnevaluatedContext() || !E.isUsable() || !Decl || !Decl->isConsteval() || isConstantEvaluated() || + isCheckingDefaultArgumentOrInitializer() || RebuildingImmediateInvocation || isImmediateFunctionContext()) return E; @@ -17537,8 +17815,14 @@ static void EvaluateAndDiagnoseImmediateInvocation( FD = Call->getConstructor(); else llvm_unreachable("unhandled decl kind"); - assert(FD->isConsteval()); + assert(FD && FD->isConsteval()); SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) << FD; + if (auto Context = + SemaRef.InnermostDeclarationWithDelayedImmediateInvocations()) { + SemaRef.Diag(Context->Loc, diag::note_invalid_consteval_initializer) + << Context->Decl; + SemaRef.Diag(Context->Decl->getBeginLoc(), diag::note_declared_at); + } for (auto &Note : Notes) SemaRef.Diag(Note.first, Note.second); return; @@ -17598,6 +17882,11 @@ static void RemoveNestedImmediateInvocation( DRSet.erase(E); return E; } + ExprResult TransformLambdaExpr(LambdaExpr *E) { + // Do not rebuild lambdas to avoid creating a new type. + // Lambdas have already been processed inside their eval context. + return E; + } bool AlwaysRebuild() { return false; } bool ReplacingOriginal() { return true; } bool AllowSkippingCXXConstructExpr() { @@ -17619,9 +17908,13 @@ static void RemoveNestedImmediateInvocation( Transformer.AllowSkippingFirstCXXConstructExpr = false; ExprResult Res = Transformer.TransformExpr(It->getPointer()->getSubExpr()); - assert(Res.isUsable()); - Res = SemaRef.MaybeCreateExprWithCleanups(Res); - It->getPointer()->setSubExpr(Res.get()); + // The result may not be usable in case of previous compilation errors. + // In this case evaluation of the expression may result in crash so just + // don't do anything further with the result. + if (Res.isUsable()) { + Res = SemaRef.MaybeCreateExprWithCleanups(Res); + It->getPointer()->setSubExpr(Res.get()); + } } static void @@ -17639,7 +17932,7 @@ HandleImmediateInvocations(Sema &SemaRef, /// Prevent sema calls during the tree transform from adding pointers that /// are already in the sets. - llvm::SaveAndRestore<bool> DisableIITracking( + llvm::SaveAndRestore DisableIITracking( SemaRef.RebuildingImmediateInvocation, true); /// Prevent diagnostic during tree transfrom as they are duplicates @@ -17665,7 +17958,7 @@ HandleImmediateInvocations(Sema &SemaRef, for (auto CE : Rec.ImmediateInvocationCandidates) if (!CE.getInt()) EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE); - for (auto DR : Rec.ReferenceToConsteval) { + for (auto *DR : Rec.ReferenceToConsteval) { auto *FD = cast<FunctionDecl>(DR->getDecl()); SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) << FD; @@ -18106,7 +18399,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, } } else { // Walk redefinitions, as some of them may be instantiable. - for (auto i : Func->redecls()) { + for (auto *i : Func->redecls()) { if (!i->isUsed(false) && i->isImplicitlyInstantiable()) MarkFunctionReferenced(Loc, i, MightBeOdrUse); } @@ -18114,6 +18407,16 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, }); } + // If a constructor was defined in the context of a default parameter + // or of another default member initializer (ie a PotentiallyEvaluatedIfUsed + // context), its initializers may not be referenced yet. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) { + for (CXXCtorInitializer *Init : Constructor->inits()) { + if (Init->isInClassMemberInitializer()) + MarkDeclarationsReferencedInExpr(Init->getInit()); + } + } + // C++14 [except.spec]p17: // An exception-specification is considered to be needed when: // - the function is odr-used or, if it appears in an unevaluated operand, @@ -18173,10 +18476,13 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, /// - else capture it in the DeclContext that maps to the /// *FunctionScopeIndexToStopAt on the FunctionScopeInfo stack. static void -MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, +MarkVarDeclODRUsed(ValueDecl *V, SourceLocation Loc, Sema &SemaRef, const unsigned *const FunctionScopeIndexToStopAt = nullptr) { // Keep track of used but undefined variables. // FIXME: We shouldn't suppress this warning for static data members. + VarDecl *Var = V->getPotentiallyDecomposedVarDecl(); + assert(Var && "expected a capturable variable"); + if (Var->hasDefinition(SemaRef.Context) == VarDecl::DeclarationOnly && (!Var->isExternallyVisible() || Var->isInline() || SemaRef.isExternalWithNoLinkageType(Var)) && @@ -18187,12 +18493,11 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, } QualType CaptureType, DeclRefType; if (SemaRef.LangOpts.OpenMP) - SemaRef.tryCaptureOpenMPLambdas(Var); - SemaRef.tryCaptureVariable(Var, Loc, Sema::TryCapture_Implicit, - /*EllipsisLoc*/ SourceLocation(), - /*BuildAndDiagnose*/ true, - CaptureType, DeclRefType, - FunctionScopeIndexToStopAt); + SemaRef.tryCaptureOpenMPLambdas(V); + SemaRef.tryCaptureVariable(V, Loc, Sema::TryCapture_Implicit, + /*EllipsisLoc*/ SourceLocation(), + /*BuildAndDiagnose*/ true, CaptureType, + DeclRefType, FunctionScopeIndexToStopAt); if (SemaRef.LangOpts.CUDA && Var->hasGlobalStorage()) { auto *FD = dyn_cast_or_null<FunctionDecl>(SemaRef.CurContext); @@ -18232,17 +18537,17 @@ MarkVarDeclODRUsed(VarDecl *Var, SourceLocation Loc, Sema &SemaRef, } } - Var->markUsed(SemaRef.Context); + V->markUsed(SemaRef.Context); } -void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture, +void Sema::MarkCaptureUsedInEnclosingContext(ValueDecl *Capture, SourceLocation Loc, unsigned CapturingScopeIndex) { MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex); } -static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, - ValueDecl *var) { +void diagnoseUncapturableValueReferenceOrBinding(Sema &S, SourceLocation loc, + ValueDecl *var) { DeclContext *VarDC = var->getDeclContext(); // If the parameter still belongs to the translation unit, then @@ -18282,12 +18587,12 @@ static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, // capture. } - -static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDecl *Var, - bool &SubCapturesAreNested, - QualType &CaptureType, - QualType &DeclRefType) { - // Check whether we've already captured it. +static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, + ValueDecl *Var, + bool &SubCapturesAreNested, + QualType &CaptureType, + QualType &DeclRefType) { + // Check whether we've already captured it. if (CSI->CaptureMap.count(Var)) { // If we found a capture, any subcaptures are nested. SubCapturesAreNested = true; @@ -18314,14 +18619,18 @@ static bool isVariableAlreadyCapturedInScopeInfo(CapturingScopeInfo *CSI, VarDec // Only block literals, captured statements, and lambda expressions can // capture; other scopes don't work. -static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl *Var, - SourceLocation Loc, - const bool Diagnose, Sema &S) { +static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, + ValueDecl *Var, + SourceLocation Loc, + const bool Diagnose, + Sema &S) { if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC) || isLambdaCallOperator(DC)) return getLambdaAwareParentOfDeclContext(DC); - else if (Var->hasLocalStorage()) { - if (Diagnose) - diagnoseUncapturableValueReference(S, Loc, Var); + + VarDecl *Underlying = Var->getPotentiallyDecomposedVarDecl(); + if (Underlying) { + if (Underlying->hasLocalStorage() && Diagnose) + diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var); } return nullptr; } @@ -18329,9 +18638,12 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl * // Certain capturing entities (lambdas, blocks etc.) are not allowed to capture // certain types of variables (unnamed, variably modified types etc.) // so check for eligibility. -static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var, - SourceLocation Loc, - const bool Diagnose, Sema &S) { +static bool isVariableCapturable(CapturingScopeInfo *CSI, ValueDecl *Var, + SourceLocation Loc, const bool Diagnose, + Sema &S) { + + assert((isa<VarDecl, BindingDecl>(Var)) && + "Only variables and structured bindings can be captured"); bool IsBlock = isa<BlockScopeInfo>(CSI); bool IsLambda = isa<LambdaScopeInfo>(CSI); @@ -18388,17 +18700,28 @@ static bool isVariableCapturable(CapturingScopeInfo *CSI, VarDecl *Var, return false; } + if (isa<BindingDecl>(Var)) { + if (!IsLambda || !S.getLangOpts().CPlusPlus) { + if (Diagnose) + diagnoseUncapturableValueReferenceOrBinding(S, Loc, Var); + return false; + } else if (Diagnose && S.getLangOpts().CPlusPlus) { + S.Diag(Loc, S.LangOpts.CPlusPlus20 + ? diag::warn_cxx17_compat_capture_binding + : diag::ext_capture_binding) + << Var; + S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var; + } + } + return true; } // Returns true if the capture by block was successful. -static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, - SourceLocation Loc, - const bool BuildAndDiagnose, - QualType &CaptureType, - QualType &DeclRefType, - const bool Nested, - Sema &S, bool Invalid) { +static bool captureInBlock(BlockScopeInfo *BSI, ValueDecl *Var, + SourceLocation Loc, const bool BuildAndDiagnose, + QualType &CaptureType, QualType &DeclRefType, + const bool Nested, Sema &S, bool Invalid) { bool ByRef = false; // Blocks are not allowed to capture arrays, excepting OpenCL. @@ -18462,10 +18785,9 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, return !Invalid; } - /// Capture the given variable in the captured region. static bool captureInCapturedRegion( - CapturedRegionScopeInfo *RSI, VarDecl *Var, SourceLocation Loc, + CapturedRegionScopeInfo *RSI, ValueDecl *Var, SourceLocation Loc, const bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const bool RefersToCapturedVariable, Sema::TryCaptureKind Kind, bool IsTopScope, Sema &S, bool Invalid) { @@ -18504,16 +18826,12 @@ static bool captureInCapturedRegion( } /// Capture the given variable in the lambda. -static bool captureInLambda(LambdaScopeInfo *LSI, - VarDecl *Var, - SourceLocation Loc, - const bool BuildAndDiagnose, - QualType &CaptureType, - QualType &DeclRefType, +static bool captureInLambda(LambdaScopeInfo *LSI, ValueDecl *Var, + SourceLocation Loc, const bool BuildAndDiagnose, + QualType &CaptureType, QualType &DeclRefType, const bool RefersToCapturedVariable, const Sema::TryCaptureKind Kind, - SourceLocation EllipsisLoc, - const bool IsTopScope, + SourceLocation EllipsisLoc, const bool IsTopScope, Sema &S, bool Invalid) { // Determine whether we are capturing by reference or by value. bool ByRef = false; @@ -18523,6 +18841,16 @@ static bool captureInLambda(LambdaScopeInfo *LSI, ByRef = (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByref); } + BindingDecl *BD = dyn_cast<BindingDecl>(Var); + // FIXME: We should support capturing structured bindings in OpenMP. + if (!Invalid && BD && S.LangOpts.OpenMP) { + if (BuildAndDiagnose) { + S.Diag(Loc, diag::err_capture_binding_openmp) << Var; + S.Diag(Var->getLocation(), diag::note_entity_declared_at) << Var; + } + Invalid = true; + } + // Compute the type of the field that will capture this variable. if (ByRef) { // C++11 [expr.prim.lambda]p15: @@ -18603,7 +18931,8 @@ static bool captureInLambda(LambdaScopeInfo *LSI, return !Invalid; } -static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) { +static bool canCaptureVariableByCopy(ValueDecl *Var, + const ASTContext &Context) { // Offer a Copy fix even if the type is dependent. if (Var->getType()->isDependentType()) return true; @@ -18629,7 +18958,7 @@ static bool canCaptureVariableByCopy(VarDecl *Var, const ASTContext &Context) { /// standard, for example we can't emit a default copy capture fix-it if we /// already explicitly copy capture capture another variable. static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI, - VarDecl *Var) { + ValueDecl *Var) { assert(LSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_None); // Don't offer Capture by copy of default capture by copy fixes if Var is // known not to be copy constructible. @@ -18705,14 +19034,20 @@ static void buildLambdaCaptureFixit(Sema &Sema, LambdaScopeInfo *LSI, } bool Sema::tryCaptureVariable( - VarDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind, + ValueDecl *Var, SourceLocation ExprLoc, TryCaptureKind Kind, SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt) { // An init-capture is notionally from the context surrounding its // declaration, but its parent DC is the lambda class. DeclContext *VarDC = Var->getDeclContext(); - if (Var->isInitCapture()) - VarDC = VarDC->getParent(); + const auto *VD = dyn_cast<VarDecl>(Var); + if (VD) { + if (VD->isInitCapture()) + VarDC = VarDC->getParent(); + } else { + VD = Var->getPotentiallyDecomposedVarDecl(); + } + assert(VD && "Cannot capture a null variable"); DeclContext *DC = CurContext; const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt @@ -18734,12 +19069,14 @@ bool Sema::tryCaptureVariable( // Capture global variables if it is required to use private copy of this // variable. - bool IsGlobal = !Var->hasLocalStorage(); + bool IsGlobal = !VD->hasLocalStorage(); if (IsGlobal && !(LangOpts.OpenMP && isOpenMPCapturedDecl(Var, /*CheckScopeInfo=*/true, MaxFunctionScopesIndex))) return true; - Var = Var->getCanonicalDecl(); + + if (isa<VarDecl>(Var)) + Var = cast<VarDecl>(Var->getCanonicalDecl()); // Walk up the stack to determine whether we can capture the variable, // performing the "simple" checks that don't depend on type. We stop when @@ -18795,7 +19132,7 @@ bool Sema::tryCaptureVariable( Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl); buildLambdaCaptureFixit(*this, LSI, Var); } else - diagnoseUncapturableValueReference(*this, ExprLoc, Var); + diagnoseUncapturableValueReferenceOrBinding(*this, ExprLoc, Var); } return true; } @@ -18943,7 +19280,7 @@ bool Sema::tryCaptureVariable( return Invalid; } -bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, +bool Sema::tryCaptureVariable(ValueDecl *Var, SourceLocation Loc, TryCaptureKind Kind, SourceLocation EllipsisLoc) { QualType CaptureType; QualType DeclRefType; @@ -18952,7 +19289,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, DeclRefType, nullptr); } -bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) { +bool Sema::NeedToCaptureVariable(ValueDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; return !tryCaptureVariable(Var, Loc, TryCapture_Implicit, SourceLocation(), @@ -18960,7 +19297,7 @@ bool Sema::NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc) { DeclRefType, nullptr); } -QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) { +QualType Sema::getCapturedDeclRefType(ValueDecl *Var, SourceLocation Loc) { QualType CaptureType; QualType DeclRefType; @@ -19382,6 +19719,38 @@ void Sema::CleanupVarDeclMarking() { "MarkVarDeclODRUsed failed to cleanup MaybeODRUseExprs?"); } +static void DoMarkPotentialCapture(Sema &SemaRef, SourceLocation Loc, + ValueDecl *Var, Expr *E) { + VarDecl *VD = Var->getPotentiallyDecomposedVarDecl(); + if (!VD) + return; + + const bool RefersToEnclosingScope = + (SemaRef.CurContext != VD->getDeclContext() && + VD->getDeclContext()->isFunctionOrMethod() && VD->hasLocalStorage()); + if (RefersToEnclosingScope) { + LambdaScopeInfo *const LSI = + SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true); + if (LSI && (!LSI->CallOperator || + !LSI->CallOperator->Encloses(Var->getDeclContext()))) { + // If a variable could potentially be odr-used, defer marking it so + // until we finish analyzing the full expression for any + // lvalue-to-rvalue + // or discarded value conversions that would obviate odr-use. + // Add it to the list of potential captures that will be analyzed + // later (ActOnFinishFullExpr) for eventual capture and odr-use marking + // unless the variable is a reference that was initialized by a constant + // expression (this will never need to be captured or odr-used). + // + // FIXME: We can simplify this a lot after implementing P0588R1. + assert(E && "Capture variable should be used in an expression."); + if (!Var->getType()->isReferenceType() || + !VD->isUsableInConstantExpressions(SemaRef.Context)) + LSI->addPotentialCapture(E->IgnoreParens()); + } + } +} + static void DoMarkVarDeclReferenced( Sema &SemaRef, SourceLocation Loc, VarDecl *Var, Expr *E, llvm::DenseMap<const VarDecl *, int> &RefsMinusAssignments) { @@ -19505,7 +19874,10 @@ static void DoMarkVarDeclReferenced( switch (OdrUse) { case OdrUseContext::None: - assert((!E || isa<FunctionParmPackExpr>(E)) && + // In some cases, a variable may not have been marked unevaluated, if it + // appears in a defaukt initializer. + assert((!E || isa<FunctionParmPackExpr>(E) || + SemaRef.isUnevaluatedContext()) && "missing non-odr-use marking for unevaluated decl ref"); break; @@ -19528,34 +19900,31 @@ static void DoMarkVarDeclReferenced( // odr-used, but we may still need to track them for lambda capture. // FIXME: Do we also need to do this inside dependent typeid expressions // (which are modeled as unevaluated at this point)? - const bool RefersToEnclosingScope = - (SemaRef.CurContext != Var->getDeclContext() && - Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage()); - if (RefersToEnclosingScope) { - LambdaScopeInfo *const LSI = - SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true); - if (LSI && (!LSI->CallOperator || - !LSI->CallOperator->Encloses(Var->getDeclContext()))) { - // If a variable could potentially be odr-used, defer marking it so - // until we finish analyzing the full expression for any - // lvalue-to-rvalue - // or discarded value conversions that would obviate odr-use. - // Add it to the list of potential captures that will be analyzed - // later (ActOnFinishFullExpr) for eventual capture and odr-use marking - // unless the variable is a reference that was initialized by a constant - // expression (this will never need to be captured or odr-used). - // - // FIXME: We can simplify this a lot after implementing P0588R1. - assert(E && "Capture variable should be used in an expression."); - if (!Var->getType()->isReferenceType() || - !Var->isUsableInConstantExpressions(SemaRef.Context)) - LSI->addPotentialCapture(E->IgnoreParens()); - } - } + DoMarkPotentialCapture(SemaRef, Loc, Var, E); break; } } +static void DoMarkBindingDeclReferenced(Sema &SemaRef, SourceLocation Loc, + BindingDecl *BD, Expr *E) { + BD->setReferenced(); + + if (BD->isInvalidDecl()) + return; + + OdrUseContext OdrUse = isOdrUseContext(SemaRef); + if (OdrUse == OdrUseContext::Used) { + QualType CaptureType, DeclRefType; + SemaRef.tryCaptureVariable(BD, Loc, Sema::TryCapture_Implicit, + /*EllipsisLoc*/ SourceLocation(), + /*BuildAndDiagnose*/ true, CaptureType, + DeclRefType, + /*FunctionScopeIndexToStopAt*/ nullptr); + } else if (OdrUse == OdrUseContext::Dependent) { + DoMarkPotentialCapture(SemaRef, Loc, BD, E); + } +} + /// Mark a variable referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3). Note that this should not be /// used directly for normal expressions referring to VarDecl. @@ -19575,6 +19944,11 @@ MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E, return; } + if (BindingDecl *Decl = dyn_cast<BindingDecl>(D)) { + DoMarkBindingDeclReferenced(SemaRef, Loc, Decl, E); + return; + } + SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse); // If this is a call to a method via a cast, also mark the method in the @@ -19615,7 +19989,9 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl())) if (!isUnevaluatedContext() && !isConstantEvaluated() && - FD->isConsteval() && !RebuildingImmediateInvocation) + !isImmediateFunctionContext() && + !isCheckingDefaultArgumentOrInitializer() && FD->isConsteval() && + !RebuildingImmediateInvocation && !FD->isDependentContext()) ExprEvalContexts.back().ReferenceToConsteval.insert(E); MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse, RefsMinusAssignments); @@ -19849,7 +20225,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts, bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD) { return DiagRuntimeBehavior( - Loc, Statement ? llvm::makeArrayRef(Statement) : llvm::None, PD); + Loc, Statement ? llvm::ArrayRef(Statement) : std::nullopt, PD); } bool Sema::CheckCallReturnType(QualType ReturnType, SourceLocation Loc, @@ -20761,7 +21137,8 @@ Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { ExprResult Sema::ActOnObjCAvailabilityCheckExpr( llvm::ArrayRef<AvailabilitySpec> AvailSpecs, SourceLocation AtLoc, SourceLocation RParen) { - auto FindSpecVersion = [&](StringRef Platform) -> Optional<VersionTuple> { + auto FindSpecVersion = + [&](StringRef Platform) -> std::optional<VersionTuple> { auto Spec = llvm::find_if(AvailSpecs, [&](const AvailabilitySpec &Spec) { return Spec.getPlatform() == Platform; }); @@ -20773,7 +21150,7 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( }); } if (Spec == AvailSpecs.end()) - return None; + return std::nullopt; return Spec->getVersion(); }; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 5331193de863..e3eef9323b2f 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -21,11 +21,13 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/AlignedAllocation.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Basic/TypeTraits.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" @@ -42,6 +44,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TypeSize.h" +#include <optional> using namespace clang; using namespace sema; @@ -241,7 +244,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (IsAcceptableResult(Type)) { QualType T = Context.getTypeDeclType(Type); MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); - return CreateParsedType(T, + return CreateParsedType(Context.getElaboratedType(ETK_None, nullptr, T), Context.getTrivialTypeSourceInfo(T, NameLoc)); } } @@ -1388,6 +1391,13 @@ ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit) { + if (getLangOpts().HLSL && Type.getTypePtr()->isPointerType()) { + auto *This = new (Context) + CXXThisExpr(Loc, Type.getTypePtr()->getPointeeType(), IsImplicit); + This->setValueKind(ExprValueKind::VK_LValue); + MarkThisReferenced(This); + return This; + } auto *This = new (Context) CXXThisExpr(Loc, Type, IsImplicit); MarkThisReferenced(This); return This; @@ -1450,9 +1460,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, QualType Ty = TInfo->getType(); SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); - assert((!ListInitialization || - (Exprs.size() == 1 && isa<InitListExpr>(Exprs[0]))) && - "List initialization must have initializer list as expression."); + assert((!ListInitialization || Exprs.size() == 1) && + "List initialization must have exactly one expression."); SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc); InitializedEntity Entity = @@ -1506,12 +1515,17 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces) << ListInitialization << Ty << FullRange); QualType DeducedType; - if (DeduceAutoType(TInfo, Deduce, DeducedType) == DAR_Failed) + TemplateDeductionInfo Info(Deduce->getExprLoc()); + TemplateDeductionResult Result = + DeduceAutoType(TInfo->getTypeLoc(), Deduce, DeducedType, Info); + if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure) << Ty << Deduce->getType() << FullRange << Deduce->getSourceRange()); - if (DeducedType.isNull()) + if (DeducedType.isNull()) { + assert(Result == TDK_AlreadyDiagnosed); return ExprError(); + } Ty = DeducedType; Entity = InitializedEntity::InitializeTemporary(TInfo, Ty); @@ -1832,7 +1846,7 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer) { - Optional<Expr *> ArraySize; + std::optional<Expr *> ArraySize; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { @@ -1924,7 +1938,7 @@ Sema::isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const { return false; if (FD.isDefined()) return false; - Optional<unsigned> AlignmentParam; + std::optional<unsigned> AlignmentParam; if (FD.isReplaceableGlobalAllocationFunction(&AlignmentParam) && AlignmentParam) return true; @@ -1950,17 +1964,14 @@ void Sema::diagnoseUnavailableAlignedAllocation(const FunctionDecl &FD, } } -ExprResult -Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, - SourceLocation PlacementLParen, - MultiExprArg PlacementArgs, - SourceLocation PlacementRParen, - SourceRange TypeIdParens, - QualType AllocType, - TypeSourceInfo *AllocTypeInfo, - Optional<Expr *> ArraySize, - SourceRange DirectInitRange, - Expr *Initializer) { +ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + SourceRange TypeIdParens, QualType AllocType, + TypeSourceInfo *AllocTypeInfo, + std::optional<Expr *> ArraySize, + SourceRange DirectInitRange, Expr *Initializer) { SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange(); SourceLocation StartLoc = Range.getBegin(); @@ -2045,12 +2056,17 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, Diag(Deduce->getBeginLoc(), diag::err_auto_expr_init_paren_braces) << Braced << AllocType << TypeRange); QualType DeducedType; - if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) + TemplateDeductionInfo Info(Deduce->getExprLoc()); + TemplateDeductionResult Result = + DeduceAutoType(AllocTypeInfo->getTypeLoc(), Deduce, DeducedType, Info); + if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) - << AllocType << Deduce->getType() - << TypeRange << Deduce->getSourceRange()); - if (DeducedType.isNull()) + << AllocType << Deduce->getType() << TypeRange + << Deduce->getSourceRange()); + if (DeducedType.isNull()) { + assert(Result == TDK_AlreadyDiagnosed); return ExprError(); + } AllocType = DeducedType; } @@ -2069,6 +2085,9 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange)) return ExprError(); + if (ArraySize && !checkArrayElementAlignment(AllocType, TypeRange.getBegin())) + return ExprError(); + // In ARC, infer 'retaining' for the allocated if (getLangOpts().ObjCAutoRefCount && AllocType.getObjCLifetime() == Qualifiers::OCL_None && @@ -2092,7 +2111,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // conversion function to integral or unscoped enumeration type exists. // C++1y [expr.new]p6: The expression [...] is implicitly converted to // std::size_t. - llvm::Optional<uint64_t> KnownArraySize; + std::optional<uint64_t> KnownArraySize; if (ArraySize && *ArraySize && !(*ArraySize)->isTypeDependent()) { ExprResult ConvertedSize; if (getLangOpts().CPlusPlus14) { @@ -2186,7 +2205,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // FIXME: Per CWG1464, we are required to check the value prior to // converting to size_t. This will never find a negative array size in // C++14 onwards, because Value is always unsigned here! - if (Optional<llvm::APSInt> Value = + if (std::optional<llvm::APSInt> Value = (*ArraySize)->getIntegerConstantExpr(Context)) { if (Value->isSigned() && Value->isNegative()) { return ExprError(Diag((*ArraySize)->getBeginLoc(), @@ -2273,7 +2292,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, SizeTyWidth, Context.getTypeSizeInChars(AllocType).getQuantity()); // How many bytes do we want to allocate here? - llvm::Optional<llvm::APInt> AllocationSize; + std::optional<llvm::APInt> AllocationSize; if (!ArraySize && !AllocType->isDependentType()) { // For non-array operator new, we only want to allocate one element. AllocationSize = SingleEltSize; @@ -2632,7 +2651,9 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // tree? Or should the consumer just recalculate the value? // FIXME: Using a dummy value will interact poorly with attribute enable_if. IntegerLiteral Size( - Context, llvm::APInt::getZero(Context.getTargetInfo().getPointerWidth(0)), + Context, + llvm::APInt::getZero( + Context.getTargetInfo().getPointerWidth(LangAS::Default)), Context.getSizeType(), SourceLocation()); AllocArgs.push_back(&Size); @@ -2950,6 +2971,14 @@ void Sema::DeclareGlobalNewDelete() { if (getLangOpts().OpenCLCPlusPlus) return; + // C++ [basic.stc.dynamic.general]p2: + // The library provides default definitions for the global allocation + // and deallocation functions. Some global allocation and deallocation + // functions are replaceable ([new.delete]); these are attached to the + // global module ([module.unit]). + if (getLangOpts().CPlusPlusModules && getCurrentModule()) + PushGlobalModuleFragment(SourceLocation(), /*IsImplicit=*/true); + // C++ [basic.std.dynamic]p2: // [...] The following allocation and deallocation functions (18.4) are // implicitly declared in global scope in each translation unit of a @@ -2989,6 +3018,14 @@ void Sema::DeclareGlobalNewDelete() { &PP.getIdentifierTable().get("bad_alloc"), nullptr); getStdBadAlloc()->setImplicit(true); + + // The implicitly declared "std::bad_alloc" should live in global module + // fragment. + if (GlobalModuleFragment) { + getStdBadAlloc()->setModuleOwnershipKind( + Decl::ModuleOwnershipKind::ReachableWhenImported); + getStdBadAlloc()->setLocalOwningModule(GlobalModuleFragment); + } } if (!StdAlignValT && getLangOpts().AlignedAllocation) { // The "std::align_val_t" enum class has not yet been declared, so build it @@ -2996,9 +3033,19 @@ void Sema::DeclareGlobalNewDelete() { auto *AlignValT = EnumDecl::Create( Context, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(), &PP.getIdentifierTable().get("align_val_t"), nullptr, true, true, true); + + // The implicitly declared "std::align_val_t" should live in global module + // fragment. + if (GlobalModuleFragment) { + AlignValT->setModuleOwnershipKind( + Decl::ModuleOwnershipKind::ReachableWhenImported); + AlignValT->setLocalOwningModule(GlobalModuleFragment); + } + AlignValT->setIntegerType(Context.getSizeType()); AlignValT->setPromotionType(Context.getSizeType()); AlignValT->setImplicit(true); + StdAlignValT = AlignValT; } @@ -3040,6 +3087,9 @@ void Sema::DeclareGlobalNewDelete() { DeclareGlobalAllocationFunctions(OO_Array_New, VoidPtr, SizeT); DeclareGlobalAllocationFunctions(OO_Delete, Context.VoidTy, VoidPtr); DeclareGlobalAllocationFunctions(OO_Array_Delete, Context.VoidTy, VoidPtr); + + if (getLangOpts().CPlusPlusModules && getCurrentModule()) + PopGlobalModuleFragment(); } /// DeclareGlobalAllocationFunction - Declares a single implicit global @@ -3061,7 +3111,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, for (auto *P : Func->parameters()) FuncParams.push_back( Context.getCanonicalType(P->getType().getUnqualifiedType())); - if (llvm::makeArrayRef(FuncParams) == Params) { + if (llvm::ArrayRef(FuncParams) == Params) { // Make the function visible to name lookup, even if we found it in // an unimported module. It either is an implicitly-declared global // allocation function, or is suppressing that function. @@ -3084,7 +3134,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); assert(StdBadAlloc && "Must have std::bad_alloc declared"); EPI.ExceptionSpec.Type = EST_Dynamic; - EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType); + EPI.ExceptionSpec.Exceptions = llvm::ArrayRef(BadAllocType); } if (getLangOpts().NewInfallible) { EPI.ExceptionSpec.Type = EST_DynamicNone; @@ -3108,6 +3158,22 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, Alloc->addAttr( ReturnsNonNullAttr::CreateImplicit(Context, Alloc->getLocation())); + // C++ [basic.stc.dynamic.general]p2: + // The library provides default definitions for the global allocation + // and deallocation functions. Some global allocation and deallocation + // functions are replaceable ([new.delete]); these are attached to the + // global module ([module.unit]). + // + // In the language wording, these functions are attched to the global + // module all the time. But in the implementation, the global module + // is only meaningful when we're in a module unit. So here we attach + // these allocation functions to global module conditionally. + if (GlobalModuleFragment) { + Alloc->setModuleOwnershipKind( + Decl::ModuleOwnershipKind::ReachableWhenImported); + Alloc->setLocalOwningModule(GlobalModuleFragment); + } + Alloc->addAttr(VisibilityAttr::CreateImplicit( Context, LangOpts.GlobalAllocationFunctionVisibilityHidden ? VisibilityAttr::Hidden @@ -3176,7 +3242,8 @@ FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc, bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, - FunctionDecl *&Operator, bool Diagnose) { + FunctionDecl *&Operator, bool Diagnose, + bool WantSize, bool WantAligned) { LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); @@ -3186,13 +3253,14 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Found.suppressDiagnostics(); - bool Overaligned = hasNewExtendedAlignment(*this, Context.getRecordType(RD)); + bool Overaligned = + WantAligned || hasNewExtendedAlignment(*this, Context.getRecordType(RD)); // C++17 [expr.delete]p10: // If the deallocation functions have class scope, the one without a // parameter of type std::size_t is selected. llvm::SmallVector<UsualDeallocFnInfo, 4> Matches; - resolveDeallocationOverload(*this, Found, /*WantSize*/ false, + resolveDeallocationOverload(*this, Found, /*WantSize*/ WantSize, /*WantAlign*/ Overaligned, &Matches); // If we could find an overload, use it. @@ -4170,7 +4238,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return ExprError(); case ImplicitConversionSequence::EllipsisConversion: - llvm_unreachable("Cannot perform an ellipsis conversion"); + case ImplicitConversionSequence::StaticObjectArgumentConversion: + llvm_unreachable("bad conversion"); case ImplicitConversionSequence::BadConversion: Sema::AssignConvertType ConvTy = @@ -4740,12 +4809,16 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, case UTT_IsIntegral: case UTT_IsFloatingPoint: case UTT_IsArray: + case UTT_IsBoundedArray: case UTT_IsPointer: + case UTT_IsNullPointer: + case UTT_IsReferenceable: case UTT_IsLvalueReference: case UTT_IsRvalueReference: case UTT_IsMemberFunctionPointer: case UTT_IsMemberObjectPointer: case UTT_IsEnum: + case UTT_IsScopedEnum: case UTT_IsUnion: case UTT_IsClass: case UTT_IsFunction: @@ -4766,6 +4839,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, case UTT_IsConst: case UTT_IsVolatile: case UTT_IsSigned: + case UTT_IsUnboundedArray: case UTT_IsUnsigned: // This type trait always returns false, checking the type is moot. @@ -4792,9 +4866,16 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); return true; + // LWG3823: T shall be an array type, a complete type, or cv void. + case UTT_IsAggregate: + if (ArgTy->isArrayType() || ArgTy->isVoidType()) + return true; + + return !S.RequireCompleteType( + Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); + // C++1z [meta.unary.prop]: // remove_all_extents_t<T> shall be a complete type or cv void. - case UTT_IsAggregate: case UTT_IsTrivial: case UTT_IsTriviallyCopyable: case UTT_IsStandardLayout: @@ -4817,7 +4898,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, case UTT_HasTrivialDestructor: case UTT_HasVirtualDestructor: ArgTy = QualType(ArgTy->getBaseElementTypeUnsafe(), 0); - LLVM_FALLTHROUGH; + [[fallthrough]]; // C++1z [meta.unary.prop]: // T shall be a complete type, cv void, or an array of unknown bound. @@ -4885,8 +4966,26 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return T->isFloatingType(); case UTT_IsArray: return T->isArrayType(); + case UTT_IsBoundedArray: + if (!T->isVariableArrayType()) { + return T->isArrayType() && !T->isIncompleteArrayType(); + } + + Self.Diag(KeyLoc, diag::err_vla_unsupported) + << 1 << tok::kw___is_bounded_array; + return false; + case UTT_IsUnboundedArray: + if (!T->isVariableArrayType()) { + return T->isIncompleteArrayType(); + } + + Self.Diag(KeyLoc, diag::err_vla_unsupported) + << 1 << tok::kw___is_unbounded_array; + return false; case UTT_IsPointer: return T->isAnyPointerType(); + case UTT_IsNullPointer: + return T->isNullPtrType(); case UTT_IsLvalueReference: return T->isLValueReferenceType(); case UTT_IsRvalueReference: @@ -4897,6 +4996,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return T->isMemberDataPointerType(); case UTT_IsEnum: return T->isEnumeralType(); + case UTT_IsScopedEnum: + return T->isScopedEnumeralType(); case UTT_IsUnion: return T->isUnionType(); case UTT_IsClass: @@ -5268,6 +5369,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return C.hasUniqueObjectRepresentations(T); case UTT_IsTriviallyRelocatable: return T.isTriviallyRelocatableType(C); + case UTT_IsReferenceable: + return T.isReferenceable(); } } @@ -5412,6 +5515,8 @@ void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind, Replacement = BTT_IsTriviallyAssignable; break; case UTT_HasTrivialCopy: + Replacement = UTT_IsTriviallyCopyable; + break; case UTT_HasTrivialDefaultConstructor: case UTT_HasTrivialMoveConstructor: Replacement = TT_IsTriviallyConstructible; @@ -5427,9 +5532,26 @@ void DiagnoseBuiltinDeprecation(Sema& S, TypeTrait Kind, } } +bool Sema::CheckTypeTraitArity(unsigned Arity, SourceLocation Loc, size_t N) { + if (Arity && N != Arity) { + Diag(Loc, diag::err_type_trait_arity) + << Arity << 0 << (Arity > 1) << (int)N << SourceRange(Loc); + return false; + } + + if (!Arity && N == 0) { + Diag(Loc, diag::err_type_trait_arity) + << 1 << 1 << 1 << (int)N << SourceRange(Loc); + return false; + } + return true; +} + ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef<TypeSourceInfo *> Args, SourceLocation RParenLoc) { + if (!CheckTypeTraitArity(getTypeTraitArity(Kind), KWLoc, Args.size())) + return ExprError(); QualType ResultType = Context.getLogicalOperationType(); if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness( @@ -6186,7 +6308,7 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, << LHSType << RHSType; return {}; } - ResultType = LHSType; + ResultType = Context.getCommonSugaredType(LHSType, RHSType); } else if (LHSVT || RHSVT) { ResultType = CheckVectorOperands( LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true, @@ -6197,15 +6319,13 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, return {}; } else { // Both are scalar. - QualType ResultElementTy; - LHSType = LHSType.getCanonicalType().getUnqualifiedType(); - RHSType = RHSType.getCanonicalType().getUnqualifiedType(); - - if (Context.hasSameType(LHSType, RHSType)) - ResultElementTy = LHSType; - else - ResultElementTy = - UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); + LHSType = LHSType.getUnqualifiedType(); + RHSType = RHSType.getUnqualifiedType(); + QualType ResultElementTy = + Context.hasSameType(LHSType, RHSType) + ? Context.getCommonSugaredType(LHSType, RHSType) + : UsualArithmeticConversions(LHS, RHS, QuestionLoc, + ACK_Conditional); if (ResultElementTy->isEnumeralType()) { Diag(QuestionLoc, diag::err_conditional_vector_operand_type) @@ -6425,7 +6545,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // -- Both the second and third operands have type void; the result is of // type void and is a prvalue. if (LVoid && RVoid) - return Context.VoidTy; + return Context.getCommonSugaredType(LTy, RTy); // Neither holds, error. Diag(QuestionLoc, diag::err_conditional_void_nonvoid) @@ -6531,21 +6651,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (LHS.get()->getObjectKind() == OK_BitField || RHS.get()->getObjectKind() == OK_BitField) OK = OK_BitField; - - // If we have function pointer types, unify them anyway to unify their - // exception specifications, if any. - if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { - Qualifiers Qs = LTy.getQualifiers(); - LTy = FindCompositePointerType(QuestionLoc, LHS, RHS, - /*ConvertArgs*/false); - LTy = Context.getQualifiedType(LTy, Qs); - - assert(!LTy.isNull() && "failed to find composite pointer type for " - "canonically equivalent function ptr types"); - assert(Context.hasSameType(LTy, RTy) && "bad composite pointer type"); - } - - return LTy; + return Context.getCommonSugaredType(LTy, RTy); } // C++11 [expr.cond]p5 @@ -6575,36 +6681,23 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // is a prvalue temporary of the result type, which is // copy-initialized from either the second operand or the third // operand depending on the value of the first operand. - if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { + if (Context.hasSameType(LTy, RTy)) { if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. - InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); - - ExprResult LHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), - LHS); + ExprResult LHSCopy = PerformCopyInitialization( + InitializedEntity::InitializeTemporary(LTy), SourceLocation(), LHS); if (LHSCopy.isInvalid()) return QualType(); - ExprResult RHSCopy = PerformCopyInitialization(Entity, - SourceLocation(), - RHS); + ExprResult RHSCopy = PerformCopyInitialization( + InitializedEntity::InitializeTemporary(RTy), SourceLocation(), RHS); if (RHSCopy.isInvalid()) return QualType(); LHS = LHSCopy; RHS = RHSCopy; } - - // If we have function pointer types, unify them anyway to unify their - // exception specifications, if any. - if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { - LTy = FindCompositePointerType(QuestionLoc, LHS, RHS); - assert(!LTy.isNull() && "failed to find composite pointer type for " - "canonically equivalent function ptr types"); - } - - return LTy; + return Context.getCommonSugaredType(LTy, RTy); } // Extension: conditional operator involving vector types. @@ -6669,79 +6762,6 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, return QualType(); } -static FunctionProtoType::ExceptionSpecInfo -mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, - FunctionProtoType::ExceptionSpecInfo ESI2, - SmallVectorImpl<QualType> &ExceptionTypeStorage) { - ExceptionSpecificationType EST1 = ESI1.Type; - ExceptionSpecificationType EST2 = ESI2.Type; - - // If either of them can throw anything, that is the result. - if (EST1 == EST_None) return ESI1; - if (EST2 == EST_None) return ESI2; - if (EST1 == EST_MSAny) return ESI1; - if (EST2 == EST_MSAny) return ESI2; - if (EST1 == EST_NoexceptFalse) return ESI1; - if (EST2 == EST_NoexceptFalse) return ESI2; - - // If either of them is non-throwing, the result is the other. - if (EST1 == EST_NoThrow) return ESI2; - if (EST2 == EST_NoThrow) return ESI1; - if (EST1 == EST_DynamicNone) return ESI2; - if (EST2 == EST_DynamicNone) return ESI1; - if (EST1 == EST_BasicNoexcept) return ESI2; - if (EST2 == EST_BasicNoexcept) return ESI1; - if (EST1 == EST_NoexceptTrue) return ESI2; - if (EST2 == EST_NoexceptTrue) return ESI1; - - // If we're left with value-dependent computed noexcept expressions, we're - // stuck. Before C++17, we can just drop the exception specification entirely, - // since it's not actually part of the canonical type. And this should never - // happen in C++17, because it would mean we were computing the composite - // pointer type of dependent types, which should never happen. - if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) { - assert(!S.getLangOpts().CPlusPlus17 && - "computing composite pointer type of dependent types"); - return FunctionProtoType::ExceptionSpecInfo(); - } - - // Switch over the possibilities so that people adding new values know to - // update this function. - switch (EST1) { - case EST_None: - case EST_DynamicNone: - case EST_MSAny: - case EST_BasicNoexcept: - case EST_DependentNoexcept: - case EST_NoexceptFalse: - case EST_NoexceptTrue: - case EST_NoThrow: - llvm_unreachable("handled above"); - - case EST_Dynamic: { - // This is the fun case: both exception specifications are dynamic. Form - // the union of the two lists. - assert(EST2 == EST_Dynamic && "other cases should already be handled"); - llvm::SmallPtrSet<QualType, 8> Found; - for (auto &Exceptions : {ESI1.Exceptions, ESI2.Exceptions}) - for (QualType E : Exceptions) - if (Found.insert(S.Context.getCanonicalType(E)).second) - ExceptionTypeStorage.push_back(E); - - FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic); - Result.Exceptions = ExceptionTypeStorage; - return Result; - } - - case EST_Unevaluated: - case EST_Uninstantiated: - case EST_Unparsed: - llvm_unreachable("shouldn't see unresolved exception specifications here"); - } - - llvm_unreachable("invalid ExceptionSpecificationType"); -} - /// Find a merged pointer type and convert the two expressions to it. /// /// This finds the composite pointer type for \p E1 and \p E2 according to @@ -7045,9 +7065,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // The result is nothrow if both operands are. SmallVector<QualType, 8> ExceptionTypeStorage; - EPI1.ExceptionSpec = EPI2.ExceptionSpec = - mergeExceptionSpecs(*this, EPI1.ExceptionSpec, EPI2.ExceptionSpec, - ExceptionTypeStorage); + EPI1.ExceptionSpec = EPI2.ExceptionSpec = Context.mergeExceptionSpecs( + EPI1.ExceptionSpec, EPI2.ExceptionSpec, ExceptionTypeStorage, + getLangOpts().CPlusPlus17); Composite1 = Context.getFunctionType(FPT1->getReturnType(), FPT1->getParamTypes(), EPI1); @@ -7091,7 +7111,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, Steps[I].Quals.addConst(); // Rebuild the composite type. - QualType Composite = Composite1; + QualType Composite = Context.getCommonSugaredType(Composite1, Composite2); for (auto &S : llvm::reverse(Steps)) Composite = S.rebuild(Context, Composite); @@ -7308,8 +7328,8 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) { if (!Cleanup.exprNeedsCleanups()) return SubExpr; - auto Cleanups = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup, - ExprCleanupObjects.size() - FirstCleanup); + auto Cleanups = llvm::ArrayRef(ExprCleanupObjects.begin() + FirstCleanup, + ExprCleanupObjects.size() - FirstCleanup); auto *E = ExprWithCleanups::Create( Context, SubExpr, Cleanup.cleanupsHaveSideEffects(), Cleanups); @@ -7381,7 +7401,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { return BinaryOperator::Create(Context, BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(), BO->getObjectKind(), BO->getOperatorLoc(), - BO->getFPFeatures(getLangOpts())); + BO->getFPFeatures()); } } @@ -7713,8 +7733,8 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, // designated by the pseudo-destructor-name shall be the same type. if (DestructedTypeInfo) { QualType DestructedType = DestructedTypeInfo->getType(); - SourceLocation DestructedTypeStart - = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); + SourceLocation DestructedTypeStart = + DestructedTypeInfo->getTypeLoc().getBeginLoc(); if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) { if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { // Detect dot pseudo destructor calls on pointer objects, e.g.: @@ -7739,7 +7759,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, } else { Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) << ObjectType << DestructedType << Base->getSourceRange() - << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); + << DestructedTypeInfo->getTypeLoc().getSourceRange(); // Recover by setting the destructed type to the object type. DestructedType = ObjectType; @@ -7755,8 +7775,8 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, // type. } else { Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals) - << ObjectType << DestructedType << Base->getSourceRange() - << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); + << ObjectType << DestructedType << Base->getSourceRange() + << DestructedTypeInfo->getTypeLoc().getSourceRange(); } // Recover by setting the destructed type to the object type. @@ -7780,10 +7800,10 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(ScopeType, ObjectType)) { - Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(), + Diag(ScopeTypeInfo->getTypeLoc().getSourceRange().getBegin(), diag::err_pseudo_dtor_type_mismatch) - << ObjectType << ScopeType << Base->getSourceRange() - << ScopeTypeInfo->getTypeLoc().getLocalSourceRange(); + << ObjectType << ScopeType << Base->getSourceRange() + << ScopeTypeInfo->getTypeLoc().getSourceRange(); ScopeType = QualType(); ScopeTypeInfo = nullptr; @@ -8254,7 +8274,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( // All the potentially captureable variables in the current nested // lambda (within a generic outer lambda), must be captured by an // outer lambda that is enclosed within a non-dependent context. - CurrentLSI->visitPotentialCaptures([&] (VarDecl *Var, Expr *VarExpr) { + CurrentLSI->visitPotentialCaptures([&](ValueDecl *Var, Expr *VarExpr) { // If the variable is clearly identified as non-odr-used and the full // expression is not instantiation dependent, only then do we not // need to check enclosing lambda's for speculative captures. @@ -8270,14 +8290,18 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( !IsFullExprInstantiationDependent) return; + VarDecl *UnderlyingVar = Var->getPotentiallyDecomposedVarDecl(); + if (!UnderlyingVar) + return; + // If we have a capture-capable lambda for the variable, go ahead and // capture the variable in that lambda (and all its enclosing lambdas). - if (const Optional<unsigned> Index = + if (const std::optional<unsigned> Index = getStackIndexOfNearestEnclosingCaptureCapableLambda( S.FunctionScopes, Var, S)) S.MarkCaptureUsedInEnclosingContext(Var, VarExpr->getExprLoc(), *Index); const bool IsVarNeverAConstantExpression = - VariableCanNeverBeAConstantExpression(Var, S.Context); + VariableCanNeverBeAConstantExpression(UnderlyingVar, S.Context); if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) { // This full expression is not instantiation dependent or the variable // can not be used in a constant expression - which means @@ -8305,7 +8329,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( if (CurrentLSI->hasPotentialThisCapture()) { // If we have a capture-capable lambda for 'this', go ahead and capture // 'this' in that lambda (and all its enclosing lambdas). - if (const Optional<unsigned> Index = + if (const std::optional<unsigned> Index = getStackIndexOfNearestEnclosingCaptureCapableLambda( S.FunctionScopes, /*0 is 'this'*/ nullptr, S)) { const unsigned FunctionScopeIndexOfCapturableLambda = *Index; @@ -8448,7 +8472,7 @@ class TransformTypos : public TreeTransform<TransformTypos> { /// /// Returns true if there are any untried correction combinations. bool CheckAndAdvanceTypoExprCorrectionStreams() { - for (auto TE : TypoExprs) { + for (auto *TE : TypoExprs) { auto &State = SemaRef.getTypoExprState(TE); TransformCache.erase(TE); if (!State.Consumer->hasMadeAnyCorrectionProgress()) @@ -8470,7 +8494,7 @@ class TransformTypos : public TreeTransform<TransformTypos> { return DRE->getFoundDecl(); if (auto *ME = dyn_cast<MemberExpr>(E)) return ME->getFoundDecl(); - // FIXME: Add any other expr types that could be be seen by the delayed typo + // FIXME: Add any other expr types that could be seen by the delayed typo // correction TreeTransform for which the corresponding TypoCorrection could // contain multiple decls. return nullptr; @@ -8515,7 +8539,7 @@ class TransformTypos : public TreeTransform<TransformTypos> { // TypoExprs were created recursively and thus won't be in our // Sema's TypoExprs - they were created in our `RecursiveTransformLoop`. auto &SemaTypoExprs = SemaRef.TypoExprs; - for (auto TE : TypoExprs) { + for (auto *TE : TypoExprs) { TransformCache.erase(TE); SemaRef.clearDelayedTypo(TE); @@ -8744,14 +8768,14 @@ Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, } ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, - bool DiscardedValue, - bool IsConstexpr) { + bool DiscardedValue, bool IsConstexpr, + bool IsTemplateArgument) { ExprResult FullExpr = FE; if (!FullExpr.get()) return ExprError(); - if (DiagnoseUnexpandedParameterPack(FullExpr.get())) + if (!IsTemplateArgument && DiagnoseUnexpandedParameterPack(FullExpr.get())) return ExprError(); if (DiscardedValue) { @@ -8998,13 +9022,14 @@ Sema::BuildExprRequirement( Context.getReferenceQualifiedType(E).getCanonicalType(); llvm::SmallVector<TemplateArgument, 1> Args; Args.push_back(TemplateArgument(MatchedType)); + + auto *Param = cast<TemplateTypeParmDecl>(TPL->getParam(0)); + TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args); - MultiLevelTemplateArgumentList MLTAL(TAL); - for (unsigned I = 0; I < TPL->getDepth(); ++I) - MLTAL.addOuterRetainedLevel(); - Expr *IDC = - cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint() - ->getImmediatelyDeclaredConstraint(); + MultiLevelTemplateArgumentList MLTAL(Param, TAL.asArray(), + /*Final=*/false); + MLTAL.addOuterRetainedLevels(TPL->getDepth()); + Expr *IDC = Param->getTypeConstraint()->getImmediatelyDeclaredConstraint(); ExprResult Constraint = SubstExpr(IDC, MLTAL); if (Constraint.isInvalid()) { Status = concepts::ExprRequirement::SS_ExprSubstitutionFailure; @@ -9057,9 +9082,11 @@ Sema::BuildNestedRequirement(Expr *Constraint) { } concepts::NestedRequirement * -Sema::BuildNestedRequirement( - concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { - return new (Context) concepts::NestedRequirement(SubstDiag); +Sema::BuildNestedRequirement(StringRef InvalidConstraintEntity, + const ASTConstraintSatisfaction &Satisfaction) { + return new (Context) concepts::NestedRequirement( + InvalidConstraintEntity, + ASTConstraintSatisfaction::Rebuild(Context, Satisfaction)); } RequiresExprBodyDecl * diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index c9d9ef31f3ee..a3420ac6fdd2 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -249,7 +249,7 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr( case IMA_Field_Uneval_Context: Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use) << R.getLookupNameInfo().getName(); - LLVM_FALLTHROUGH; + [[fallthrough]]; case IMA_Static: case IMA_Abstract: case IMA_Mixed_StaticContext: @@ -1161,10 +1161,10 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, if (!Var->getTemplateSpecializationKind()) Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, MemberLoc); - return BuildMemberExpr( - BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, FoundDecl, - /*HadMultipleCandidates=*/false, MemberNameInfo, - Var->getType().getNonReferenceType(), VK_LValue, OK_Ordinary); + return BuildMemberExpr(BaseExpr, IsArrow, OpLoc, &SS, TemplateKWLoc, Var, + FoundDecl, /*HadMultipleCandidates=*/false, + MemberNameInfo, Var->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary, TemplateArgs); } // We found something that we didn't expect. Complain. @@ -1621,16 +1621,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (BaseType->isExtVectorType()) { // FIXME: this expr should store IsArrow. IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - ExprValueKind VK; - if (IsArrow) - VK = VK_LValue; - else { - if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(BaseExpr.get())) - VK = POE->getSyntacticForm()->getValueKind(); - else - VK = BaseExpr.get()->getValueKind(); - } - + ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind()); QualType ret = CheckExtVectorComponent(S, BaseType, VK, OpLoc, Member, MemberLoc); if (ret.isNull()) @@ -1903,6 +1894,14 @@ Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS, if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); baseExpr = BuildCXXThisExpr(loc, ThisTy, /*IsImplicit=*/true); + if (getLangOpts().HLSL && ThisTy.getTypePtr()->isPointerType()) { + ThisTy = ThisTy.getTypePtr()->getPointeeType(); + return BuildMemberReferenceExpr(baseExpr, ThisTy, + /*OpLoc*/ SourceLocation(), + /*IsArrow*/ false, SS, TemplateKWLoc, + /*FirstQualifierInScope*/ nullptr, R, + TemplateArgs, S); + } } return BuildMemberReferenceExpr(baseExpr, ThisTy, diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index a6c92d1a338d..a4372349fff7 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -27,10 +27,11 @@ #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ConvertUTF.h" +#include <optional> using namespace clang; using namespace sema; -using llvm::makeArrayRef; +using llvm::ArrayRef; ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef<Expr *> Strings) { @@ -243,7 +244,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, QualType NumberType, bool isLiteral = false, SourceRange R = SourceRange()) { - Optional<NSAPI::NSNumberLiteralMethodKind> Kind = + std::optional<NSAPI::NSNumberLiteralMethodKind> Kind = S.NSAPIObj->getNSNumberFactoryMethodKind(NumberType); if (!Kind) { @@ -298,7 +299,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, &CX.Idents.get("value"), NumberType, /*TInfo=*/nullptr, SC_None, nullptr); - Method->setMethodParams(S.Context, value, None); + Method->setMethodParams(S.Context, value, std::nullopt); } if (!validateBoxingMethod(S, Loc, S.NSNumberDecl, Sel, Method)) @@ -577,7 +578,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { Context.getPointerType(ConstCharType), /*TInfo=*/nullptr, SC_None, nullptr); - M->setMethodParams(Context, value, None); + M->setMethodParams(Context, value, std::nullopt); BoxingMethod = M; } @@ -591,8 +592,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { BoxingMethod = StringWithUTF8StringMethod; BoxedType = NSStringPointer; // Transfer the nullability from method's return type. - Optional<NullabilityKind> Nullability = - BoxingMethod->getReturnType()->getNullability(Context); + std::optional<NullabilityKind> Nullability = + BoxingMethod->getReturnType()->getNullability(); if (Nullability) BoxedType = Context.getAttributedType( AttributedType::getNullabilityAttrKind(*Nullability), BoxedType, @@ -705,7 +706,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { SC_None, nullptr); Params.push_back(type); - M->setMethodParams(Context, Params, None); + M->setMethodParams(Context, Params, std::nullopt); BoxingMethod = M; } @@ -833,7 +834,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { /*TInfo=*/nullptr, SC_None, nullptr); Params.push_back(cnt); - Method->setMethodParams(Context, Params, None); + Method->setMethodParams(Context, Params, std::nullopt); } if (!validateBoxingMethod(*this, Loc, NSArrayDecl, Sel, Method)) @@ -1003,7 +1004,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, /*TInfo=*/nullptr, SC_None, nullptr); Params.push_back(cnt); - Method->setMethodParams(Context, Params, None); + Method->setMethodParams(Context, Params, std::nullopt); } if (!validateBoxingMethod(*this, SR.getBegin(), NSDictionaryDecl, Sel, @@ -1037,12 +1038,9 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, if (ObjCProtocolDecl *NSCopyingPDecl = LookupProtocol(&Context.Idents.get("NSCopying"), SR.getBegin())) { ObjCProtocolDecl *PQ[] = {NSCopyingPDecl}; - QIDNSCopying = - Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { }, - llvm::makeArrayRef( - (ObjCProtocolDecl**) PQ, - 1), - false); + QIDNSCopying = Context.getObjCObjectType( + Context.ObjCBuiltinIdTy, {}, + llvm::ArrayRef((ObjCProtocolDecl **)PQ, 1), false); QIDNSCopying = Context.getObjCObjectPointerType(QIDNSCopying); } } @@ -1466,8 +1464,8 @@ static QualType getBaseMessageSendResultType(Sema &S, // result type to the returned result. auto transferNullability = [&](QualType type) -> QualType { // If the method's result type has nullability, extract it. - if (auto nullability = Method->getSendResultType(ReceiverType) - ->getNullability(Context)){ + if (auto nullability = + Method->getSendResultType(ReceiverType)->getNullability()) { // Strip off any outer nullability sugar from the provided type. (void)AttributedType::stripOuterNullability(type); @@ -1546,7 +1544,7 @@ QualType Sema::getMessageSendResultType(const Expr *Receiver, assert(MD->isClassMethod() && "expected a class method"); QualType NewResultType = Context.getObjCObjectPointerType( Context.getObjCInterfaceType(MD->getClassInterface())); - if (auto Nullability = resultType->getNullability(Context)) + if (auto Nullability = resultType->getNullability()) NewResultType = Context.getAttributedType( AttributedType::getNullabilityAttrKind(*Nullability), NewResultType, NewResultType); @@ -1563,16 +1561,16 @@ QualType Sema::getMessageSendResultType(const Expr *Receiver, // Map the nullability of the result into a table index. unsigned receiverNullabilityIdx = 0; - if (Optional<NullabilityKind> nullability = - ReceiverType->getNullability(Context)) { + if (std::optional<NullabilityKind> nullability = + ReceiverType->getNullability()) { if (*nullability == NullabilityKind::NullableResult) nullability = NullabilityKind::Nullable; receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability); } unsigned resultNullabilityIdx = 0; - if (Optional<NullabilityKind> nullability = - resultType->getNullability(Context)) { + if (std::optional<NullabilityKind> nullability = + resultType->getNullability()) { if (*nullability == NullabilityKind::NullableResult) nullability = NullabilityKind::Nullable; resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability); @@ -1605,7 +1603,7 @@ QualType Sema::getMessageSendResultType(const Expr *Receiver, } else { resultType = resultType.getDesugaredType(Context); } - } while (resultType->getNullability(Context)); + } while (resultType->getNullability()); // Add nullability back if needed. if (newResultNullabilityIdx > 0) { @@ -1808,8 +1806,8 @@ bool Sema::CheckMessageArgumentTypes( // Compute the set of type arguments to be substituted into each parameter // type. - Optional<ArrayRef<QualType>> typeArgs - = ReceiverType->getObjCSubstitutions(Method->getDeclContext()); + std::optional<ArrayRef<QualType>> typeArgs = + ReceiverType->getObjCSubstitutions(Method->getDeclContext()); bool IsError = false; for (unsigned i = 0; i < NumNamedArgs; i++) { // We can't do any type-checking on a type-dependent argument. @@ -1909,8 +1907,8 @@ bool Sema::CheckMessageArgumentTypes( DiagnoseSentinelCalls(Method, SelLoc, Args); // Do additional checkings on method. - IsError |= CheckObjCMethodCall( - Method, SelLoc, makeArrayRef(Args.data(), Args.size())); + IsError |= + CheckObjCMethodCall(Method, SelLoc, ArrayRef(Args.data(), Args.size())); return IsError; } @@ -2633,10 +2631,10 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, unsigned NumArgs = ArgsIn.size(); Expr **Args = ArgsIn.data(); assert(SuperLoc.isInvalid() && "Message to super with dependent type"); - return ObjCMessageExpr::Create( - Context, ReceiverType, VK_PRValue, LBracLoc, ReceiverTypeInfo, Sel, - SelectorLocs, /*Method=*/nullptr, makeArrayRef(Args, NumArgs), RBracLoc, - isImplicit); + return ObjCMessageExpr::Create(Context, ReceiverType, VK_PRValue, LBracLoc, + ReceiverTypeInfo, Sel, SelectorLocs, + /*Method=*/nullptr, ArrayRef(Args, NumArgs), + RBracLoc, isImplicit); } // Find the class to which we are sending this message. @@ -2735,21 +2733,19 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, // Construct the appropriate ObjCMessageExpr. ObjCMessageExpr *Result; if (SuperLoc.isValid()) - Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - SuperLoc, /*IsInstanceSuper=*/false, - ReceiverType, Sel, SelectorLocs, - Method, makeArrayRef(Args, NumArgs), - RBracLoc, isImplicit); + Result = ObjCMessageExpr::Create( + Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/false, + ReceiverType, Sel, SelectorLocs, Method, ArrayRef(Args, NumArgs), + RBracLoc, isImplicit); else { - Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - ReceiverTypeInfo, Sel, SelectorLocs, - Method, makeArrayRef(Args, NumArgs), - RBracLoc, isImplicit); + Result = ObjCMessageExpr::Create( + Context, ReturnType, VK, LBracLoc, ReceiverTypeInfo, Sel, SelectorLocs, + Method, ArrayRef(Args, NumArgs), RBracLoc, isImplicit); if (!isImplicit) checkCocoaAPI(*this, Result); } if (Method) - checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs), + checkFoundationAPI(*this, SelLoc, Method, ArrayRef(Args, NumArgs), ReceiverType, /*IsClassObjectCall=*/true); return MaybeBindToTemporary(Result); } @@ -2888,8 +2884,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return ObjCMessageExpr::Create( Context, Context.DependentTy, VK_PRValue, LBracLoc, Receiver, Sel, - SelectorLocs, /*Method=*/nullptr, makeArrayRef(Args, NumArgs), - RBracLoc, isImplicit); + SelectorLocs, /*Method=*/nullptr, ArrayRef(Args, NumArgs), RBracLoc, + isImplicit); } // If necessary, apply function/array conversion to the receiver. @@ -3326,16 +3322,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // Construct the appropriate ObjCMessageExpr instance. ObjCMessageExpr *Result; if (SuperLoc.isValid()) - Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - SuperLoc, /*IsInstanceSuper=*/true, - ReceiverType, Sel, SelectorLocs, Method, - makeArrayRef(Args, NumArgs), RBracLoc, - isImplicit); + Result = ObjCMessageExpr::Create( + Context, ReturnType, VK, LBracLoc, SuperLoc, /*IsInstanceSuper=*/true, + ReceiverType, Sel, SelectorLocs, Method, ArrayRef(Args, NumArgs), + RBracLoc, isImplicit); else { - Result = ObjCMessageExpr::Create(Context, ReturnType, VK, LBracLoc, - Receiver, Sel, SelectorLocs, Method, - makeArrayRef(Args, NumArgs), RBracLoc, - isImplicit); + Result = ObjCMessageExpr::Create( + Context, ReturnType, VK, LBracLoc, Receiver, Sel, SelectorLocs, Method, + ArrayRef(Args, NumArgs), RBracLoc, isImplicit); if (!isImplicit) checkCocoaAPI(*this, Result); } @@ -3356,7 +3350,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } } } - checkFoundationAPI(*this, SelLoc, Method, makeArrayRef(Args, NumArgs), + checkFoundationAPI(*this, SelLoc, Method, ArrayRef(Args, NumArgs), ReceiverType, IsClassObjectCall); } @@ -3860,7 +3854,7 @@ static inline T *getObjCBridgeAttr(const TypedefType *TD) { static ObjCBridgeRelatedAttr *ObjCBridgeRelatedAttrFromType(QualType T, TypedefNameDecl *&TDNDecl) { - while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) { + while (const auto *TD = T->getAs<TypedefType>()) { TDNDecl = TD->getDecl(); if (ObjCBridgeRelatedAttr *ObjCBAttr = getObjCBridgeAttr<ObjCBridgeRelatedAttr>(TD)) @@ -4007,7 +4001,7 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr, bool &HadTheAttribute, bool warn) { QualType T = castExpr->getType(); HadTheAttribute = false; - while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) { + while (const auto *TD = T->getAs<TypedefType>()) { TypedefNameDecl *TDNDecl = TD->getDecl(); if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) { if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { @@ -4070,7 +4064,7 @@ static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr, bool &HadTheAttribute, bool warn) { QualType T = castType; HadTheAttribute = false; - while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr())) { + while (const auto *TD = T->getAs<TypedefType>()) { TypedefNameDecl *TDNDecl = TD->getDecl(); if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) { if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { @@ -4377,11 +4371,9 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc, Diag(RelatedClass->getBeginLoc(), diag::note_declared_at); Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - ExprResult msg = - BuildInstanceMessageImplicit(SrcExpr, SrcType, - InstanceMethod->getLocation(), - InstanceMethod->getSelector(), - InstanceMethod, None); + ExprResult msg = BuildInstanceMessageImplicit( + SrcExpr, SrcType, InstanceMethod->getLocation(), + InstanceMethod->getSelector(), InstanceMethod, std::nullopt); SrcExpr = msg.get(); } return true; diff --git a/clang/lib/Sema/SemaFixItUtils.cpp b/clang/lib/Sema/SemaFixItUtils.cpp index 2910a56f866b..2c85a5319430 100644 --- a/clang/lib/Sema/SemaFixItUtils.cpp +++ b/clang/lib/Sema/SemaFixItUtils.cpp @@ -124,7 +124,7 @@ bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr, // Check if the pointer to the argument needs to be passed: // (type -> type *) or (type & -> type *). - if (isa<PointerType>(ToQTy)) { + if (const auto *ToPtrTy = dyn_cast<PointerType>(ToQTy)) { bool CanConvert = false; OverloadFixItKind FixKind = OFIK_TakeAddress; @@ -132,6 +132,10 @@ bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr, if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary) return false; + // Do no take address of const pointer to get void* + if (isa<PointerType>(FromQTy) && ToPtrTy->isVoidPointerType()) + return false; + CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, S, Begin, VK_PRValue); if (CanConvert) { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp new file mode 100644 index 000000000000..cf82cc9bccdf --- /dev/null +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -0,0 +1,34 @@ +//===- SemaHLSL.cpp - Semantic Analysis for HLSL constructs ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// This implements Semantic Analysis for HLSL constructs. +//===----------------------------------------------------------------------===// + +#include "clang/Sema/Sema.h" + +using namespace clang; + +Decl *Sema::ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer, + SourceLocation KwLoc, IdentifierInfo *Ident, + SourceLocation IdentLoc, + SourceLocation LBrace) { + // For anonymous namespace, take the location of the left brace. + DeclContext *LexicalParent = getCurLexicalContext(); + HLSLBufferDecl *Result = HLSLBufferDecl::Create( + Context, LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace); + + PushOnScopeChains(Result, BufferScope); + PushDeclContext(BufferScope, Result); + + return Result; +} + +void Sema::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) { + auto *BufDecl = cast<HLSLBufferDecl>(Dcl); + BufDecl->setRBraceLoc(RBrace); + PopDeclContext(); +} diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index d3b454843234..ddb2b5cf5cd1 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -81,12 +81,22 @@ static StringInitFailureKind IsStringInit(Expr *Init, const ArrayType *AT, const QualType ElemTy = Context.getCanonicalType(AT->getElementType()).getUnqualifiedType(); + auto IsCharOrUnsignedChar = [](const QualType &T) { + const BuiltinType *BT = dyn_cast<BuiltinType>(T.getTypePtr()); + return BT && BT->isCharType() && BT->getKind() != BuiltinType::SChar; + }; + switch (SL->getKind()) { case StringLiteral::UTF8: // char8_t array can be initialized with a UTF-8 string. - if (ElemTy->isChar8Type()) + // - C++20 [dcl.init.string] (DR) + // Additionally, an array of char or unsigned char may be initialized + // by a UTF-8 string literal. + if (ElemTy->isChar8Type() || + (Context.getLangOpts().Char8 && + IsCharOrUnsignedChar(ElemTy.getCanonicalType()))) return SIF_None; - LLVM_FALLTHROUGH; + [[fallthrough]]; case StringLiteral::Ordinary: // char array can be initialized with a narrow string. // Only allow char x[] = "foo"; not char x[] = L"foo"; @@ -229,6 +239,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, if (StrLength > CAT->getSize().getZExtValue()) S.Diag(Str->getBeginLoc(), diag::err_initializer_string_for_char_array_too_long) + << CAT->getSize().getZExtValue() << StrLength << Str->getSourceRange(); } else { // C99 6.7.8p14. @@ -493,7 +504,7 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc, true); MultiExprArg SubInit; Expr *InitExpr; - InitListExpr DummyInitList(SemaRef.Context, Loc, None, Loc); + InitListExpr DummyInitList(SemaRef.Context, Loc, std::nullopt, Loc); // C++ [dcl.init.aggr]p7: // If there are fewer initializer-clauses in the list than there are @@ -512,8 +523,10 @@ ExprResult InitListChecker::PerformEmptyInit(SourceLocation Loc, // // Only do this if we're initializing a class type, to avoid filling in // the initializer list where possible. - InitExpr = VerifyOnly ? &DummyInitList : new (SemaRef.Context) - InitListExpr(SemaRef.Context, Loc, None, Loc); + InitExpr = VerifyOnly + ? &DummyInitList + : new (SemaRef.Context) + InitListExpr(SemaRef.Context, Loc, std::nullopt, Loc); InitExpr->setType(SemaRef.Context.VoidTy); SubInit = InitExpr; Kind = InitializationKind::CreateCopy(Loc, Loc); @@ -695,10 +708,10 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, // member of reference type uninitialized, the program is // ill-formed. SemaRef.Diag(Loc, diag::err_init_reference_member_uninitialized) - << Field->getType() - << ILE->getSyntacticForm()->getSourceRange(); - SemaRef.Diag(Field->getLocation(), - diag::note_uninit_reference_member); + << Field->getType() + << (ILE->isSyntacticForm() ? ILE : ILE->getSyntacticForm()) + ->getSourceRange(); + SemaRef.Diag(Field->getLocation(), diag::note_uninit_reference_member); } hadError = true; return; @@ -1518,8 +1531,8 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity, // As an extension, clang supports complex initializers, which initialize // a complex number component-wise. When an explicit initializer list for - // a complex number contains two two initializers, this extension kicks in: - // it exepcts the initializer list to contain two elements convertible to + // a complex number contains two initializers, this extension kicks in: + // it expects the initializer list to contain two elements convertible to // the element type of the complex type. The first element initializes // the real part, and the second element intitializes the imaginary part. @@ -2934,7 +2947,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Compute the type of the integer literals. QualType PromotedCharTy = CharTy; - if (CharTy->isPromotableIntegerType()) + if (Context.isPromotableIntegerType(CharTy)) PromotedCharTy = Context.getPromotedIntegerType(CharTy); unsigned PromotedCharTyWidth = Context.getTypeSize(PromotedCharTy); @@ -3110,10 +3123,8 @@ InitListExpr * InitListChecker::createInitListExpr(QualType CurrentObjectType, SourceRange InitRange, unsigned ExpectedNumInits) { - InitListExpr *Result - = new (SemaRef.Context) InitListExpr(SemaRef.Context, - InitRange.getBegin(), None, - InitRange.getEnd()); + InitListExpr *Result = new (SemaRef.Context) InitListExpr( + SemaRef.Context, InitRange.getBegin(), std::nullopt, InitRange.getEnd()); QualType ResultType = CurrentObjectType; if (!ResultType->isArrayType()) @@ -3519,6 +3530,7 @@ void InitializationSequence::Step::Destroy() { case SK_StdInitializerListConstructorCall: case SK_OCLSamplerInit: case SK_OCLZeroOpaqueType: + case SK_ParenthesizedListInit: break; case SK_ConversionSequence: @@ -3578,6 +3590,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_PlaceholderType: case FK_ExplicitConstructor: case FK_AddressOfUnaddressableFunction: + case FK_ParenthesizedListInitFailed: return false; case FK_ReferenceInitOverloadFailed: @@ -3813,6 +3826,13 @@ void InitializationSequence::AddOCLZeroOpaqueTypeStep(QualType T) { Steps.push_back(S); } +void InitializationSequence::AddParenthesizedListInitStep(QualType T) { + Step S; + S.Kind = SK_ParenthesizedListInit; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::RewrapReferenceInitList(QualType T, InitListExpr *Syntactic) { assert(Syntactic->getNumInits() == 1 && @@ -5227,7 +5247,7 @@ static void TryDefaultInitialization(Sema &S, // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); if (DestType->isRecordType() && S.getLangOpts().CPlusPlus) { - TryConstructorInitialization(S, Entity, Kind, None, DestType, + TryConstructorInitialization(S, Entity, Kind, std::nullopt, DestType, Entity.getType(), Sequence); return; } @@ -5250,6 +5270,208 @@ static void TryDefaultInitialization(Sema &S, } } +static void TryOrBuildParenListInitialization( + Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, + ArrayRef<Expr *> Args, InitializationSequence &Sequence, bool VerifyOnly, + ExprResult *Result = nullptr) { + unsigned ArgIndexToProcess = 0; + SmallVector<Expr *, 4> InitExprs; + QualType ResultType; + Expr *ArrayFiller = nullptr; + FieldDecl *InitializedFieldInUnion = nullptr; + + // Process entities (i.e. array members, base classes, or class fields) by + // adding an initialization expression to InitExprs for each entity to + // initialize. + auto ProcessEntities = [&](auto Range) -> bool { + bool IsUnionType = Entity.getType()->isUnionType(); + for (InitializedEntity SubEntity : Range) { + // Unions should only have one initializer expression. + // If there are more initializers than it will be caught when we check + // whether Index equals Args.size(). + if (ArgIndexToProcess == 1 && IsUnionType) + return true; + + bool IsMember = SubEntity.getKind() == InitializedEntity::EK_Member; + + // Unnamed bitfields should not be initialized at all, either with an arg + // or by default. + if (IsMember && cast<FieldDecl>(SubEntity.getDecl())->isUnnamedBitfield()) + continue; + + if (ArgIndexToProcess < Args.size()) { + // There are still expressions in Args that haven't been processed. + // Let's match them to the current entity to initialize. + Expr *E = Args[ArgIndexToProcess++]; + + // Incomplete array types indicate flexible array members. Do not allow + // paren list initializations of structs with these members, as GCC + // doesn't either. + if (IsMember) { + auto *FD = cast<FieldDecl>(SubEntity.getDecl()); + if (FD->getType()->isIncompleteArrayType()) { + if (!VerifyOnly) { + S.Diag(E->getBeginLoc(), diag::err_flexible_array_init) + << SourceRange(E->getBeginLoc(), E->getEndLoc()); + S.Diag(FD->getLocation(), diag::note_flexible_array_member) << FD; + } + Sequence.SetFailed( + InitializationSequence::FK_ParenthesizedListInitFailed); + return false; + } + } + + InitializationKind SubKind = InitializationKind::CreateForInit( + E->getExprLoc(), /*isDirectInit=*/false, E); + InitializationSequence SubSeq(S, SubEntity, SubKind, E); + + if (SubSeq.Failed()) { + if (!VerifyOnly) + SubSeq.Diagnose(S, SubEntity, SubKind, E); + else + Sequence.SetFailed( + InitializationSequence::FK_ParenthesizedListInitFailed); + + return false; + } + if (!VerifyOnly) { + ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, E); + InitExprs.push_back(ER.get()); + if (IsMember && IsUnionType) + InitializedFieldInUnion = cast<FieldDecl>(SubEntity.getDecl()); + } + } else { + // We've processed all of the args, but there are still entities that + // have to be initialized. + if (IsMember) { + // C++ [dcl.init]p17.6.2.2 + // The remaining elements are initialized with their default member + // initializers, if any + auto *FD = cast<FieldDecl>(SubEntity.getDecl()); + if (Expr *ICE = FD->getInClassInitializer(); ICE && !VerifyOnly) { + ExprResult DIE = S.BuildCXXDefaultInitExpr(FD->getLocation(), FD); + if (DIE.isInvalid()) + return false; + S.checkInitializerLifetime(SubEntity, DIE.get()); + InitExprs.push_back(DIE.get()); + continue; + }; + } + // Remaining class elements without default member initializers and + // array elements are value initialized: + // + // C++ [dcl.init]p17.6.2.2 + // The remaining elements...otherwise are value initialzed + // + // C++ [dcl.init]p17.5 + // if the destination type is an array, the object is initialized as + // . follows. Let x1, . . . , xk be the elements of the expression-list + // ...Let n denote the array size...the ith array element is...value- + // initialized for each k < i <= n. + InitializationKind SubKind = InitializationKind::CreateValue( + Kind.getLocation(), Kind.getLocation(), Kind.getLocation(), true); + InitializationSequence SubSeq(S, SubEntity, SubKind, std::nullopt); + if (SubSeq.Failed()) { + if (!VerifyOnly) + SubSeq.Diagnose(S, SubEntity, SubKind, std::nullopt); + return false; + } + if (!VerifyOnly) { + ExprResult ER = SubSeq.Perform(S, SubEntity, SubKind, std::nullopt); + if (SubEntity.getKind() == InitializedEntity::EK_ArrayElement) { + ArrayFiller = ER.get(); + return true; + } + InitExprs.push_back(ER.get()); + } + } + } + return true; + }; + + if (const ArrayType *AT = + S.getASTContext().getAsArrayType(Entity.getType())) { + + SmallVector<InitializedEntity, 4> ElementEntities; + uint64_t ArrayLength; + // C++ [dcl.init]p17.5 + // if the destination type is an array, the object is initialized as + // follows. Let x1, . . . , xk be the elements of the expression-list. If + // the destination type is an array of unknown bound, it is define as + // having k elements. + if (const ConstantArrayType *CAT = + S.getASTContext().getAsConstantArrayType(Entity.getType())) + ArrayLength = CAT->getSize().getZExtValue(); + else + ArrayLength = Args.size(); + + if (ArrayLength >= Args.size()) { + for (uint64_t I = 0; I < ArrayLength; ++I) + ElementEntities.push_back( + InitializedEntity::InitializeElement(S.getASTContext(), I, Entity)); + + if (!ProcessEntities(ElementEntities)) + return; + + ResultType = S.Context.getConstantArrayType( + AT->getElementType(), llvm::APInt(/*numBits=*/32, ArrayLength), + nullptr, ArrayType::Normal, 0); + } + } else if (auto *RT = Entity.getType()->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + + auto BaseRange = map_range(RD->bases(), [&S](auto &base) { + return InitializedEntity::InitializeBase(S.getASTContext(), &base, false); + }); + auto FieldRange = map_range(RD->fields(), [](auto *field) { + return InitializedEntity::InitializeMember(field); + }); + + if (!ProcessEntities(BaseRange)) + return; + + if (!ProcessEntities(FieldRange)) + return; + + ResultType = Entity.getType(); + } + + // Not all of the args have been processed, so there must've been more args + // then were required to initialize the element. + if (ArgIndexToProcess < Args.size()) { + Sequence.SetFailed(InitializationSequence::FK_ParenthesizedListInitFailed); + if (!VerifyOnly) { + QualType T = Entity.getType(); + int InitKind = T->isArrayType() ? 0 : T->isUnionType() ? 3 : 4; + SourceRange ExcessInitSR(Args[ArgIndexToProcess]->getBeginLoc(), + Args.back()->getEndLoc()); + S.Diag(Kind.getLocation(), diag::err_excess_initializers) + << InitKind << ExcessInitSR; + } + return; + } + + if (VerifyOnly) { + Sequence.setSequenceKind(InitializationSequence::NormalSequence); + Sequence.AddParenthesizedListInitStep(Entity.getType()); + } else if (Result) { + SourceRange SR = Kind.getParenOrBraceRange(); + auto *CPLIE = CXXParenListInitExpr::Create( + S.getASTContext(), InitExprs, ResultType, Args.size(), + Kind.getLocation(), SR.getBegin(), SR.getEnd()); + if (ArrayFiller) + CPLIE->setArrayFiller(ArrayFiller); + if (InitializedFieldInUnion) + CPLIE->setInitializedFieldInUnion(InitializedFieldInUnion); + *Result = CPLIE; + S.Diag(Kind.getLocation(), + diag::warn_cxx17_compat_aggregate_init_paren_list) + << Kind.getLocation() << SR << ResultType; + } + + return; +} + /// Attempt a user-defined conversion between two types (C++ [dcl.init]), /// which enumerates all conversion functions and performs overload resolution /// to select the best. @@ -5905,7 +6127,11 @@ void InitializationSequence::InitializeFrom(Sema &S, TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer), *this, TreatUnavailableAsInvalid); AddParenthesizedArrayInitStep(DestType); - } else if (DestAT->getElementType()->isCharType()) + } else if (S.getLangOpts().CPlusPlus20 && !TopLevelOfInitList && + Kind.getKind() == InitializationKind::IK_Direct) + TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this, + /*VerifyOnly=*/true); + else if (DestAT->getElementType()->isCharType()) SetFailed(FK_ArrayNeedsInitListOrStringLiteral); else if (IsWideCharCompatible(DestAT->getElementType(), Context)) SetFailed(FK_ArrayNeedsInitListOrWideStringLiteral); @@ -5952,18 +6178,53 @@ void InitializationSequence::InitializeFrom(Sema &S, if (Kind.getKind() == InitializationKind::IK_Direct || (Kind.getKind() == InitializationKind::IK_Copy && (Context.hasSameUnqualifiedType(SourceType, DestType) || - S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType)))) - TryConstructorInitialization(S, Entity, Kind, Args, - DestType, DestType, *this); - // - Otherwise (i.e., for the remaining copy-initialization cases), - // user-defined conversion sequences that can convert from the source - // type to the destination type or (when a conversion function is - // used) to a derived class thereof are enumerated as described in - // 13.3.1.4, and the best one is chosen through overload resolution - // (13.3). - else + S.IsDerivedFrom(Initializer->getBeginLoc(), SourceType, DestType)))) { + TryConstructorInitialization(S, Entity, Kind, Args, DestType, DestType, + *this); + + // We fall back to the "no matching constructor" path if the + // failed candidate set has functions other than the three default + // constructors. For example, conversion function. + if (const auto *RD = + dyn_cast<CXXRecordDecl>(DestType->getAs<RecordType>()->getDecl()); + // In general, we should call isCompleteType for RD to check its + // completeness, we don't call it here as it was already called in the + // above TryConstructorInitialization. + S.getLangOpts().CPlusPlus20 && RD && RD->hasDefinition() && + RD->isAggregate() && Failed() && + getFailureKind() == FK_ConstructorOverloadFailed) { + // Do not attempt paren list initialization if overload resolution + // resolves to a deleted function . + // + // We may reach this condition if we have a union wrapping a class with + // a non-trivial copy or move constructor and we call one of those two + // constructors. The union is an aggregate, but the matched constructor + // is implicitly deleted, so we need to prevent aggregate initialization + // (otherwise, it'll attempt aggregate initialization by initializing + // the first element with a reference to the union). + OverloadCandidateSet::iterator Best; + OverloadingResult OR = getFailedCandidateSet().BestViableFunction( + S, Kind.getLocation(), Best); + if (OR != OverloadingResult::OR_Deleted) { + // C++20 [dcl.init] 17.6.2.2: + // - Otherwise, if no constructor is viable, the destination type is + // an + // aggregate class, and the initializer is a parenthesized + // expression-list. + TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this, + /*VerifyOnly=*/true); + } + } + } else { + // - Otherwise (i.e., for the remaining copy-initialization cases), + // user-defined conversion sequences that can convert from the + // source type to the destination type or (when a conversion + // function is used) to a derived class thereof are enumerated as + // described in 13.3.1.4, and the best one is chosen through + // overload resolution (13.3). TryUserDefinedConversion(S, DestType, Kind, Initializer, *this, TopLevelOfInitList); + } return; } @@ -5977,7 +6238,7 @@ void InitializationSequence::InitializeFrom(Sema &S, !Context.hasSameUnqualifiedType(SourceType, DestType))) { llvm::SmallVector<Expr *> InitArgs; - for (auto Arg : Args) { + for (auto *Arg : Args) { if (Arg->getType()->isExtVectorType()) { const auto *VTy = Arg->getType()->castAs<ExtVectorType>(); unsigned Elm = VTy->getNumElements(); @@ -7085,11 +7346,11 @@ static void visitLifetimeBoundArguments(IndirectLocalPath &Path, Expr *Call, if (auto *CE = dyn_cast<CallExpr>(Call)) { Callee = CE->getDirectCallee(); - Args = llvm::makeArrayRef(CE->getArgs(), CE->getNumArgs()); + Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs()); } else { auto *CCE = cast<CXXConstructExpr>(Call); Callee = CCE->getConstructor(); - Args = llvm::makeArrayRef(CCE->getArgs(), CCE->getNumArgs()); + Args = llvm::ArrayRef(CCE->getArgs(), CCE->getNumArgs()); } if (!Callee) return; @@ -7572,7 +7833,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I, case IndirectLocalPathEntry::VarInit: if (cast<VarDecl>(Path[I].D)->isImplicit()) return SourceRange(); - LLVM_FALLTHROUGH; + [[fallthrough]]; case IndirectLocalPathEntry::DefaultInit: return Path[I].E->getSourceRange(); @@ -7586,15 +7847,15 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I, } static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) { - for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) { - if (It->Kind == IndirectLocalPathEntry::VarInit) + for (const auto &It : llvm::reverse(Path)) { + if (It.Kind == IndirectLocalPathEntry::VarInit) continue; - if (It->Kind == IndirectLocalPathEntry::AddressOf) + if (It.Kind == IndirectLocalPathEntry::AddressOf) continue; - if (It->Kind == IndirectLocalPathEntry::LifetimeBoundCall) + if (It.Kind == IndirectLocalPathEntry::LifetimeBoundCall) continue; - return It->Kind == IndirectLocalPathEntry::GslPointerInit || - It->Kind == IndirectLocalPathEntry::GslReferenceInit; + return It.Kind == IndirectLocalPathEntry::GslPointerInit || + It.Kind == IndirectLocalPathEntry::GslReferenceInit; } return false; } @@ -7846,7 +8107,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, break; // FIXME: We can't easily tell apart an init-capture from a nested // capture of an init-capture. - const VarDecl *VD = Elem.Capture->getCapturedVar(); + const ValueDecl *VD = Elem.Capture->getCapturedVar(); Diag(Elem.Capture->getLocation(), diag::note_lambda_capture_initializer) << VD << VD->isInitCapture() << Elem.Capture->isExplicit() << (Elem.Capture->getCaptureKind() == LCK_ByRef) << VD @@ -8053,19 +8314,29 @@ ExprResult InitializationSequence::Perform(Sema &S, return ExprError(); } if (!ZeroInitializationFixit.empty()) { - unsigned DiagID = diag::err_default_init_const; - if (Decl *D = Entity.getDecl()) - if (S.getLangOpts().MSVCCompat && D->hasAttr<SelectAnyAttr>()) - DiagID = diag::ext_default_init_const; + const Decl *D = Entity.getDecl(); + const auto *VD = dyn_cast_or_null<VarDecl>(D); + QualType DestType = Entity.getType(); // The initialization would have succeeded with this fixit. Since the fixit // is on the error, we need to build a valid AST in this case, so this isn't // handled in the Failed() branch above. - QualType DestType = Entity.getType(); - S.Diag(Kind.getLocation(), DiagID) - << DestType << (bool)DestType->getAs<RecordType>() - << FixItHint::CreateInsertion(ZeroInitializationFixitLoc, - ZeroInitializationFixit); + if (!DestType->isRecordType() && VD && VD->isConstexpr()) { + // Use a more useful diagnostic for constexpr variables. + S.Diag(Kind.getLocation(), diag::err_constexpr_var_requires_const_init) + << VD + << FixItHint::CreateInsertion(ZeroInitializationFixitLoc, + ZeroInitializationFixit); + } else { + unsigned DiagID = diag::err_default_init_const; + if (S.getLangOpts().MSVCCompat && D && D->hasAttr<SelectAnyAttr>()) + DiagID = diag::ext_default_init_const; + + S.Diag(Kind.getLocation(), DiagID) + << DestType << (bool)DestType->getAs<RecordType>() + << FixItHint::CreateInsertion(ZeroInitializationFixitLoc, + ZeroInitializationFixit); + } } if (getKind() == DependentSequence) { @@ -8213,6 +8484,7 @@ ExprResult InitializationSequence::Perform(Sema &S, case SK_ConstructorInitializationFromList: case SK_StdInitializerListConstructorCall: case SK_ZeroInitialization: + case SK_ParenthesizedListInit: break; } @@ -8739,7 +9011,7 @@ ExprResult InitializationSequence::Perform(Sema &S, << Step->Type << CurInit.get()->getType() << CurInit.get()->getSourceRange(); updateGNUCompoundLiteralRValue(CurInit.get()); - LLVM_FALLTHROUGH; + [[fallthrough]]; case SK_ArrayInit: // If the destination type is an incomplete array type, update the // type accordingly. @@ -8902,6 +9174,14 @@ ExprResult InitializationSequence::Perform(Sema &S, CurInit.get()->getValueKind()); break; } + case SK_ParenthesizedListInit: { + CurInit = nullptr; + TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this, + /*VerifyOnly=*/false, &CurInit); + if (CurInit.get() && ResultType) + *ResultType = CurInit.get()->getType(); + break; + } } } @@ -9104,9 +9384,8 @@ bool InitializationSequence::Diagnose(Sema &S, << FixItHint::CreateInsertion(Args.front()->getBeginLoc(), "u8"); break; case FK_UTF8StringIntoPlainChar: - S.Diag(Kind.getLocation(), - diag::err_array_init_utf8_string_into_char) - << S.getLangOpts().CPlusPlus20; + S.Diag(Kind.getLocation(), diag::err_array_init_utf8_string_into_char) + << DestType->isSignedIntegerType() << S.getLangOpts().CPlusPlus20; break; case FK_ArrayTypeMismatch: case FK_NonConstantArrayInit: @@ -9201,7 +9480,7 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->getSourceRange(); break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case FK_NonConstLValueReferenceBindingToUnrelated: S.Diag(Kind.getLocation(), @@ -9464,6 +9743,10 @@ bool InitializationSequence::Diagnose(Sema &S, << Entity.getName(); S.Diag(Entity.getDecl()->getLocation(), diag::note_previous_decl) << Entity.getName(); + } else if (const auto *VD = dyn_cast_if_present<VarDecl>(Entity.getDecl()); + VD && VD->isConstexpr()) { + S.Diag(Kind.getLocation(), diag::err_constexpr_var_requires_const_init) + << VD; } else { S.Diag(Kind.getLocation(), diag::err_default_init_const) << DestType << (bool)DestType->getAs<RecordType>(); @@ -9500,6 +9783,11 @@ bool InitializationSequence::Diagnose(Sema &S, diag::note_explicit_ctor_deduction_guide_here) << false; break; } + + case FK_ParenthesizedListInitFailed: + TryOrBuildParenListInitialization(S, Entity, Kind, Args, *this, + /*VerifyOnly=*/false); + break; } PrintInitLocationNote(S, Entity); @@ -9666,6 +9954,10 @@ void InitializationSequence::dump(raw_ostream &OS) const { case FK_ExplicitConstructor: OS << "list copy initialization chose explicit constructor"; break; + + case FK_ParenthesizedListInitFailed: + OS << "parenthesized list initialization failed"; + break; } OS << '\n'; return; @@ -9837,6 +10129,9 @@ void InitializationSequence::dump(raw_ostream &OS) const { case SK_OCLZeroOpaqueType: OS << "OpenCL opaque type from zero"; break; + case SK_ParenthesizedListInit: + OS << "initialization from a parenthesized list of values"; + break; } OS << " [" << S->Type << ']'; @@ -9868,6 +10163,7 @@ static void DiagnoseNarrowingInInitList(Sema &S, SCS = &ICS.UserDefined.After; break; case ImplicitConversionSequence::AmbiguousConversion: + case ImplicitConversionSequence::StaticObjectArgumentConversion: case ImplicitConversionSequence::EllipsisConversion: case ImplicitConversionSequence::BadConversion: return; diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index afc2f3ef4d76..00ab6ba580bf 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -21,6 +21,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" #include "llvm/ADT/STLExtras.h" +#include <optional> using namespace clang; using namespace sema; @@ -54,17 +55,17 @@ using namespace sema; /// is at the top of the stack and has the highest index. /// \param VarToCapture - the variable to capture. If NULL, capture 'this'. /// -/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains -/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda -/// which is capture-ready. If the return value evaluates to 'false' then -/// no lambda is capture-ready for \p VarToCapture. +/// \returns An std::optional<unsigned> Index that if evaluates to 'true' +/// contains the index (into Sema's FunctionScopeInfo stack) of the innermost +/// lambda which is capture-ready. If the return value evaluates to 'false' +/// then no lambda is capture-ready for \p VarToCapture. -static inline Optional<unsigned> +static inline std::optional<unsigned> getStackIndexOfNearestEnclosingCaptureReadyLambda( ArrayRef<const clang::sema::FunctionScopeInfo *> FunctionScopes, - VarDecl *VarToCapture) { + ValueDecl *VarToCapture) { // Label failure to capture. - const Optional<unsigned> NoLambdaIsCaptureReady; + const std::optional<unsigned> NoLambdaIsCaptureReady; // Ignore all inner captured regions. unsigned CurScopeIndex = FunctionScopes.size() - 1; @@ -165,18 +166,19 @@ getStackIndexOfNearestEnclosingCaptureReadyLambda( /// \param VarToCapture - the variable to capture. If NULL, capture 'this'. /// /// -/// \returns An Optional<unsigned> Index that if evaluates to 'true' contains -/// the index (into Sema's FunctionScopeInfo stack) of the innermost lambda -/// which is capture-capable. If the return value evaluates to 'false' then -/// no lambda is capture-capable for \p VarToCapture. +/// \returns An std::optional<unsigned> Index that if evaluates to 'true' +/// contains the index (into Sema's FunctionScopeInfo stack) of the innermost +/// lambda which is capture-capable. If the return value evaluates to 'false' +/// then no lambda is capture-capable for \p VarToCapture. -Optional<unsigned> clang::getStackIndexOfNearestEnclosingCaptureCapableLambda( +std::optional<unsigned> +clang::getStackIndexOfNearestEnclosingCaptureCapableLambda( ArrayRef<const sema::FunctionScopeInfo *> FunctionScopes, - VarDecl *VarToCapture, Sema &S) { + ValueDecl *VarToCapture, Sema &S) { - const Optional<unsigned> NoLambdaIsCaptureCapable; + const std::optional<unsigned> NoLambdaIsCaptureCapable; - const Optional<unsigned> OptionalStackIndex = + const std::optional<unsigned> OptionalStackIndex = getStackIndexOfNearestEnclosingCaptureReadyLambda(FunctionScopes, VarToCapture); if (!OptionalStackIndex) @@ -282,7 +284,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { DataMember, StaticDataMember, InlineVariable, - VariableTemplate + VariableTemplate, + Concept } Kind = Normal; // Default arguments of member function parameters that appear in a class @@ -307,6 +310,8 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { } } else if (isa<FieldDecl>(ManglingContextDecl)) { Kind = DataMember; + } else if (isa<ImplicitConceptSpecializationDecl>(ManglingContextDecl)) { + Kind = Concept; } } @@ -330,12 +335,17 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { return std::make_tuple(nullptr, nullptr); } + case Concept: + // Concept definitions aren't code generated and thus aren't mangled, + // however the ManglingContextDecl is important for the purposes of + // re-forming the template argument list of the lambda for constraint + // evaluation. case StaticDataMember: // -- the initializers of nonspecialized static members of template classes if (!IsInNonspecializedTemplate) return std::make_tuple(nullptr, ManglingContextDecl); // Fall through to get the current context. - LLVM_FALLTHROUGH; + [[fallthrough]]; case DataMember: // -- the in-class initializers of class members @@ -354,13 +364,11 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) { llvm_unreachable("unexpected context"); } -CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, - SourceRange IntroducerRange, - TypeSourceInfo *MethodTypeInfo, - SourceLocation EndLoc, - ArrayRef<ParmVarDecl *> Params, - ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause) { +CXXMethodDecl *Sema::startLambdaDefinition( + CXXRecordDecl *Class, SourceRange IntroducerRange, + TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc, + ArrayRef<ParmVarDecl *> Params, ConstexprSpecKind ConstexprKind, + StorageClass SC, Expr *TrailingRequiresClause) { QualType MethodType = MethodTypeInfo->getType(); TemplateParameterList *TemplateParams = getGenericLambdaTemplateParameterList(getCurLambda(), *this); @@ -390,7 +398,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, Context, Class, EndLoc, DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), MethodNameLoc), - MethodType, MethodTypeInfo, SC_None, getCurFPFeatures().isFPConstrained(), + MethodType, MethodTypeInfo, SC, getCurFPFeatures().isFPConstrained(), /*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause); Method->setAccess(AS_public); if (!TemplateParams) @@ -418,7 +426,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false); - for (auto P : Method->parameters()) + for (auto *P : Method->parameters()) P->setOwningFunction(Method); } @@ -427,7 +435,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, void Sema::handleLambdaNumbering( CXXRecordDecl *Class, CXXMethodDecl *Method, - Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) { + std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling) { if (Mangling) { bool HasKnownInternalLinkage; unsigned ManglingNumber, DeviceManglingNumber; @@ -769,8 +777,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { if (Context.getCanonicalFunctionResultType(ReturnType) == Context.getCanonicalFunctionResultType(CSI.ReturnType)) { // Use the return type with the strictest possible nullability annotation. - auto RetTyNullability = ReturnType->getNullability(Ctx); - auto BlockNullability = CSI.ReturnType->getNullability(Ctx); + auto RetTyNullability = ReturnType->getNullability(); + auto BlockNullability = CSI.ReturnType->getNullability(); if (BlockNullability && (!RetTyNullability || hasWeakerNullability(*RetTyNullability, *BlockNullability))) @@ -789,8 +797,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { QualType Sema::buildLambdaInitCaptureInitialization( SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, - Optional<unsigned> NumExpansions, IdentifierInfo *Id, bool IsDirectInit, - Expr *&Init) { + std::optional<unsigned> NumExpansions, IdentifierInfo *Id, + bool IsDirectInit, Expr *&Init) { // Create an 'auto' or 'auto&' TypeSourceInfo that we can use to // deduce against. QualType DeductType = Context.getAutoDeductType(); @@ -881,11 +889,12 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc, return NewVD; } -void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var) { +void Sema::addInitCapture(LambdaScopeInfo *LSI, VarDecl *Var, + bool isReferenceType) { assert(Var->isInitCapture() && "init capture flag should be set"); - LSI->addCapture(Var, /*isBlock*/false, Var->getType()->isReferenceType(), - /*isNested*/false, Var->getLocation(), SourceLocation(), - Var->getType(), /*Invalid*/false); + LSI->addCapture(Var, /*isBlock*/ false, isReferenceType, + /*isNested*/ false, Var->getLocation(), SourceLocation(), + Var->getType(), /*Invalid*/ false); } void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, @@ -917,6 +926,15 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, bool ContainsUnexpandedParameterPack = false; SourceLocation EndLoc; SmallVector<ParmVarDecl *, 8> Params; + + assert( + (ParamInfo.getDeclSpec().getStorageClassSpec() == + DeclSpec::SCS_unspecified || + ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static) && + "Unexpected storage specifier"); + bool IsLambdaStatic = + ParamInfo.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static; + if (ParamInfo.getNumTypeObjects() == 0) { // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a lambda-declarator, it is as @@ -938,8 +956,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, QualType DefaultTypeForNoTrailingReturn = getLangOpts().CPlusPlus14 ? Context.getAutoDeductType() : Context.DependentTy; - QualType MethodTy = - Context.getFunctionType(DefaultTypeForNoTrailingReturn, None, EPI); + QualType MethodTy = Context.getFunctionType(DefaultTypeForNoTrailingReturn, + std::nullopt, EPI); MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy); ExplicitParams = false; ExplicitResultType = false; @@ -953,7 +971,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // This function call operator is declared const (9.3.1) if and only if // the lambda-expression's parameter-declaration-clause is not followed // by mutable. It is neither virtual nor declared volatile. [...] - if (!FTI.hasMutableQualifier()) { + if (!FTI.hasMutableQualifier() && !IsLambdaStatic) { FTI.getOrCreateMethodQualifiers().SetTypeQual(DeclSpec::TQ_const, SourceLocation()); } @@ -964,6 +982,18 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, ExplicitResultType = FTI.hasTrailingReturnType(); + if (ExplicitResultType && getLangOpts().HLSL) { + QualType RetTy = FTI.getTrailingReturnType().get(); + if (!RetTy.isNull()) { + // HLSL does not support specifying an address space on a lambda return + // type. + LangAS AddressSpace = RetTy.getAddressSpace(); + if (AddressSpace != LangAS::Default) + Diag(FTI.getTrailingReturnTypeLoc(), + diag::err_return_value_with_address_space); + } + } + if (FTIHasNonVoidParameters(FTI)) { Params.reserve(FTI.NumParams); for (unsigned i = 0, e = FTI.NumParams; i != e; ++i) @@ -981,6 +1011,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params, ParamInfo.getDeclSpec().getConstexprSpecifier(), + IsLambdaStatic ? SC_Static : SC_None, ParamInfo.getTrailingRequiresClause()); if (ExplicitParams) CheckCXXDefaultArguments(Method); @@ -1088,7 +1119,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (C->Init.isInvalid()) continue; - VarDecl *Var = nullptr; + ValueDecl *Var = nullptr; if (C->Init.isUsable()) { Diag(C->Loc, getLangOpts().CPlusPlus14 ? diag::warn_cxx11_compat_init_capture @@ -1166,7 +1197,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } - Var = R.getAsSingle<VarDecl>(); + if (auto *BD = R.getAsSingle<BindingDecl>()) + Var = BD; + else + Var = R.getAsSingle<VarDecl>(); if (Var && DiagnoseUseOfDecl(Var, C->Loc)) continue; } @@ -1200,7 +1234,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (Var->isInvalidDecl()) continue; - if (!Var->hasLocalStorage()) { + VarDecl *Underlying = Var->getPotentiallyDecomposedVarDecl(); + + if (!Underlying->hasLocalStorage()) { Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id; Diag(Var->getLocation(), diag::note_previous_decl) << C->Id; continue; @@ -1224,7 +1260,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, } if (C->Init.isUsable()) { - addInitCapture(LSI, Var); + addInitCapture(LSI, cast<VarDecl>(Var), C->Kind == LCK_ByRef); } else { TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef : TryCapture_ExplicitByVal; @@ -1374,7 +1410,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, ConvExtInfo.TypeQuals.addConst(); ConvExtInfo.ExceptionSpec.Type = EST_BasicNoexcept; QualType ConvTy = - S.Context.getFunctionType(PtrToFunctionTy, None, ConvExtInfo); + S.Context.getFunctionType(PtrToFunctionTy, std::nullopt, ConvExtInfo); SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName ConversionName @@ -1470,45 +1506,50 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, Class->addDecl(ConversionTemplate); } else Class->addDecl(Conversion); - // Add a non-static member function that will be the result of - // the conversion with a certain unique ID. - DeclarationName InvokerName = &S.Context.Idents.get( - getLambdaStaticInvokerName()); - // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo() - // we should get a prebuilt TrivialTypeSourceInfo from Context - // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc - // then rewire the parameters accordingly, by hoisting up the InvokeParams - // loop below and then use its Params to set Invoke->setParams(...) below. - // This would avoid the 'const' qualifier of the calloperator from - // contaminating the type of the invoker, which is currently adjusted - // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the - // trailing return type of the invoker would require a visitor to rebuild - // the trailing return type and adjusting all back DeclRefExpr's to refer - // to the new static invoker parameters - not the call operator's. - CXXMethodDecl *Invoke = CXXMethodDecl::Create( - S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc), - InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static, - S.getCurFPFeatures().isFPConstrained(), - /*isInline=*/true, ConstexprSpecKind::Unspecified, - CallOperator->getBody()->getEndLoc()); - for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) - InvokerParams[I]->setOwningFunction(Invoke); - Invoke->setParams(InvokerParams); - Invoke->setAccess(AS_private); - Invoke->setImplicit(true); - if (Class->isGenericLambda()) { - FunctionTemplateDecl *TemplateCallOperator = - CallOperator->getDescribedFunctionTemplate(); - FunctionTemplateDecl *StaticInvokerTemplate = FunctionTemplateDecl::Create( - S.Context, Class, Loc, InvokerName, - TemplateCallOperator->getTemplateParameters(), - Invoke); - StaticInvokerTemplate->setAccess(AS_private); - StaticInvokerTemplate->setImplicit(true); - Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate); - Class->addDecl(StaticInvokerTemplate); - } else - Class->addDecl(Invoke); + + // If the lambda is not static, we need to add a static member + // function that will be the result of the conversion with a + // certain unique ID. + // When it is static we just return the static call operator instead. + if (CallOperator->isInstance()) { + DeclarationName InvokerName = + &S.Context.Idents.get(getLambdaStaticInvokerName()); + // FIXME: Instead of passing in the CallOperator->getTypeSourceInfo() + // we should get a prebuilt TrivialTypeSourceInfo from Context + // using FunctionTy & Loc and get its TypeLoc as a FunctionProtoTypeLoc + // then rewire the parameters accordingly, by hoisting up the InvokeParams + // loop below and then use its Params to set Invoke->setParams(...) below. + // This would avoid the 'const' qualifier of the calloperator from + // contaminating the type of the invoker, which is currently adjusted + // in SemaTemplateDeduction.cpp:DeduceTemplateArguments. Fixing the + // trailing return type of the invoker would require a visitor to rebuild + // the trailing return type and adjusting all back DeclRefExpr's to refer + // to the new static invoker parameters - not the call operator's. + CXXMethodDecl *Invoke = CXXMethodDecl::Create( + S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc), + InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static, + S.getCurFPFeatures().isFPConstrained(), + /*isInline=*/true, ConstexprSpecKind::Unspecified, + CallOperator->getBody()->getEndLoc()); + for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) + InvokerParams[I]->setOwningFunction(Invoke); + Invoke->setParams(InvokerParams); + Invoke->setAccess(AS_private); + Invoke->setImplicit(true); + if (Class->isGenericLambda()) { + FunctionTemplateDecl *TemplateCallOperator = + CallOperator->getDescribedFunctionTemplate(); + FunctionTemplateDecl *StaticInvokerTemplate = + FunctionTemplateDecl::Create( + S.Context, Class, Loc, InvokerName, + TemplateCallOperator->getTemplateParameters(), Invoke); + StaticInvokerTemplate->setAccess(AS_private); + StaticInvokerTemplate->setImplicit(true); + Invoke->setDescribedFunctionTemplate(StaticInvokerTemplate); + Class->addDecl(StaticInvokerTemplate); + } else + Class->addDecl(Invoke); + } } /// Add a lambda's conversion to function pointers, as described in @@ -1546,7 +1587,8 @@ static void addBlockPointerConversion(Sema &S, /*IsVariadic=*/false, /*IsCXXMethod=*/true)); ConversionEPI.TypeQuals = Qualifiers(); ConversionEPI.TypeQuals.addConst(); - QualType ConvTy = S.Context.getFunctionType(BlockPtrTy, None, ConversionEPI); + QualType ConvTy = + S.Context.getFunctionType(BlockPtrTy, std::nullopt, ConversionEPI); SourceLocation Loc = IntroducerRange.getBegin(); DeclarationName Name @@ -1574,7 +1616,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap, // An init-capture is initialized directly from its stored initializer. if (Cap.isInitCapture()) - return Cap.getVariable()->getInit(); + return cast<VarDecl>(Cap.getVariable())->getInit(); // For anything else, build an initialization expression. For an implicit // capture, the capture notionally happens at the capture-default, so use @@ -1605,7 +1647,7 @@ ExprResult Sema::BuildCaptureInit(const Capture &Cap, Init = This; } else { assert(Cap.isVariableCapture() && "unknown kind of capture"); - VarDecl *Var = Cap.getVariable(); + ValueDecl *Var = Cap.getVariable(); Name = Var->getIdentifier(); Init = BuildDeclarationNameExpr( CXXScopeSpec(), DeclarationNameInfo(Var->getDeclName(), Loc), Var); @@ -1654,7 +1696,7 @@ mapImplicitCaptureStyle(CapturingScopeInfo::ImplicitCaptureStyle ICS) { bool Sema::CaptureHasSideEffects(const Capture &From) { if (From.isInitCapture()) { - Expr *Init = From.getVariable()->getInit(); + Expr *Init = cast<VarDecl>(From.getVariable())->getInit(); if (Init && Init->HasSideEffects(Context)) return true; } @@ -1704,9 +1746,9 @@ FieldDecl *Sema::BuildCaptureField(RecordDecl *RD, TypeSourceInfo *TSI = nullptr; if (Capture.isVariableCapture()) { - auto *Var = Capture.getVariable(); - if (Var->isInitCapture()) - TSI = Capture.getVariable()->getTypeSourceInfo(); + const auto *Var = dyn_cast_or_null<VarDecl>(Capture.getVariable()); + if (Var && Var->isInitCapture()) + TSI = Var->getTypeSourceInfo(); } // FIXME: Should we really be doing this? A null TypeSourceInfo seems more @@ -1854,7 +1896,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, return LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType); } else { assert(From.isVariableCapture() && "unknown kind of capture"); - VarDecl *Var = From.getVariable(); + ValueDecl *Var = From.getVariable(); LambdaCaptureKind Kind = From.isCopyCapture() ? LCK_ByCopy : LCK_ByRef; return LambdaCapture(From.getLocation(), IsImplicit, Kind, Var, diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 68158ec977cf..b2e943699c5f 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -40,10 +40,12 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/edit_distance.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <iterator> #include <list> +#include <optional> #include <set> #include <utility> #include <vector> @@ -156,7 +158,7 @@ namespace { void addUsingDirectives(DeclContext *DC, DeclContext *EffectiveDC) { SmallVector<DeclContext*, 4> queue; while (true) { - for (auto UD : DC->using_directives()) { + for (auto *UD : DC->using_directives()) { DeclContext *NS = UD->getNominatedNamespace(); if (SemaRef.isVisible(UD) && visited.insert(NS).second) { addUsingDirective(UD, EffectiveDC); @@ -519,12 +521,13 @@ void LookupResult::resolveKind() { D = cast<NamedDecl>(D->getCanonicalDecl()); // Ignore an invalid declaration unless it's the only one left. - if (D->isInvalidDecl() && !(I == 0 && N == 1)) { + // Also ignore HLSLBufferDecl which not have name conflict with other Decls. + if ((D->isInvalidDecl() || isa<HLSLBufferDecl>(D)) && !(I == 0 && N == 1)) { Decls[I] = Decls[--N]; continue; } - llvm::Optional<unsigned> ExistingI; + std::optional<unsigned> ExistingI; // Redeclarations of types via typedef can occur both within a scope // and, through using declarations and directives, across scopes. There is @@ -939,11 +942,9 @@ bool Sema::LookupBuiltin(LookupResult &R) { // If this is a builtin on this (or all) targets, create the decl. if (unsigned BuiltinID = II->getBuiltinID()) { - // In C++, C2x, and OpenCL (spec v1.2 s6.9.f), we don't have any - // predefined library functions like 'malloc'. Instead, we'll just - // error. - if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL || - getLangOpts().C2x) && + // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined + // library functions like 'malloc'. Instead, we'll just error. + if ((getLangOpts().CPlusPlus || getLangOpts().OpenCL) && Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return false; @@ -1179,9 +1180,8 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo(); EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_C); EPI.ExceptionSpec = EST_None; - QualType ExpectedType - = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), - None, EPI); + QualType ExpectedType = R.getSema().Context.getFunctionType( + R.getLookupName().getCXXNameType(), std::nullopt, EPI); // Perform template argument deduction against the type that we would // expect the function to have. @@ -1624,10 +1624,8 @@ hasAcceptableDefaultArgument(Sema &S, const ParmDecl *D, if (!D->hasDefaultArgument()) return false; - llvm::SmallDenseSet<const ParmDecl *, 4> Visited; - while (D && !Visited.count(D)) { - Visited.insert(D); - + llvm::SmallPtrSet<const ParmDecl *, 4> Visited; + while (D && Visited.insert(D).second) { auto &DefaultArg = D->getDefaultArgStorage(); if (!DefaultArg.isInherited() && S.isAcceptable(D, Kind)) return true; @@ -1920,12 +1918,7 @@ bool LookupResult::isReachableSlow(Sema &SemaRef, NamedDecl *D) { // If D comes from a module and SemaRef doesn't own a module, it implies D // comes from another TU. In case SemaRef owns a module, we could judge if D // comes from another TU by comparing the module unit. - // - // FIXME: It would look better if we have direct method to judge whether D is - // in another TU. - if (SemaRef.getCurrentModule() && - SemaRef.getCurrentModule()->getTopLevelModule() == - DeclModule->getTopLevelModule()) + if (SemaRef.isModuleUnitOfCurrentTU(DeclModule)) return true; // [module.reach]/p3: @@ -2023,7 +2016,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D, unsigned IDNS) { assert(!LookupResult::isAvailableForLookup(SemaRef, D) && "not in slow case"); - for (auto RD : D->redecls()) { + for (auto *RD : D->redecls()) { // Don't bother with extra checks if we already know this one isn't visible. if (RD == D) continue; @@ -2107,6 +2100,22 @@ bool LookupResult::isAvailableForLookup(Sema &SemaRef, NamedDecl *ND) { if (auto *DeductionGuide = ND->getDeclName().getCXXDeductionGuideTemplate()) return SemaRef.hasReachableDefinition(DeductionGuide); + // FIXME: The lookup for allocation function is a standalone process. + // (We can find the logics in Sema::FindAllocationFunctions) + // + // Such structure makes it a problem when we instantiate a template + // declaration using placement allocation function if the placement + // allocation function is invisible. + // (See https://github.com/llvm/llvm-project/issues/59601) + // + // Here we workaround it by making the placement allocation functions + // always acceptable. The downside is that we can't diagnose the direct + // use of the invisible placement allocation functions. (Although such uses + // should be rare). + if (auto *FD = dyn_cast<FunctionDecl>(ND); + FD && FD->isReservedGlobalPlacementOperator()) + return true; + auto *DC = ND->getDeclContext(); // If ND is not visible and it is at namespace scope, it shouldn't be found // by name lookup. @@ -2367,7 +2376,7 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, continue; } - for (auto I : ND->using_directives()) { + for (auto *I : ND->using_directives()) { NamespaceDecl *Nom = I->getNominatedNamespace(); if (S.isVisible(I) && Visited.insert(Nom).second) Queue.push_back(Nom); @@ -3147,7 +3156,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { for (const auto &Arg : Proto->param_types()) Queue.push_back(Arg.getTypePtr()); // fallthrough - LLVM_FALLTHROUGH; + [[fallthrough]]; } case Type::FunctionNoProto: { const FunctionType *FnType = cast<FunctionType>(T); @@ -3477,27 +3486,27 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) AddMethodCandidate(M, Cand, RD, ThisTy, Classification, - llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + llvm::ArrayRef(&Arg, NumArgs), OCS, true); else if (CtorInfo) AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl, - llvm::makeArrayRef(&Arg, NumArgs), OCS, + llvm::ArrayRef(&Arg, NumArgs), OCS, /*SuppressUserConversions*/ true); else - AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS, + AddOverloadCandidate(M, Cand, llvm::ArrayRef(&Arg, NumArgs), OCS, /*SuppressUserConversions*/ true); } else if (FunctionTemplateDecl *Tmpl = dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) - AddMethodTemplateCandidate( - Tmpl, Cand, RD, nullptr, ThisTy, Classification, - llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + AddMethodTemplateCandidate(Tmpl, Cand, RD, nullptr, ThisTy, + Classification, + llvm::ArrayRef(&Arg, NumArgs), OCS, true); else if (CtorInfo) - AddTemplateOverloadCandidate( - CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr, - llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + AddTemplateOverloadCandidate(CtorInfo.ConstructorTmpl, + CtorInfo.FoundDecl, nullptr, + llvm::ArrayRef(&Arg, NumArgs), OCS, true); else - AddTemplateOverloadCandidate( - Tmpl, Cand, nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + AddTemplateOverloadCandidate(Tmpl, Cand, nullptr, + llvm::ArrayRef(&Arg, NumArgs), OCS, true); } else { assert(isa<UsingDecl>(Cand.getDecl()) && "illegal Kind of operator = Decl"); @@ -3620,9 +3629,10 @@ CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, /// /// \returns The destructor for this class. CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) { - return cast<CXXDestructorDecl>(LookupSpecialMember(Class, CXXDestructor, - false, false, false, - false, false).getMethod()); + return cast_or_null<CXXDestructorDecl>( + LookupSpecialMember(Class, CXXDestructor, false, false, false, false, + false) + .getMethod()); } /// LookupLiteralOperator - Determine which literal operator should be used for @@ -3696,11 +3706,11 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, // is a well-formed template argument for the template parameter. if (StringLit) { SFINAETrap Trap(*this); - SmallVector<TemplateArgument, 1> Checked; + SmallVector<TemplateArgument, 1> SugaredChecked, CanonicalChecked; TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit); - if (CheckTemplateArgument(Params->getParam(0), Arg, FD, - R.getNameLoc(), R.getNameLoc(), 0, - Checked) || + if (CheckTemplateArgument( + Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(), + 0, SugaredChecked, CanonicalChecked, CTAK_Specified) || Trap.hasErrorOccurred()) IsTemplate = false; } @@ -4166,7 +4176,7 @@ private: // Traverse using directives for qualified name lookup. if (QualifiedNameLookup) { ShadowContextRAII Shadow(Visited); - for (auto I : Ctx->using_directives()) { + for (auto *I : Ctx->using_directives()) { if (!Result.getSema().isVisible(I)) continue; lookupInDeclContext(I->getNominatedNamespace(), Result, @@ -4939,9 +4949,9 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( if (NNS && !CurNameSpecifierIdentifiers.empty()) { SmallVector<const IdentifierInfo*, 4> NewNameSpecifierIdentifiers; getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers); - NumSpecifiers = llvm::ComputeEditDistance( - llvm::makeArrayRef(CurNameSpecifierIdentifiers), - llvm::makeArrayRef(NewNameSpecifierIdentifiers)); + NumSpecifiers = + llvm::ComputeEditDistance(llvm::ArrayRef(CurNameSpecifierIdentifiers), + llvm::ArrayRef(NewNameSpecifierIdentifiers)); } SpecifierInfo SI = {Ctx, NNS, NumSpecifiers}; @@ -5028,9 +5038,8 @@ static void AddKeywordsToConsumer(Sema &SemaRef, "extern", "inline", "static", "typedef" }; - const unsigned NumCTypeSpecs = llvm::array_lengthof(CTypeSpecs); - for (unsigned I = 0; I != NumCTypeSpecs; ++I) - Consumer.addKeywordResult(CTypeSpecs[I]); + for (const auto *CTS : CTypeSpecs) + Consumer.addKeywordResult(CTS); if (SemaRef.getLangOpts().C99) Consumer.addKeywordResult("restrict"); @@ -5082,9 +5091,8 @@ static void AddKeywordsToConsumer(Sema &SemaRef, static const char *const CXXExprs[] = { "delete", "new", "operator", "throw", "typeid" }; - const unsigned NumCXXExprs = llvm::array_lengthof(CXXExprs); - for (unsigned I = 0; I != NumCXXExprs; ++I) - Consumer.addKeywordResult(CXXExprs[I]); + for (const auto *CE : CXXExprs) + Consumer.addKeywordResult(CE); if (isa<CXXMethodDecl>(SemaRef.CurContext) && cast<CXXMethodDecl>(SemaRef.CurContext)->isInstance()) @@ -5108,9 +5116,8 @@ static void AddKeywordsToConsumer(Sema &SemaRef, // Statements. static const char *const CStmts[] = { "do", "else", "for", "goto", "if", "return", "switch", "while" }; - const unsigned NumCStmts = llvm::array_lengthof(CStmts); - for (unsigned I = 0; I != NumCStmts; ++I) - Consumer.addKeywordResult(CStmts[I]); + for (const auto *CS : CStmts) + Consumer.addKeywordResult(CS); if (SemaRef.getLangOpts().CPlusPlus) { Consumer.addKeywordResult("catch"); @@ -5699,7 +5706,7 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, llvm::SmallVector<Module*, 8> UniqueModules; llvm::SmallDenseSet<Module*, 8> UniqueModuleSet; for (auto *M : Modules) { - if (M->Kind == Module::GlobalModuleFragment) + if (M->isGlobalModule() || M->isPrivateModule()) continue; if (UniqueModuleSet.insert(M).second) UniqueModules.push_back(M); diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index f5c24bd10daa..f52c0247f01c 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -15,6 +15,7 @@ #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/SemaInternal.h" +#include <optional> using namespace clang; using namespace sema; @@ -119,12 +120,12 @@ void Sema::HandleStartOfHeaderUnit() { // TODO: Make the C++20 header lookup independent. // When the input is pre-processed source, we need a file ref to the original // file for the header map. - auto F = SourceMgr.getFileManager().getFile(HUName); + auto F = SourceMgr.getFileManager().getOptionalFileRef(HUName); // For the sake of error recovery (if someone has moved the original header // after creating the pre-processed output) fall back to obtaining the file // ref for the input file, which must be present. if (!F) - F = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()); + F = SourceMgr.getFileEntryRefForID(SourceMgr.getMainFileID()); assert(F && "failed to find the header unit source?"); Module::Header H{HUName.str(), HUName.str(), *F}; auto &Map = PP.getHeaderSearchInfo().getModuleMap(); @@ -144,6 +145,36 @@ void Sema::HandleStartOfHeaderUnit() { TU->setLocalOwningModule(Mod); } +/// Tests whether the given identifier is reserved as a module name and +/// diagnoses if it is. Returns true if a diagnostic is emitted and false +/// otherwise. +static bool DiagReservedModuleName(Sema &S, const IdentifierInfo *II, + SourceLocation Loc) { + enum { + Valid = -1, + Invalid = 0, + Reserved = 1, + } Reason = Valid; + + if (II->isStr("module") || II->isStr("import")) + Reason = Invalid; + else if (II->isReserved(S.getLangOpts()) != + ReservedIdentifierStatus::NotReserved) + Reason = Reserved; + + // If the identifier is reserved (not invalid) but is in a system header, + // we do not diagnose (because we expect system headers to use reserved + // identifiers). + if (Reason == Reserved && S.getSourceManager().isInSystemHeader(Loc)) + Reason = Valid; + + if (Reason != Valid) { + S.Diag(Loc, diag::err_invalid_module_name) << II << (int)Reason; + return true; + } + return false; +} + Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, ModuleDeclKind MDK, ModuleIdPath Path, @@ -195,9 +226,8 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, Diag(ModuleLoc, diag::err_module_decl_in_module_map_module); return nullptr; - case LangOptions::CMK_HeaderModule: case LangOptions::CMK_HeaderUnit: - Diag(ModuleLoc, diag::err_module_decl_in_header_module); + Diag(ModuleLoc, diag::err_module_decl_in_header_unit); return nullptr; } @@ -207,22 +237,15 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, // here, in order to support macro import. // Only one module-declaration is permitted per source file. - if (!ModuleScopes.empty() && - ModuleScopes.back().Module->isModulePurview()) { + if (isCurrentModulePurview()) { Diag(ModuleLoc, diag::err_module_redeclaration); Diag(VisibleModules.getImportLoc(ModuleScopes.back().Module), diag::note_prev_module_declaration); return nullptr; } - // Find the global module fragment we're adopting into this module, if any. - Module *GlobalModuleFragment = nullptr; - if (!ModuleScopes.empty() && - ModuleScopes.back().Module->Kind == Module::GlobalModuleFragment) - GlobalModuleFragment = ModuleScopes.back().Module; - assert((!getLangOpts().CPlusPlusModules || getLangOpts().ModulesTS || - SeenGMF == (bool)GlobalModuleFragment) && + SeenGMF == (bool)this->GlobalModuleFragment) && "mismatched global module state"); // In C++20, the module-declaration must be the first declaration if there @@ -239,6 +262,32 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, } } + // C++2b [module.unit]p1: ... The identifiers module and import shall not + // appear as identifiers in a module-name or module-partition. All + // module-names either beginning with an identifier consisting of std + // followed by zero or more digits or containing a reserved identifier + // ([lex.name]) are reserved and shall not be specified in a + // module-declaration; no diagnostic is required. + + // Test the first part of the path to see if it's std[0-9]+ but allow the + // name in a system header. + StringRef FirstComponentName = Path[0].first->getName(); + if (!getSourceManager().isInSystemHeader(Path[0].second) && + (FirstComponentName == "std" || + (FirstComponentName.startswith("std") && + llvm::all_of(FirstComponentName.drop_front(3), &llvm::isDigit)))) { + Diag(Path[0].second, diag::err_invalid_module_name) + << Path[0].first << /*reserved*/ 1; + return nullptr; + } + + // Then test all of the components in the path to see if any of them are + // using another kind of reserved or invalid identifier. + for (auto Part : Path) { + if (DiagReservedModuleName(*this, Part.first, Part.second)) + return nullptr; + } + // Flatten the dots in a module name. Unlike Clang's hierarchical module map // modules, the dots here are just another character that can appear in a // module name. @@ -272,7 +321,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, Diag(Path[0].second, diag::err_module_redefinition) << ModuleName; if (M->DefinitionLoc.isValid()) Diag(M->DefinitionLoc, diag::note_prev_module_definition); - else if (Optional<FileEntryRef> FE = M->getASTFile()) + else if (OptionalFileEntryRef FE = M->getASTFile()) Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file) << FE->getName(); Mod = M; @@ -280,8 +329,7 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, } // Create a Module for the module that we're defining. - Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, - GlobalModuleFragment); + Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); if (MDK == ModuleDeclKind::PartitionInterface) Mod->Kind = Module::ModulePartitionInterface; assert(Mod && "module creation should not fail"); @@ -301,21 +349,19 @@ Sema::ActOnModuleDecl(SourceLocation StartLoc, SourceLocation ModuleLoc, if (!Mod) { Diag(ModuleLoc, diag::err_module_not_defined) << ModuleName; // Create an empty module interface unit for error recovery. - Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, - GlobalModuleFragment); + Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); } } break; case ModuleDeclKind::PartitionImplementation: // Create an interface, but note that it is an implementation // unit. - Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName, - GlobalModuleFragment); + Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); Mod->Kind = Module::ModulePartitionImplementation; break; } - if (!GlobalModuleFragment) { + if (!this->GlobalModuleFragment) { ModuleScopes.push_back({}); if (getLangOpts().ModulesLocalVisibility) ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); @@ -495,7 +541,7 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, // of the same top-level module. Until we do, make it an error rather than // silently ignoring the import. // FIXME: Should we warn on a redundant import of the current module? - if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule && + if (Mod->isForBuilding(getLangOpts()) && (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) { Diag(ImportLoc, getLangOpts().isCompilingModule() ? diag::err_module_self_import @@ -545,9 +591,6 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, (ModuleScopes.back().ModuleInterface || (getLangOpts().CPlusPlusModules && ModuleScopes.back().Module->isGlobalModule()))) { - assert((!ModuleScopes.back().Module->isGlobalModule() || - Mod->Kind == Module::ModuleKind::ModuleHeaderUnit) && - "should only be importing a header unit into the GMF"); // Re-export the module if the imported module is exported. // Note that we don't need to add re-exported module to Imports field // since `Exports` implies the module is imported already. @@ -562,11 +605,6 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, Diag(ExportLoc, diag::err_export_not_in_module_interface) << (!ModuleScopes.empty() && !ModuleScopes.back().ImplicitGlobalModuleFragment); - } else if (getLangOpts().isCompilingModule()) { - Module *ThisModule = PP.getHeaderSearchInfo().lookupModule( - getLangOpts().CurrentModule, ExportLoc, false, false); - (void)ThisModule; - assert(ThisModule && "was expecting a module if building one"); } // In some cases we need to know if an entity was present in a directly- @@ -717,7 +755,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, // An export-declaration shall appear only [...] in the purview of a module // interface unit. An export-declaration shall not appear directly or // indirectly within [...] a private-module-fragment. - if (ModuleScopes.empty() || !ModuleScopes.back().Module->isModulePurview()) { + if (!isCurrentModulePurview()) { Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0; D->setInvalidDecl(); return D; @@ -786,7 +824,7 @@ enum class UnnamedDeclKind { }; } -static llvm::Optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) { +static std::optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) { if (isa<EmptyDecl>(D)) return UnnamedDeclKind::Empty; if (isa<StaticAssertDecl>(D)) @@ -796,7 +834,7 @@ static llvm::Optional<UnnamedDeclKind> getUnnamedDeclKind(Decl *D) { if (isa<UsingDirectiveDecl>(D)) return UnnamedDeclKind::UsingDirective; // Everything else either introduces one or more names or is ill-formed. - return llvm::None; + return std::nullopt; } unsigned getUnnamedDeclDiag(UnnamedDeclKind UDK, bool InBlock) { @@ -911,6 +949,17 @@ Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) { diagExportedUnnamedDecl(*this, UnnamedDeclKind::Context, Child, BlockStart); } + if (auto *FD = dyn_cast<FunctionDecl>(Child)) { + // [dcl.inline]/7 + // If an inline function or variable that is attached to a named module + // is declared in a definition domain, it shall be defined in that + // domain. + // So, if the current declaration does not have a definition, we must + // check at the end of the TU (or when the PMF starts) to see that we + // have a definition at that point. + if (FD->isInlineSpecified() && !FD->isDefined()) + PendingInlineFuncDecls.insert(FD); + } } } diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 118afb81dd72..584c4a31793c 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1028,7 +1028,7 @@ static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop, // Find the corresponding property in the primary class definition. auto OrigClass = Category->getClassInterface(); - for (auto Found : OrigClass->lookup(Prop->getDeclName())) { + for (auto *Found : OrigClass->lookup(Prop->getDeclName())) { if (ObjCPropertyDecl *OrigProp = dyn_cast<ObjCPropertyDecl>(Found)) return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask; } @@ -1822,9 +1822,8 @@ CollectImmediateProperties(ObjCContainerDecl *CDecl, static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl, ObjCInterfaceDecl::PropertyMap &PropMap) { if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) { - ObjCInterfaceDecl::PropertyDeclOrder PO; while (SDecl) { - SDecl->collectPropertiesToImplement(PropMap, PO); + SDecl->collectPropertiesToImplement(PropMap); SDecl = SDecl->getSuperClass(); } } @@ -1889,15 +1888,14 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, ObjCInterfaceDecl *IDecl, SourceLocation AtEnd) { ObjCInterfaceDecl::PropertyMap PropMap; - ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder; - IDecl->collectPropertiesToImplement(PropMap, PropertyOrder); + IDecl->collectPropertiesToImplement(PropMap); if (PropMap.empty()) return; ObjCInterfaceDecl::PropertyMap SuperPropMap; CollectSuperClassPropertyImplementations(IDecl, SuperPropMap); - for (unsigned i = 0, e = PropertyOrder.size(); i != e; i++) { - ObjCPropertyDecl *Prop = PropertyOrder[i]; + for (const auto &PropEntry : PropMap) { + ObjCPropertyDecl *Prop = PropEntry.second; // Is there a matching property synthesize/dynamic? if (Prop->isInvalidDecl() || Prop->isClassProperty() || @@ -2046,8 +2044,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, // its primary class (and its super classes) if property is // declared in one of those containers. if ((IDecl = C->getClassInterface())) { - ObjCInterfaceDecl::PropertyDeclOrder PO; - IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO); + IDecl->collectPropertiesToImplement(NoNeedToImplPropMap); } } if (IDecl) @@ -2574,7 +2571,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { /*TInfo=*/nullptr, SC_None, nullptr); - SetterMethod->setMethodParams(Context, Argument, None); + SetterMethod->setMethodParams(Context, Argument, std::nullopt); AddPropertyAttrs(*this, SetterMethod, property); @@ -2757,7 +2754,7 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, if (Attributes & ObjCPropertyAttribute::kind_weak) { // 'weak' and 'nonnull' are mutually exclusive. - if (auto nullability = PropertyTy->getNullability(Context)) { + if (auto nullability = PropertyTy->getNullability()) { if (*nullability == NullabilityKind::NonNull) Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "nonnull" << "weak"; diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index dc1470bf7a9d..c767341d922b 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" +#include <optional> #include <set> using namespace clang; @@ -172,7 +173,8 @@ private: /// First argument (Expr *) contains optional argument of the /// 'ordered' clause, the second one is true if the regions has 'ordered' /// clause, false otherwise. - llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion; + std::optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion; + bool RegionHasOrderConcurrent = false; unsigned AssociatedLoops = 1; bool HasMutipleLoops = false; const Decl *PossiblyLoopCounter = nullptr; @@ -213,6 +215,7 @@ private: llvm::SmallVector<ImplicitDefaultFDInfoTy, 8> ImplicitDefaultFirstprivateFDs; Expr *DeclareMapperVar = nullptr; + SmallVector<VarDecl *, 16> IteratorVarDecls; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) : Directive(DKind), DirectiveName(Name), CurScope(CurScope), @@ -847,7 +850,7 @@ public: std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const { if (const SharingMapTy *Top = getTopOfStackOrNull()) if (Top->OrderedRegion) - return Top->OrderedRegion.value(); + return *Top->OrderedRegion; return std::make_pair(nullptr, nullptr); } /// Returns true, if parent region is ordered (has associated @@ -862,9 +865,20 @@ public: getParentOrderedRegionParam() const { if (const SharingMapTy *Parent = getSecondOnStackOrNull()) if (Parent->OrderedRegion) - return Parent->OrderedRegion.value(); + return *Parent->OrderedRegion; return std::make_pair(nullptr, nullptr); } + /// Marks current region as having an 'order' clause. + void setRegionHasOrderConcurrent(bool HasOrderConcurrent) { + getTopOfStack().RegionHasOrderConcurrent = HasOrderConcurrent; + } + /// Returns true, if parent region is order (has associated + /// 'order' clause), false - otherwise. + bool isParentOrderConcurrent() const { + if (const SharingMapTy *Parent = getSecondOnStackOrNull()) + return Parent->RegionHasOrderConcurrent; + return false; + } /// Marks current region as nowait (it has a 'nowait' clause). void setNowaitRegion(bool IsNowait = true) { getTopOfStack().NowaitRegion = IsNowait; @@ -1114,19 +1128,20 @@ public: } /// Checks if specified decl is used in uses allocator clause as the /// allocator. - Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(unsigned Level, - const Decl *D) const { + std::optional<UsesAllocatorsDeclKind> + isUsesAllocatorsDecl(unsigned Level, const Decl *D) const { const SharingMapTy &StackElem = getTopOfStack(); auto I = StackElem.UsesAllocatorsDecls.find(D); if (I == StackElem.UsesAllocatorsDecls.end()) - return None; + return std::nullopt; return I->getSecond(); } - Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(const Decl *D) const { + std::optional<UsesAllocatorsDeclKind> + isUsesAllocatorsDecl(const Decl *D) const { const SharingMapTy &StackElem = getTopOfStack(); auto I = StackElem.UsesAllocatorsDecls.find(D); if (I == StackElem.UsesAllocatorsDecls.end()) - return None; + return std::nullopt; return I->getSecond(); } @@ -1138,6 +1153,22 @@ public: const SharingMapTy *Top = getTopOfStackOrNull(); return Top ? Top->DeclareMapperVar : nullptr; } + + /// Add a new iterator variable. + void addIteratorVarDecl(VarDecl *VD) { + SharingMapTy &StackElem = getTopOfStack(); + StackElem.IteratorVarDecls.push_back(VD->getCanonicalDecl()); + } + /// Check if variable declaration is an iterator VarDecl. + bool isIteratorVarDecl(const VarDecl *VD) const { + const SharingMapTy *Top = getTopOfStackOrNull(); + if (!Top) + return false; + + return llvm::any_of(Top->IteratorVarDecls, [VD](const VarDecl *IteratorVD) { + return IteratorVD == VD->getCanonicalDecl(); + }); + } /// get captured field from ImplicitDefaultFirstprivateFDs VarDecl *getImplicitFDCapExprDecl(const FieldDecl *FD) const { const_iterator I = begin(); @@ -2093,7 +2124,7 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, // // ========================================================================= // | type | defaultmap | pvt | first | is_device_ptr | map | res. | - // | |(tofrom:scalar)| | pvt | | | | + // | |(tofrom:scalar)| | pvt | |has_dv_adr| | // ========================================================================= // | scl | | | | - | | bycopy| // | scl | | - | x | - | - | bycopy| @@ -2154,10 +2185,11 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, D](OMPClauseMappableExprCommon::MappableExprComponentListRef MapExprComponents, OpenMPClauseKind WhereFoundClauseKind) { - // Only the map clause information influences how a variable is - // captured. E.g. is_device_ptr does not require changing the default - // behavior. - if (WhereFoundClauseKind != OMPC_map) + // Both map and has_device_addr clauses information influences how a + // variable is captured. E.g. is_device_ptr does not require changing + // the default behavior. + if (WhereFoundClauseKind != OMPC_map && + WhereFoundClauseKind != OMPC_has_device_addr) return false; auto EI = MapExprComponents.rbegin(); @@ -2270,6 +2302,9 @@ bool Sema::isInOpenMPTargetExecutionDirective() const { } bool Sema::isOpenMPRebuildMemberExpr(ValueDecl *D) { + // Only rebuild for Field. + if (!dyn_cast<FieldDecl>(D)) + return false; DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA( D, [](OpenMPClauseKind C, bool AppliedToPointee, @@ -2661,7 +2696,7 @@ void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, const FunctionDecl *Callee, SourceLocation Loc) { assert(LangOpts.OpenMP && "Expected OpenMP compilation mode."); - Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = OMPDeclareTargetDeclAttr::getDeviceType(Caller->getMostRecentDecl()); // Ignore host functions during device analyzis. if (LangOpts.OpenMPIsDevice && @@ -2686,6 +2721,24 @@ void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, } if (!LangOpts.OpenMPIsDevice && !LangOpts.OpenMPOffloadMandatory && DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) { + // In OpenMP 5.2 or later, if the function has a host variant then allow + // that to be called instead + auto &&HasHostAttr = [](const FunctionDecl *Callee) { + for (OMPDeclareVariantAttr *A : + Callee->specific_attrs<OMPDeclareVariantAttr>()) { + auto *DeclRefVariant = cast<DeclRefExpr>(A->getVariantFuncRef()); + auto *VariantFD = cast<FunctionDecl>(DeclRefVariant->getDecl()); + std::optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType( + VariantFD->getMostRecentDecl()); + if (!DevTy || *DevTy == OMPDeclareTargetDeclAttr::DT_Host) + return true; + } + return false; + }; + if (getLangOpts().OpenMP >= 52 && + Callee->hasAttr<OMPDeclareVariantAttr>() && HasHostAttr(Callee)) + return; // Diagnose nohost function called during host codegen. StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName( OMPC_device_type, OMPC_DEVICE_TYPE_nohost); @@ -2715,7 +2768,8 @@ void Sema::EndOpenMPClause() { static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, - SourceRange &ERange, bool AllowArraySection = false); + SourceRange &ERange, bool AllowArraySection = false, + StringRef DiagType = ""); /// Check consistency of the reduction clauses. static void checkReductionClauses(Sema &S, DSAStackTy *Stack, @@ -3226,13 +3280,15 @@ getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) { Allocator->containsUnexpandedParameterPack()) return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; + llvm::FoldingSetNodeID AEId; const Expr *AE = Allocator->IgnoreParenImpCasts(); + AE->IgnoreImpCasts()->Profile(AEId, S.getASTContext(), /*Canonical=*/true); for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); const Expr *DefAllocator = Stack->getAllocator(AllocatorKind); - llvm::FoldingSetNodeID AEId, DAEId; - AE->Profile(AEId, S.getASTContext(), /*Canonical=*/true); - DefAllocator->Profile(DAEId, S.getASTContext(), /*Canonical=*/true); + llvm::FoldingSetNodeID DAEId; + DefAllocator->IgnoreImpCasts()->Profile(DAEId, S.getASTContext(), + /*Canonical=*/true); if (AEId == DAEId) { AllocatorKindRes = AllocatorKind; break; @@ -3694,7 +3750,7 @@ public: return; // Skip internally declared static variables. - llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = + std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) && (Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() || @@ -3764,9 +3820,8 @@ public: bool IsModifierPresent = Stack->getDefaultmapModifier(ClauseKind) == OMPC_DEFAULTMAP_MODIFIER_present; if (IsModifierPresent) { - if (llvm::find(ImplicitMapModifier[ClauseKind], - OMPC_MAP_MODIFIER_present) == - std::end(ImplicitMapModifier[ClauseKind])) { + if (!llvm::is_contained(ImplicitMapModifier[ClauseKind], + OMPC_MAP_MODIFIER_present)) { ImplicitMapModifier[ClauseKind].push_back( OMPC_MAP_MODIFIER_present); } @@ -3785,9 +3840,8 @@ public: // Variable is used if it has been marked as an array, array // section, array shaping or the variable iself. return StackComponents.size() == 1 || - std::all_of( - std::next(StackComponents.rbegin()), - StackComponents.rend(), + llvm::all_of( + llvm::drop_begin(llvm::reverse(StackComponents)), [](const OMPClauseMappableExprCommon:: MappableComponent &MC) { return MC.getAssociatedDeclaration() == @@ -4032,9 +4086,13 @@ public: Visit(C); } } - if (Expr *Callee = S->getCallee()) - if (auto *CE = dyn_cast<MemberExpr>(Callee->IgnoreParenImpCasts())) + if (Expr *Callee = S->getCallee()) { + auto *CI = Callee->IgnoreParenImpCasts(); + if (auto *CE = dyn_cast<MemberExpr>(CI)) Visit(CE->getBase()); + else if (auto *CE = dyn_cast<DeclRefExpr>(CI)) + Visit(CE); + } } void VisitStmt(Stmt *S) { for (Stmt *C : S->children()) { @@ -4529,6 +4587,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: + case OMPD_error: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: @@ -4674,12 +4733,12 @@ void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) { DSAStack->setForceCaptureByReferenceInTargetExecutable( /*V=*/true); if (RD->isLambda()) { - llvm::DenseMap<const VarDecl *, FieldDecl *> Captures; + llvm::DenseMap<const ValueDecl *, FieldDecl *> Captures; FieldDecl *ThisCapture; RD->getCaptureFields(Captures, ThisCapture); for (const LambdaCapture &LC : RD->captures()) { if (LC.getCaptureKind() == LCK_ByRef) { - VarDecl *VD = LC.getCapturedVar(); + VarDecl *VD = cast<VarDecl>(LC.getCapturedVar()); DeclContext *VDC = VD->getDeclContext(); if (!VDC->Encloses(CurContext)) continue; @@ -4939,6 +4998,14 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, ShouldBeInTeamsRegion, ShouldBeInLoopSimdRegion, } Recommend = NoRecommend; + if (SemaRef.LangOpts.OpenMP >= 51 && Stack->isParentOrderConcurrent() && + CurrentRegion != OMPD_simd && CurrentRegion != OMPD_loop && + CurrentRegion != OMPD_parallel && + !isOpenMPCombinedParallelADirective(CurrentRegion)) { + SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_order) + << getOpenMPDirectiveName(CurrentRegion); + return true; + } if (isOpenMPSimdDirective(ParentRegion) && ((SemaRef.LangOpts.OpenMP <= 45 && CurrentRegion != OMPD_ordered) || (SemaRef.LangOpts.OpenMP >= 50 && CurrentRegion != OMPD_ordered && @@ -5277,7 +5344,8 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, SourceRange &ERange, - bool AllowArraySection) { + bool AllowArraySection, + StringRef DiagType) { if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || RefExpr->containsUnexpandedParameterPack()) return std::make_pair(nullptr, true); @@ -5322,6 +5390,12 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, if (IsArrayExpr != NoArrayExpr) { S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr << ERange; + } else if (!DiagType.empty()) { + unsigned DiagSelect = S.getLangOpts().CPlusPlus + ? (S.getCurrentThisType().isNull() ? 1 : 2) + : 0; + S.Diag(ELoc, diag::err_omp_expected_var_name_member_expr_with_type) + << DiagSelect << DiagType << ERange; } else { S.Diag(ELoc, AllowArraySection @@ -6021,7 +6095,7 @@ processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack, CXXScopeSpec MapperIdScopeSpec; DeclarationNameInfo MapperId; if (OMPClause *NewClause = S.ActOnOpenMPMapClause( - C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), + nullptr, C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), MapperIdScopeSpec, MapperId, C->getMapType(), /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(), SubExprs, OMPVarListLocTy())) @@ -6163,8 +6237,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( CXXScopeSpec MapperIdScopeSpec; DeclarationNameInfo MapperId; if (OMPClause *Implicit = ActOnOpenMPMapClause( - OMPC_MAP_MODIFIER_unknown, SourceLocation(), MapperIdScopeSpec, - MapperId, OMPC_MAP_tofrom, + nullptr, OMPC_MAP_MODIFIER_unknown, SourceLocation(), + MapperIdScopeSpec, MapperId, OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(), Exprs, OMPVarListLocTy(), /*NoDiagnose=*/true)) ClausesWithImplicit.emplace_back(Implicit); @@ -6180,7 +6254,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( DeclarationNameInfo MapperId; auto Kind = static_cast<OpenMPMapClauseKind>(ClauseKindCnt); if (OMPClause *Implicit = ActOnOpenMPMapClause( - ImplicitMapModifiers[I], ImplicitMapModifiersLoc[I], + nullptr, ImplicitMapModifiers[I], ImplicitMapModifiersLoc[I], MapperIdScopeSpec, MapperId, Kind, /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(), ImplicitMap, OMPVarListLocTy())) { @@ -6295,6 +6369,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( "No associated statement allowed for 'omp taskyield' directive"); Res = ActOnOpenMPTaskyieldDirective(StartLoc, EndLoc); break; + case OMPD_error: + assert(AStmt == nullptr && + "No associated statement allowed for 'omp error' directive"); + Res = ActOnOpenMPErrorDirective(ClausesWithImplicit, StartLoc, EndLoc); + break; case OMPD_barrier: assert(ClausesWithImplicit.empty() && "No clauses are allowed for 'omp barrier' directive"); @@ -6703,6 +6782,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_device_type: case OMPC_match: case OMPC_when: + case OMPC_at: + case OMPC_severity: + case OMPC_message: default: llvm_unreachable("Unexpected clause"); } @@ -7176,6 +7258,13 @@ ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope, if (!CalleeFnDecl) return Call; + if (LangOpts.OpenMP >= 51 && CalleeFnDecl->getIdentifier() && + CalleeFnDecl->getName().startswith_insensitive("omp_")) { + // checking for any calls inside an Order region + if (Scope && Scope->isOpenMPOrderClauseScope()) + Diag(LParenLoc, diag::err_omp_unexpected_call_to_omp_runtime_api); + } + if (!CalleeFnDecl->hasAttr<OMPDeclareVariantAttr>()) return Call; @@ -7268,20 +7357,20 @@ ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope, return PseudoObjectExpr::Create(Context, CE, {NewCall.get()}, 0); } -Optional<std::pair<FunctionDecl *, Expr *>> +std::optional<std::pair<FunctionDecl *, Expr *>> Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, Expr *VariantRef, OMPTraitInfo &TI, unsigned NumAppendArgs, SourceRange SR) { if (!DG || DG.get().isNull()) - return None; + return std::nullopt; const int VariantId = 1; // Must be applied only to single decl. if (!DG.get().isSingleDecl()) { Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant) << VariantId << SR; - return None; + return std::nullopt; } Decl *ADecl = DG.get().getSingleDecl(); if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl)) @@ -7292,7 +7381,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, if (!FD) { Diag(ADecl->getLocation(), diag::err_omp_function_expected) << VariantId << SR; - return None; + return std::nullopt; } auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) { @@ -7304,7 +7393,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, if (HasMultiVersionAttributes(FD)) { Diag(FD->getLocation(), diag::err_omp_declare_variant_incompat_attributes) << SR; - return None; + return std::nullopt; } // Allow #pragma omp declare variant only if the function is not used. @@ -7322,7 +7411,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, // The VariantRef must point to function. if (!VariantRef) { Diag(SR.getBegin(), diag::err_omp_function_expected) << VariantId; - return None; + return std::nullopt; } auto ShouldDelayChecks = [](Expr *&E, bool) { @@ -7357,7 +7446,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, return true; }; if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions)) - return None; + return std::nullopt; QualType AdjustedFnType = FD->getType(); if (NumAppendArgs) { @@ -7365,7 +7454,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, if (!PTy) { Diag(FD->getLocation(), diag::err_omp_declare_variant_prototype_required) << SR; - return None; + return std::nullopt; } // Adjust the function type to account for an extra omp_interop_t for each // specified in the append_args clause. @@ -7378,12 +7467,12 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, } if (!TD) { Diag(SR.getBegin(), diag::err_omp_interop_type_not_found) << SR; - return None; + return std::nullopt; } QualType InteropType = Context.getTypeDeclType(TD); if (PTy->isVariadic()) { Diag(FD->getLocation(), diag::err_omp_append_args_with_varargs) << SR; - return None; + return std::nullopt; } llvm::SmallVector<QualType, 8> Params; Params.append(PTy->param_type_begin(), PTy->param_type_end()); @@ -7413,7 +7502,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, if (!ER.isUsable()) { Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) << VariantId << VariantRef->getSourceRange(); - return None; + return std::nullopt; } VariantRef = ER.get(); } else { @@ -7433,12 +7522,12 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, << VariantRef->getType() << ((Method && !Method->isStatic()) ? FnPtrType : FD->getType()) << (NumAppendArgs ? 1 : 0) << VariantRef->getSourceRange(); - return None; + return std::nullopt; } VariantRefCast = PerformImplicitConversion( VariantRef, FnPtrType.getUnqualifiedType(), AA_Converting); if (!VariantRefCast.isUsable()) - return None; + return std::nullopt; } // Drop previously built artificial addr_of unary op for member functions. if (Method && !Method->isStatic()) { @@ -7454,7 +7543,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, !ER.get()->IgnoreParenImpCasts()->getType()->isFunctionType()) { Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) << VariantId << VariantRef->getSourceRange(); - return None; + return std::nullopt; } // The VariantRef must point to function. @@ -7462,20 +7551,20 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, if (!DRE) { Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) << VariantId << VariantRef->getSourceRange(); - return None; + return std::nullopt; } auto *NewFD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl()); if (!NewFD) { Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) << VariantId << VariantRef->getSourceRange(); - return None; + return std::nullopt; } if (FD->getCanonicalDecl() == NewFD->getCanonicalDecl()) { Diag(VariantRef->getExprLoc(), diag::err_omp_declare_variant_same_base_function) << VariantRef->getSourceRange(); - return None; + return std::nullopt; } // Check if function types are compatible in C. @@ -7487,7 +7576,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, diag::err_omp_declare_variant_incompat_types) << NewFD->getType() << FD->getType() << (NumAppendArgs ? 1 : 0) << VariantRef->getSourceRange(); - return None; + return std::nullopt; } if (NewType->isFunctionProtoType()) { if (FD->getType()->isFunctionNoProtoType()) @@ -7505,7 +7594,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, SourceRange SR = NewFD->specific_attr_begin<OMPDeclareVariantAttr>()->getRange(); Diag(SR.getBegin(), diag::note_omp_marked_declare_variant_here) << SR; - return None; + return std::nullopt; } enum DoesntSupport { @@ -7521,38 +7610,38 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, if (CXXFD->isVirtual()) { Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) << VirtFuncs; - return None; + return std::nullopt; } if (isa<CXXConstructorDecl>(FD)) { Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) << Constructors; - return None; + return std::nullopt; } if (isa<CXXDestructorDecl>(FD)) { Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) << Destructors; - return None; + return std::nullopt; } } if (FD->isDeleted()) { Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) << DeletedFuncs; - return None; + return std::nullopt; } if (FD->isDefaulted()) { Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) << DefaultedFuncs; - return None; + return std::nullopt; } if (FD->isConstexpr()) { Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs); - return None; + return std::nullopt; } // Check general compatibility. @@ -7568,7 +7657,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, << FD->getLocation()), /*TemplatesSupported=*/true, /*ConstexprSupported=*/false, /*CLinkageMayDiffer=*/true)) - return None; + return std::nullopt; return std::make_pair(FD, cast<Expr>(DRE)); } @@ -7576,9 +7665,8 @@ void Sema::ActOnOpenMPDeclareVariantDirective( FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, ArrayRef<Expr *> AdjustArgsNothing, ArrayRef<Expr *> AdjustArgsNeedDevicePtr, - ArrayRef<OMPDeclareVariantAttr::InteropType> AppendArgs, - SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc, - SourceRange SR) { + ArrayRef<OMPInteropInfo> AppendArgs, SourceLocation AdjustArgsLoc, + SourceLocation AppendArgsLoc, SourceRange SR) { // OpenMP 5.1 [2.3.5, declare variant directive, Restrictions] // An adjust_args clause or append_args clause can only be specified if the @@ -7638,8 +7726,7 @@ void Sema::ActOnOpenMPDeclareVariantDirective( AdjustArgsNothing.size(), const_cast<Expr **>(AdjustArgsNeedDevicePtr.data()), AdjustArgsNeedDevicePtr.size(), - const_cast<OMPDeclareVariantAttr::InteropType *>(AppendArgs.data()), - AppendArgs.size(), SR); + const_cast<OMPInteropInfo *>(AppendArgs.data()), AppendArgs.size(), SR); FD->addAttr(NewAttr); } @@ -7750,7 +7837,7 @@ class OpenMPIterationSpaceChecker { /// UB > Var /// UB >= Var /// This will have no value when the condition is != - llvm::Optional<bool> TestIsLessOp; + std::optional<bool> TestIsLessOp; /// This flag is true when condition is strict ( < or > ). bool TestIsStrictOp = false; /// This flag is true when step is subtracted on each iteration. @@ -7759,12 +7846,13 @@ class OpenMPIterationSpaceChecker { const ValueDecl *DepDecl = nullptr; /// Contains number of loop (starts from 1) on which loop counter init /// expression of this loop depends on. - Optional<unsigned> InitDependOnLC; + std::optional<unsigned> InitDependOnLC; /// Contains number of loop (starts from 1) on which loop counter condition /// expression of this loop depends on. - Optional<unsigned> CondDependOnLC; + std::optional<unsigned> CondDependOnLC; /// Checks if the provide statement depends on the loop counter. - Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer); + std::optional<unsigned> doesDependOnLoopCounter(const Stmt *S, + bool IsInitializer); /// Original condition required for checking of the exit condition for /// non-rectangular loop. Expr *Condition = nullptr; @@ -7847,7 +7935,7 @@ private: bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB, bool EmitDiags); /// Helper to set upper bound. - bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp, + bool setUB(Expr *NewUB, std::optional<bool> LessOp, bool StrictOp, SourceRange SR, SourceLocation SL); /// Helper to set loop increment. bool setStep(Expr *NewStep, bool Subtract); @@ -7885,8 +7973,7 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl, return false; } -bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, - llvm::Optional<bool> LessOp, +bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, std::optional<bool> LessOp, bool StrictOp, SourceRange SR, SourceLocation SL) { // State consistency checking to ensure correct usage. @@ -7929,7 +8016,7 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) { // loop. If test-expr is of form b relational-op var and relational-op is // > or >= then incr-expr must cause var to increase on each iteration of // the loop. - Optional<llvm::APSInt> Result = + std::optional<llvm::APSInt> Result = NewStep->getIntegerConstantExpr(SemaRef.Context); bool IsUnsigned = !NewStep->getType()->hasSignedIntegerRepresentation(); bool IsConstNeg = @@ -7941,19 +8028,18 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) { // != with increment is treated as <; != with decrement is treated as > if (!TestIsLessOp) TestIsLessOp = IsConstPos || (IsUnsigned && !Subtract); - if (UB && - (IsConstZero || - (TestIsLessOp.value() ? (IsConstNeg || (IsUnsigned && Subtract)) - : (IsConstPos || (IsUnsigned && !Subtract))))) { + if (UB && (IsConstZero || + (*TestIsLessOp ? (IsConstNeg || (IsUnsigned && Subtract)) + : (IsConstPos || (IsUnsigned && !Subtract))))) { SemaRef.Diag(NewStep->getExprLoc(), diag::err_omp_loop_incr_not_compatible) - << LCDecl << TestIsLessOp.value() << NewStep->getSourceRange(); + << LCDecl << *TestIsLessOp << NewStep->getSourceRange(); SemaRef.Diag(ConditionLoc, diag::note_omp_loop_cond_requres_compatible_incr) - << TestIsLessOp.value() << ConditionSrcRange; + << *TestIsLessOp << ConditionSrcRange; return true; } - if (TestIsLessOp.value() == Subtract) { + if (*TestIsLessOp == Subtract) { NewStep = SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus, NewStep) .get(); @@ -8064,7 +8150,7 @@ public: }; } // namespace -Optional<unsigned> +std::optional<unsigned> OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S, bool IsInitializer) { // Check for the non-rectangular loops. @@ -8074,7 +8160,7 @@ OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S, DepDecl = LoopStmtChecker.getDepDecl(); return LoopStmtChecker.getBaseLoopId(); } - return llvm::None; + return std::nullopt; } bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) { @@ -8200,10 +8286,10 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { Condition = S; S = getExprAsWritten(S); SourceLocation CondLoc = S->getBeginLoc(); - auto &&CheckAndSetCond = [this, IneqCondIsCanonical]( - BinaryOperatorKind Opcode, const Expr *LHS, - const Expr *RHS, SourceRange SR, - SourceLocation OpLoc) -> llvm::Optional<bool> { + auto &&CheckAndSetCond = + [this, IneqCondIsCanonical](BinaryOperatorKind Opcode, const Expr *LHS, + const Expr *RHS, SourceRange SR, + SourceLocation OpLoc) -> std::optional<bool> { if (BinaryOperator::isRelationalOp(Opcode)) { if (getInitLCDecl(LHS) == LCDecl) return setUB(const_cast<Expr *>(RHS), @@ -8215,12 +8301,12 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) { (Opcode == BO_LT || Opcode == BO_GT), SR, OpLoc); } else if (IneqCondIsCanonical && Opcode == BO_NE) { return setUB(const_cast<Expr *>(getInitLCDecl(LHS) == LCDecl ? RHS : LHS), - /*LessOp=*/llvm::None, + /*LessOp=*/std::nullopt, /*StrictOp=*/true, SR, OpLoc); } - return llvm::None; + return std::nullopt; }; - llvm::Optional<bool> Res; + std::optional<bool> Res; if (auto *RBO = dyn_cast<CXXRewrittenBinaryOperator>(S)) { CXXRewrittenBinaryOperator::DecomposedForm DF = RBO->getDecomposedForm(); Res = CheckAndSetCond(DF.Opcode, DF.LHS, DF.RHS, RBO->getSourceRange(), @@ -8383,12 +8469,12 @@ calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc, return nullptr; llvm::APSInt LRes, SRes; bool IsLowerConst = false, IsStepConst = false; - if (Optional<llvm::APSInt> Res = + if (std::optional<llvm::APSInt> Res = Lower->getIntegerConstantExpr(SemaRef.Context)) { LRes = *Res; IsLowerConst = true; } - if (Optional<llvm::APSInt> Res = + if (std::optional<llvm::APSInt> Res = Step->getIntegerConstantExpr(SemaRef.Context)) { SRes = *Res; IsStepConst = true; @@ -8427,7 +8513,7 @@ calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc, } llvm::APSInt URes; bool IsUpperConst = false; - if (Optional<llvm::APSInt> Res = + if (std::optional<llvm::APSInt> Res = Upper->getIntegerConstantExpr(SemaRef.Context)) { URes = *Res; IsUpperConst = true; @@ -8708,8 +8794,8 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations( UBVal = MinUB.get(); } } - Expr *UBExpr = TestIsLessOp.value() ? UBVal : LBVal; - Expr *LBExpr = TestIsLessOp.value() ? LBVal : UBVal; + Expr *UBExpr = *TestIsLessOp ? UBVal : LBVal; + Expr *LBExpr = *TestIsLessOp ? LBVal : UBVal; Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); if (!Upper || !Lower) @@ -8772,12 +8858,12 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues( // init value. Expr *MinExpr = nullptr; Expr *MaxExpr = nullptr; - Expr *LBExpr = TestIsLessOp.value() ? LB : UB; - Expr *UBExpr = TestIsLessOp.value() ? UB : LB; - bool LBNonRect = TestIsLessOp.value() ? InitDependOnLC.has_value() - : CondDependOnLC.has_value(); - bool UBNonRect = TestIsLessOp.value() ? CondDependOnLC.has_value() - : InitDependOnLC.has_value(); + Expr *LBExpr = *TestIsLessOp ? LB : UB; + Expr *UBExpr = *TestIsLessOp ? UB : LB; + bool LBNonRect = + *TestIsLessOp ? InitDependOnLC.has_value() : CondDependOnLC.has_value(); + bool UBNonRect = + *TestIsLessOp ? CondDependOnLC.has_value() : InitDependOnLC.has_value(); Expr *Lower = LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get(); Expr *Upper = @@ -8899,11 +8985,11 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond( if (!NewLB.isUsable() || !NewUB.isUsable()) return nullptr; - ExprResult CondExpr = SemaRef.BuildBinOp( - S, DefaultLoc, - TestIsLessOp.value() ? (TestIsStrictOp ? BO_LT : BO_LE) - : (TestIsStrictOp ? BO_GT : BO_GE), - NewLB.get(), NewUB.get()); + ExprResult CondExpr = + SemaRef.BuildBinOp(S, DefaultLoc, + *TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE) + : (TestIsStrictOp ? BO_GT : BO_GE), + NewLB.get(), NewUB.get()); if (CondExpr.isUsable()) { if (!SemaRef.Context.hasSameUnqualifiedType(CondExpr.get()->getType(), SemaRef.Context.BoolTy)) @@ -8979,9 +9065,9 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( return nullptr; // Upper - Lower Expr *Upper = - TestIsLessOp.value() ? Cnt : tryBuildCapture(SemaRef, LB, Captures).get(); + *TestIsLessOp ? Cnt : tryBuildCapture(SemaRef, LB, Captures).get(); Expr *Lower = - TestIsLessOp.value() ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt; + *TestIsLessOp ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt; if (!Upper || !Lower) return nullptr; @@ -9383,7 +9469,7 @@ static ExprResult widenIterationCount(unsigned Bits, Expr *E, Sema &SemaRef) { static bool fitsInto(unsigned Bits, bool Signed, const Expr *E, Sema &SemaRef) { if (E == nullptr) return false; - if (Optional<llvm::APSInt> Result = + if (std::optional<llvm::APSInt> Result = E->getIntegerConstantExpr(SemaRef.Context)) return Signed ? Result->isSignedIntN(Bits) : Result->isIntN(Bits); return false; @@ -11012,9 +11098,50 @@ StmtResult Sema::ActOnOpenMPBarrierDirective(SourceLocation StartLoc, return OMPBarrierDirective::Create(Context, StartLoc, EndLoc); } +StmtResult Sema::ActOnOpenMPErrorDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc, + bool InExContext) { + const OMPAtClause *AtC = + OMPExecutableDirective::getSingleClause<OMPAtClause>(Clauses); + + if (AtC && !InExContext && AtC->getAtKind() == OMPC_AT_execution) { + Diag(AtC->getAtKindKwLoc(), diag::err_omp_unexpected_execution_modifier); + 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) { + if (SeverityC && SeverityC->getSeverityKind() == OMPC_SEVERITY_warning) + Diag(SeverityC->getSeverityKindKwLoc(), diag::warn_diagnose_if_succeeded) + << (ME ? cast<StringLiteral>(ME)->getString() : "WARNING"); + else + Diag(StartLoc, diag::err_diagnose_if_succeeded) + << (ME ? cast<StringLiteral>(ME)->getString() : "ERROR"); + if (!SeverityC || SeverityC->getSeverityKind() != OMPC_SEVERITY_warning) + return StmtError(); + } + return OMPErrorDirective::Create(Context, StartLoc, EndLoc, Clauses); +} + StmtResult Sema::ActOnOpenMPTaskwaitDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc) { + const OMPNowaitClause *NowaitC = + OMPExecutableDirective::getSingleClause<OMPNowaitClause>(Clauses); + bool HasDependC = + !OMPExecutableDirective::getClausesOfKind<OMPDependClause>(Clauses) + .empty(); + if (NowaitC && !HasDependC) { + Diag(StartLoc, diag::err_omp_nowait_clause_without_depend); + return StmtError(); + } + return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc, Clauses); } @@ -11569,6 +11696,9 @@ protected: static bool CheckValue(const Expr *E, ErrorInfoTy &ErrorInfo, bool ShouldBeLValue, bool ShouldBeInteger = false) { + if (E->isInstantiationDependent()) + return true; + if (ShouldBeLValue && !E->isLValue()) { ErrorInfo.Error = ErrorTy::XNotLValue; ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); @@ -11576,25 +11706,23 @@ protected: return false; } - if (!E->isInstantiationDependent()) { - QualType QTy = E->getType(); - if (!QTy->isScalarType()) { - ErrorInfo.Error = ErrorTy::NotScalar; - ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); - ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); - return false; - } - if (ShouldBeInteger && !QTy->isIntegerType()) { - ErrorInfo.Error = ErrorTy::NotInteger; - ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); - ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); - return false; - } + QualType QTy = E->getType(); + if (!QTy->isScalarType()) { + ErrorInfo.Error = ErrorTy::NotScalar; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); + return false; + } + if (ShouldBeInteger && !QTy->isIntegerType()) { + ErrorInfo.Error = ErrorTy::NotInteger; + ErrorInfo.ErrorLoc = ErrorInfo.NoteLoc = E->getExprLoc(); + ErrorInfo.ErrorRange = ErrorInfo.NoteRange = E->getSourceRange(); + return false; } return true; } -}; + }; bool OpenMPAtomicCompareChecker::checkCondUpdateStmt(IfStmt *S, ErrorInfoTy &ErrorInfo) { @@ -12174,17 +12302,33 @@ bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S, Stmt *UpdateStmt = nullptr; Stmt *CondUpdateStmt = nullptr; + Stmt *CondExprStmt = nullptr; if (auto *BO = dyn_cast<BinaryOperator>(S1)) { - // { v = x; cond-update-stmt } or form 45. - UpdateStmt = S1; - CondUpdateStmt = S2; - // Check if form 45. - if (isa<BinaryOperator>(BO->getRHS()->IgnoreImpCasts()) && - isa<IfStmt>(S2)) - return checkForm45(CS, ErrorInfo); - // It cannot be set before we the check for form45. - IsPostfixUpdate = true; + // It could be one of the following cases: + // { v = x; cond-update-stmt } + // { v = x; cond-expr-stmt } + // { cond-expr-stmt; v = x; } + // form 45 + if (isa<BinaryOperator>(BO->getRHS()->IgnoreImpCasts()) || + isa<ConditionalOperator>(BO->getRHS()->IgnoreImpCasts())) { + // check if form 45 + if (isa<IfStmt>(S2)) + return checkForm45(CS, ErrorInfo); + // { cond-expr-stmt; v = x; } + CondExprStmt = S1; + UpdateStmt = S2; + } else { + IsPostfixUpdate = true; + UpdateStmt = S1; + if (isa<IfStmt>(S2)) { + // { v = x; cond-update-stmt } + CondUpdateStmt = S2; + } else { + // { v = x; cond-expr-stmt } + CondExprStmt = S2; + } + } } else { // { cond-update-stmt v = x; } UpdateStmt = S2; @@ -12200,10 +12344,7 @@ bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S, return false; } - if (!checkCondUpdateStmt(IS, ErrorInfo)) - return false; - - return true; + return checkCondUpdateStmt(IS, ErrorInfo); }; // CheckUpdateStmt has to be called *after* CheckCondUpdateStmt. @@ -12236,7 +12377,9 @@ bool OpenMPAtomicCompareCaptureChecker::checkStmt(Stmt *S, return true; }; - if (!CheckCondUpdateStmt(CondUpdateStmt)) + if (CondUpdateStmt && !CheckCondUpdateStmt(CondUpdateStmt)) + return false; + if (CondExprStmt && !checkCondExprStmt(CondExprStmt, ErrorInfo)) return false; if (!CheckUpdateStmt(UpdateStmt)) return false; @@ -12277,7 +12420,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, case OMPC_write: case OMPC_update: MutexClauseEncountered = true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case OMPC_capture: case OMPC_compare: { if (AtomicKind != OMPC_unknown && MutexClauseEncountered) { @@ -15049,12 +15192,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_priority: Res = ActOnOpenMPPriorityClause(Expr, StartLoc, LParenLoc, EndLoc); break; - case OMPC_grainsize: - Res = ActOnOpenMPGrainsizeClause(Expr, StartLoc, LParenLoc, EndLoc); - break; - case OMPC_num_tasks: - Res = ActOnOpenMPNumTasksClause(Expr, StartLoc, LParenLoc, EndLoc); - break; case OMPC_hint: Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc); break; @@ -15076,9 +15213,17 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_partial: Res = ActOnOpenMPPartialClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_message: + Res = ActOnOpenMPMessageClause(Expr, StartLoc, LParenLoc, EndLoc); + break; case OMPC_align: Res = ActOnOpenMPAlignClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_ompx_dyn_cgroup_mem: + Res = ActOnOpenMPXDynCGroupMemClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_grainsize: + case OMPC_num_tasks: case OMPC_device: case OMPC_if: case OMPC_default: @@ -15135,6 +15280,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_match: case OMPC_nontemporal: case OMPC_order: + case OMPC_at: + case OMPC_severity: case OMPC_destroy: case OMPC_inclusive: case OMPC_exclusive: @@ -15166,7 +15313,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( CaptureRegion = OMPD_parallel; break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case OMPD_target_parallel: case OMPD_target_parallel_for: case OMPD_target_parallel_loop: @@ -15181,7 +15328,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( CaptureRegion = OMPD_parallel; break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case OMPD_target_teams_distribute_parallel_for: // If this clause applies to the nested 'parallel' region, capture within // the 'teams' region, otherwise do not capture. @@ -15194,7 +15341,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( CaptureRegion = OMPD_parallel; break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case OMPD_teams_distribute_parallel_for: CaptureRegion = OMPD_teams; break; @@ -15289,6 +15436,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: + case OMPD_error: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: @@ -15377,6 +15525,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: + case OMPD_error: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: @@ -15473,6 +15622,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: + case OMPD_error: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: @@ -15514,6 +15664,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( break; case OMPC_thread_limit: switch (DKind) { + case OMPD_target: case OMPD_target_teams: case OMPD_target_teams_distribute: case OMPD_target_teams_distribute_simd: @@ -15555,7 +15706,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_parallel_loop: - case OMPD_target: case OMPD_target_simd: case OMPD_target_parallel: case OMPD_target_parallel_for: @@ -15564,6 +15714,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: + case OMPD_error: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: @@ -15652,6 +15803,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: + case OMPD_error: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: @@ -15743,6 +15895,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: + case OMPD_error: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: @@ -15785,6 +15938,26 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( llvm_unreachable("Unknown OpenMP directive"); } break; + case OMPC_ompx_dyn_cgroup_mem: + switch (DKind) { + case OMPD_target: + case OMPD_target_simd: + case OMPD_target_teams: + case OMPD_target_parallel: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_simd: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: + case OMPD_target_parallel_loop: + case OMPD_target_teams_distribute_parallel_for: + case OMPD_target_teams_distribute_parallel_for_simd: + case OMPD_target_teams_loop: + CaptureRegion = OMPD_target; + break; + default: + llvm_unreachable("Unknown OpenMP directive"); + } + break; case OMPC_device: switch (DKind) { case OMPD_target_update: @@ -15837,6 +16010,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: + case OMPD_error: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: @@ -15928,6 +16102,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_threadprivate: case OMPD_allocate: case OMPD_taskyield: + case OMPD_error: case OMPD_barrier: case OMPD_taskwait: case OMPD_cancellation_point: @@ -16052,6 +16227,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_match: case OMPC_nontemporal: case OMPC_order: + case OMPC_at: + case OMPC_severity: + case OMPC_message: case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: @@ -16190,7 +16368,7 @@ isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind, ValExpr = Value.get(); // The expression must evaluate to a non-negative integer value. - if (Optional<llvm::APSInt> Result = + if (std::optional<llvm::APSInt> Result = ValExpr->getIntegerConstantExpr(SemaRef.Context)) { if (Result->isSigned() && !((!StrictlyPositive && Result->isNonNegative()) || @@ -16320,10 +16498,22 @@ OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc, /// Tries to find omp_allocator_handle_t type. static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc, DSAStackTy *Stack) { - QualType OMPAllocatorHandleT = Stack->getOMPAllocatorHandleT(); - if (!OMPAllocatorHandleT.isNull()) + if (!Stack->getOMPAllocatorHandleT().isNull()) return true; - // Build the predefined allocator expressions. + + // Set the allocator handle type. + IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_allocator_handle_t"); + ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope()); + if (!PT.getAsOpaquePtr() || PT.get().isNull()) { + S.Diag(Loc, diag::err_omp_implied_type_not_found) + << "omp_allocator_handle_t"; + return false; + } + QualType AllocatorHandleEnumTy = PT.get(); + AllocatorHandleEnumTy.addConst(); + Stack->setOMPAllocatorHandleT(AllocatorHandleEnumTy); + + // Fill the predefined allocator map. bool ErrorFound = false; for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); @@ -16343,9 +16533,10 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc, ErrorFound = true; break; } - if (OMPAllocatorHandleT.isNull()) - OMPAllocatorHandleT = AllocatorType; - if (!S.getASTContext().hasSameType(OMPAllocatorHandleT, AllocatorType)) { + Res = S.PerformImplicitConversion(Res.get(), AllocatorHandleEnumTy, + Sema::AA_Initializing, + /* AllowExplicit */ true); + if (!Res.isUsable()) { ErrorFound = true; break; } @@ -16356,8 +16547,7 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc, << "omp_allocator_handle_t"; return false; } - OMPAllocatorHandleT.addConst(); - Stack->setOMPAllocatorHandleT(OMPAllocatorHandleT); + return true; } @@ -16442,10 +16632,6 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( static_cast<OpenMPAtomicDefaultMemOrderClauseKind>(Argument), ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; - case OMPC_order: - Res = ActOnOpenMPOrderClause(static_cast<OpenMPOrderClauseKind>(Argument), - ArgumentLoc, StartLoc, LParenLoc, EndLoc); - break; case OMPC_update: Res = ActOnOpenMPUpdateClause(static_cast<OpenMPDependClauseKind>(Argument), ArgumentLoc, StartLoc, LParenLoc, EndLoc); @@ -16454,6 +16640,15 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( Res = ActOnOpenMPBindClause(static_cast<OpenMPBindClauseKind>(Argument), ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; + case OMPC_at: + Res = ActOnOpenMPAtClause(static_cast<OpenMPAtClauseKind>(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_severity: + Res = ActOnOpenMPSeverityClause( + static_cast<OpenMPSeverityClauseKind>(Argument), ArgumentLoc, StartLoc, + LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -16529,6 +16724,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_uses_allocators: case OMPC_affinity: case OMPC_when: + case OMPC_message: default: llvm_unreachable("Clause is not allowed."); } @@ -16537,13 +16733,12 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( static std::string getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last, - ArrayRef<unsigned> Exclude = llvm::None) { + ArrayRef<unsigned> Exclude = std::nullopt) { SmallString<256> Buffer; llvm::raw_svector_ostream Out(Buffer); unsigned Skipped = Exclude.size(); - auto S = Exclude.begin(), E = Exclude.end(); for (unsigned I = First; I < Last; ++I) { - if (std::find(S, E, I) != E) { + if (llvm::is_contained(Exclude, I)) { --Skipped; continue; } @@ -16633,22 +16828,87 @@ OMPClause *Sema::ActOnOpenMPAtomicDefaultMemOrderClause( LParenLoc, EndLoc); } -OMPClause *Sema::ActOnOpenMPOrderClause(OpenMPOrderClauseKind Kind, - SourceLocation KindKwLoc, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - if (Kind == OMPC_ORDER_unknown) { +OMPClause *Sema::ActOnOpenMPAtClause(OpenMPAtClauseKind Kind, + SourceLocation KindKwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_AT_unknown) { + Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_at, /*First=*/0, + /*Last=*/OMPC_AT_unknown) + << getOpenMPClauseName(OMPC_at); + return nullptr; + } + return new (Context) + OMPAtClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPSeverityClause(OpenMPSeverityClauseKind Kind, + SourceLocation KindKwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_SEVERITY_unknown) { + Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_severity, /*First=*/0, + /*Last=*/OMPC_SEVERITY_unknown) + << getOpenMPClauseName(OMPC_severity); + return nullptr; + } + return new (Context) + OMPSeverityClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPMessageClause(Expr *ME, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + assert(ME && "NULL expr in Message clause"); + if (!isa<StringLiteral>(ME)) { + Diag(ME->getBeginLoc(), diag::warn_clause_expected_string) + << getOpenMPClauseName(OMPC_message); + return nullptr; + } + return new (Context) OMPMessageClause(ME, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPOrderClause( + OpenMPOrderClauseModifier Modifier, OpenMPOrderClauseKind Kind, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, + SourceLocation KindLoc, SourceLocation EndLoc) { + if (Kind != OMPC_ORDER_concurrent || + (LangOpts.OpenMP < 51 && MLoc.isValid())) { + // Kind should be concurrent, + // Modifiers introduced in OpenMP 5.1 static_assert(OMPC_ORDER_unknown > 0, "OMPC_ORDER_unknown not greater than 0"); - Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) - << getListOfPossibleValues(OMPC_order, /*First=*/0, + + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_order, + /*First=*/0, /*Last=*/OMPC_ORDER_unknown) << getOpenMPClauseName(OMPC_order); return nullptr; } - return new (Context) - OMPOrderClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); + if (LangOpts.OpenMP >= 51) { + if (Modifier == OMPC_ORDER_MODIFIER_unknown && MLoc.isValid()) { + Diag(MLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_order, + /*First=*/OMPC_ORDER_MODIFIER_unknown + 1, + /*Last=*/OMPC_ORDER_MODIFIER_last) + << getOpenMPClauseName(OMPC_order); + } else { + DSAStack->setRegionHasOrderConcurrent(/*HasOrderConcurrent=*/true); + if (DSAStack->getCurScope()) { + // mark the current scope with 'order' flag + unsigned existingFlags = DSAStack->getCurScope()->getFlags(); + DSAStack->getCurScope()->setFlags(existingFlags | + Scope::OpenMPOrderClauseScope); + } + } + } + return new (Context) OMPOrderClause(Kind, KindLoc, StartLoc, LParenLoc, + EndLoc, Modifier, MLoc); } OMPClause *Sema::ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind, @@ -16760,12 +17020,33 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( StartLoc, LParenLoc, ArgumentLoc[Modifier], ArgumentLoc[DefaultmapKind], EndLoc); break; + case OMPC_order: + enum { OrderModifier, OrderKind }; + Res = ActOnOpenMPOrderClause( + static_cast<OpenMPOrderClauseModifier>(Argument[OrderModifier]), + static_cast<OpenMPOrderClauseKind>(Argument[OrderKind]), StartLoc, + LParenLoc, ArgumentLoc[OrderModifier], ArgumentLoc[OrderKind], EndLoc); + break; case OMPC_device: assert(Argument.size() == 1 && ArgumentLoc.size() == 1); Res = ActOnOpenMPDeviceClause( static_cast<OpenMPDeviceClauseModifier>(Argument.back()), Expr, StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); break; + case OMPC_grainsize: + assert(Argument.size() == 1 && ArgumentLoc.size() == 1 && + "Modifier for grainsize clause and its location are expected."); + Res = ActOnOpenMPGrainsizeClause( + static_cast<OpenMPGrainsizeClauseModifier>(Argument.back()), Expr, + StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); + break; + case OMPC_num_tasks: + assert(Argument.size() == 1 && ArgumentLoc.size() == 1 && + "Modifier for num_tasks clause and its location are expected."); + Res = ActOnOpenMPNumTasksClause( + static_cast<OpenMPNumTasksClauseModifier>(Argument.back()), Expr, + StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); + break; case OMPC_final: case OMPC_num_threads: case OMPC_safelen: @@ -16811,9 +17092,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: - case OMPC_grainsize: case OMPC_nogroup: - case OMPC_num_tasks: case OMPC_hint: case OMPC_unknown: case OMPC_uniform: @@ -16831,7 +17110,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: - case OMPC_order: + case OMPC_at: + case OMPC_severity: + case OMPC_message: case OMPC_destroy: case OMPC_novariants: case OMPC_nocontext: @@ -16935,7 +17216,7 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( // OpenMP [2.7.1, Restrictions] // chunk_size must be a loop invariant integer expression with a positive // value. - if (Optional<llvm::APSInt> Result = + if (std::optional<llvm::APSInt> Result = ValExpr->getIntegerConstantExpr(Context)) { if (Result->isSigned() && !Result->isStrictlyPositive()) { Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause) @@ -17088,6 +17369,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_match: case OMPC_nontemporal: case OMPC_order: + case OMPC_at: + case OMPC_severity: + case OMPC_message: case OMPC_novariants: case OMPC_nocontext: case OMPC_detach: @@ -17096,6 +17380,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_uses_allocators: case OMPC_affinity: case OMPC_when: + case OMPC_ompx_dyn_cgroup_mem: default: llvm_unreachable("Clause is not allowed."); } @@ -17247,32 +17532,28 @@ StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses, // OpenMP 5.1 [2.15.1, interop Construct, Restrictions] // Each interop-var may be specified for at most one action-clause of each // interop construct. - llvm::SmallPtrSet<const VarDecl *, 4> InteropVars; - for (const OMPClause *C : Clauses) { + llvm::SmallPtrSet<const ValueDecl *, 4> InteropVars; + for (OMPClause *C : Clauses) { OpenMPClauseKind ClauseKind = C->getClauseKind(); - const DeclRefExpr *DRE = nullptr; - SourceLocation VarLoc; + std::pair<ValueDecl *, bool> DeclResult; + SourceLocation ELoc; + SourceRange ERange; if (ClauseKind == OMPC_init) { - const auto *IC = cast<OMPInitClause>(C); - VarLoc = IC->getVarLoc(); - DRE = dyn_cast_or_null<DeclRefExpr>(IC->getInteropVar()); + auto *E = cast<OMPInitClause>(C)->getInteropVar(); + DeclResult = getPrivateItem(*this, E, ELoc, ERange); } else if (ClauseKind == OMPC_use) { - const auto *UC = cast<OMPUseClause>(C); - VarLoc = UC->getVarLoc(); - DRE = dyn_cast_or_null<DeclRefExpr>(UC->getInteropVar()); + auto *E = cast<OMPUseClause>(C)->getInteropVar(); + DeclResult = getPrivateItem(*this, E, ELoc, ERange); } else if (ClauseKind == OMPC_destroy) { - const auto *DC = cast<OMPDestroyClause>(C); - VarLoc = DC->getVarLoc(); - DRE = dyn_cast_or_null<DeclRefExpr>(DC->getInteropVar()); + auto *E = cast<OMPDestroyClause>(C)->getInteropVar(); + DeclResult = getPrivateItem(*this, E, ELoc, ERange); } - if (!DRE) - continue; - - if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { - if (!InteropVars.insert(VD->getCanonicalDecl()).second) { - Diag(VarLoc, diag::err_omp_interop_var_multiple_actions) << VD; + if (DeclResult.first) { + if (!InteropVars.insert(DeclResult.first).second) { + Diag(ELoc, diag::err_omp_interop_var_multiple_actions) + << DeclResult.first; return StmtError(); } } @@ -17284,16 +17565,20 @@ StmtResult Sema::ActOnOpenMPInteropDirective(ArrayRef<OMPClause *> Clauses, static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr, SourceLocation VarLoc, OpenMPClauseKind Kind) { - if (InteropVarExpr->isValueDependent() || InteropVarExpr->isTypeDependent() || - InteropVarExpr->isInstantiationDependent() || - InteropVarExpr->containsUnexpandedParameterPack()) + SourceLocation ELoc; + SourceRange ERange; + Expr *RefExpr = InteropVarExpr; + auto Res = + getPrivateItem(SemaRef, RefExpr, ELoc, ERange, + /*AllowArraySection=*/false, /*DiagType=*/"omp_interop_t"); + + if (Res.second) { + // It will be analyzed later. return true; + } - const auto *DRE = dyn_cast<DeclRefExpr>(InteropVarExpr); - if (!DRE || !isa<VarDecl>(DRE->getDecl())) { - SemaRef.Diag(VarLoc, diag::err_omp_interop_variable_expected) << 0; + if (!Res.first) return false; - } // Interop variable should be of type omp_interop_t. bool HasError = false; @@ -17335,8 +17620,7 @@ static bool isValidInteropVariable(Sema &SemaRef, Expr *InteropVarExpr, } OMPClause * -Sema::ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs, - bool IsTarget, bool IsTargetSync, +Sema::ActOnOpenMPInitClause(Expr *InteropVar, OMPInteropInfo &InteropInfo, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation VarLoc, SourceLocation EndLoc) { @@ -17345,7 +17629,7 @@ Sema::ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs, // Check prefer_type values. These foreign-runtime-id values are either // string literals or constant integral expressions. - for (const Expr *E : PrefExprs) { + for (const Expr *E : InteropInfo.PreferTypes) { if (E->isValueDependent() || E->isTypeDependent() || E->isInstantiationDependent() || E->containsUnexpandedParameterPack()) continue; @@ -17357,9 +17641,8 @@ Sema::ActOnOpenMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs, return nullptr; } - return OMPInitClause::Create(Context, InteropVar, PrefExprs, IsTarget, - IsTargetSync, StartLoc, LParenLoc, VarLoc, - EndLoc); + return OMPInitClause::Create(Context, InteropVar, InteropInfo, StartLoc, + LParenLoc, VarLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPUseClause(Expr *InteropVar, SourceLocation StartLoc, @@ -17549,7 +17832,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown && "Unexpected map modifier."); Res = ActOnOpenMPMapClause( - Data.MapTypeModifiers, Data.MapTypeModifiersLoc, + Data.IteratorExpr, Data.MapTypeModifiers, Data.MapTypeModifiersLoc, Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, static_cast<OpenMPMapClauseKind>(ExtraModifier), Data.IsMapTypeImplicit, ExtraModifierLoc, ColonLoc, VarList, Locs); @@ -17644,6 +17927,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, case OMPC_device_type: case OMPC_match: case OMPC_order: + case OMPC_at: + case OMPC_severity: + case OMPC_message: case OMPC_destroy: case OMPC_novariants: case OMPC_nocontext: @@ -18417,7 +18703,7 @@ static T filterLookupForUDReductionAndMapper( static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case"); - for (auto RD : D->redecls()) { + for (auto *RD : D->redecls()) { // Don't bother with extra checks if we already know this one isn't visible. if (RD == D) continue; @@ -19744,7 +20030,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause( // Warn about zero linear step (it would be probably better specified as // making corresponding variables 'const'). - if (Optional<llvm::APSInt> Result = + if (std::optional<llvm::APSInt> Result = StepExpr->getIntegerConstantExpr(Context)) { if (!Result->isNegative() && !Result->isStrictlyPositive()) Diag(StepLoc, diag::warn_omp_linear_step_zero) @@ -20927,8 +21213,8 @@ public: } // Pointer arithmetic is the only thing we expect to happen here so after we - // make sure the binary operator is a pointer type, the we only thing need - // to to is to visit the subtree that has the same type as root (so that we + // make sure the binary operator is a pointer type, the only thing we need + // to do is to visit the subtree that has the same type as root (so that we // know the other subtree is just an offset) Expr *LE = BO->getLHS()->IgnoreParenImpCasts(); Expr *RE = BO->getRHS()->IgnoreParenImpCasts(); @@ -21403,7 +21689,7 @@ static void checkMappableExpressionList( CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo MapperId, ArrayRef<Expr *> UnresolvedMappers, OpenMPMapClauseKind MapType = OMPC_MAP_unknown, - ArrayRef<OpenMPMapModifierKind> Modifiers = None, + ArrayRef<OpenMPMapModifierKind> Modifiers = std::nullopt, bool IsMapTypeImplicit = false, bool NoDiagnose = false) { // We only expect mappable expressions in 'to', 'from', and 'map' clauses. assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) && @@ -21603,10 +21889,12 @@ static void checkMappableExpressionList( // target enter data // OpenMP [2.10.2, Restrictions, p. 99] // A map-type must be specified in all map clauses and must be either - // to or alloc. + // to or alloc. Starting with OpenMP 5.2 the default map type is `to` if + // no map type is present. OpenMPDirectiveKind DKind = DSAS->getCurrentDirective(); if (DKind == OMPD_target_enter_data && - !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc)) { + !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc || + SemaRef.getLangOpts().OpenMP >= 52)) { SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive) << (IsMapTypeImplicit ? 1 : 0) << getOpenMPSimpleClauseTypeName(OMPC_map, MapType) @@ -21617,10 +21905,11 @@ static void checkMappableExpressionList( // target exit_data // OpenMP [2.10.3, Restrictions, p. 102] // A map-type must be specified in all map clauses and must be either - // from, release, or delete. + // from, release, or delete. Starting with OpenMP 5.2 the default map + // type is `from` if no map type is present. if (DKind == OMPD_target_exit_data && !(MapType == OMPC_MAP_from || MapType == OMPC_MAP_release || - MapType == OMPC_MAP_delete)) { + MapType == OMPC_MAP_delete || SemaRef.getLangOpts().OpenMP >= 52)) { SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive) << (IsMapTypeImplicit ? 1 : 0) << getOpenMPSimpleClauseTypeName(OMPC_map, MapType) @@ -21698,7 +21987,7 @@ static void checkMappableExpressionList( /*WhereFoundClauseKind=*/OMPC_map); // Save the components and declaration to create the clause. For purposes of - // the clause creation, any component list that has has base 'this' uses + // the clause creation, any component list that has base 'this' uses // null as base declaration. MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1); MVLI.VarComponents.back().append(CurComponents.begin(), @@ -21709,7 +21998,7 @@ static void checkMappableExpressionList( } OMPClause *Sema::ActOnOpenMPMapClause( - ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, + Expr *IteratorModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, ArrayRef<SourceLocation> MapTypeModifiersLoc, CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, @@ -21719,9 +22008,14 @@ OMPClause *Sema::ActOnOpenMPMapClause( OpenMPMapModifierKind Modifiers[] = { OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, - OMPC_MAP_MODIFIER_unknown}; + OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown}; SourceLocation ModifiersLoc[NumberOfOMPMapClauseModifiers]; + if (IteratorModifier && !IteratorModifier->getType()->isSpecificBuiltinType( + BuiltinType::OMPIterator)) + Diag(IteratorModifier->getExprLoc(), + diag::err_omp_map_modifier_not_iterator); + // Process map-type-modifiers, flag errors for duplicate modifiers. unsigned Count = 0; for (unsigned I = 0, E = MapTypeModifiers.size(); I < E; ++I) { @@ -21745,11 +22039,11 @@ OMPClause *Sema::ActOnOpenMPMapClause( // We need to produce a map clause even if we don't have variables so that // other diagnostics related with non-existing map clauses are accurate. - return OMPMapClause::Create(Context, Locs, MVLI.ProcessedVarList, - MVLI.VarBaseDeclarations, MVLI.VarComponents, - MVLI.UDMapperList, Modifiers, ModifiersLoc, - MapperIdScopeSpec.getWithLocInContext(Context), - MapperId, MapType, IsMapTypeImplicit, MapLoc); + return OMPMapClause::Create( + Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents, MVLI.UDMapperList, IteratorModifier, Modifiers, + ModifiersLoc, MapperIdScopeSpec.getWithLocInContext(Context), MapperId, + MapType, IsMapTypeImplicit, MapLoc); } QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, @@ -22143,6 +22437,11 @@ Sema::ActOnOpenMPDeclareMapperDirectiveVarDecl(Scope *S, QualType MapperType, return E; } +void Sema::ActOnOpenMPIteratorVarDecl(VarDecl *VD) { + if (DSAStack->getDeclareMapperVarRef()) + DSAStack->addIteratorVarDecl(VD); +} + bool Sema::isOpenMPDeclareMapperVarDeclAllowed(const VarDecl *VD) const { assert(LangOpts.OpenMP && "Expected OpenMP mode."); const Expr *Ref = DSAStack->getDeclareMapperVarRef(); @@ -22151,6 +22450,8 @@ bool Sema::isOpenMPDeclareMapperVarDeclAllowed(const VarDecl *VD) const { return true; if (VD->isUsableInConstantExpressions(Context)) return true; + if (LangOpts.OpenMP >= 52 && DSAStack->isIteratorVarDecl(VD)) + return true; return false; } return true; @@ -22235,10 +22536,21 @@ OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority, StartLoc, LParenLoc, EndLoc); } -OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { +OMPClause *Sema::ActOnOpenMPGrainsizeClause( + OpenMPGrainsizeClauseModifier Modifier, Expr *Grainsize, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation EndLoc) { + assert((ModifierLoc.isInvalid() || LangOpts.OpenMP >= 51) && + "Unexpected grainsize modifier in OpenMP < 51."); + + if (ModifierLoc.isValid() && Modifier == OMPC_GRAINSIZE_unknown) { + std::string Values = getListOfPossibleValues(OMPC_grainsize, /*First=*/0, + OMPC_GRAINSIZE_unknown); + Diag(ModifierLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_grainsize); + return nullptr; + } + Expr *ValExpr = Grainsize; Stmt *HelperValStmt = nullptr; OpenMPDirectiveKind CaptureRegion = OMPD_unknown; @@ -22246,20 +22558,33 @@ OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize, // OpenMP [2.9.2, taskloop Constrcut] // The parameter of the grainsize clause must be a positive integer // expression. - if (!isNonNegativeIntegerValue( - ValExpr, *this, OMPC_grainsize, - /*StrictlyPositive=*/true, /*BuildCapture=*/true, - DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt)) + if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize, + /*StrictlyPositive=*/true, + /*BuildCapture=*/true, + DSAStack->getCurrentDirective(), + &CaptureRegion, &HelperValStmt)) return nullptr; - return new (Context) OMPGrainsizeClause(ValExpr, HelperValStmt, CaptureRegion, - StartLoc, LParenLoc, EndLoc); + return new (Context) + OMPGrainsizeClause(Modifier, ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, ModifierLoc, EndLoc); } -OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { +OMPClause *Sema::ActOnOpenMPNumTasksClause( + OpenMPNumTasksClauseModifier Modifier, Expr *NumTasks, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation EndLoc) { + assert((ModifierLoc.isInvalid() || LangOpts.OpenMP >= 51) && + "Unexpected num_tasks modifier in OpenMP < 51."); + + if (ModifierLoc.isValid() && Modifier == OMPC_NUMTASKS_unknown) { + std::string Values = getListOfPossibleValues(OMPC_num_tasks, /*First=*/0, + OMPC_NUMTASKS_unknown); + Diag(ModifierLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_num_tasks); + return nullptr; + } + Expr *ValExpr = NumTasks; Stmt *HelperValStmt = nullptr; OpenMPDirectiveKind CaptureRegion = OMPD_unknown; @@ -22273,8 +22598,9 @@ OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks, DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt)) return nullptr; - return new (Context) OMPNumTasksClause(ValExpr, HelperValStmt, CaptureRegion, - StartLoc, LParenLoc, EndLoc); + return new (Context) + OMPNumTasksClause(Modifier, ValExpr, HelperValStmt, CaptureRegion, + StartLoc, LParenLoc, ModifierLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, @@ -22384,7 +22710,7 @@ OMPClause *Sema::ActOnOpenMPDistScheduleClause( // OpenMP [2.7.1, Restrictions] // chunk_size must be a loop invariant integer expression with a positive // value. - if (Optional<llvm::APSInt> Result = + if (std::optional<llvm::APSInt> Result = ValExpr->getIntegerConstantExpr(Context)) { if (Result->isSigned() && !Result->isStrictlyPositive()) { Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause) @@ -22583,29 +22909,29 @@ void Sema::ActOnOpenMPDeclareTargetName(NamedDecl *ND, SourceLocation Loc, const unsigned Level = -1; auto *VD = cast<ValueDecl>(ND); - llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = + std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = OMPDeclareTargetDeclAttr::getActiveAttr(VD); - if (ActiveAttr && ActiveAttr.value()->getDevType() != DTCI.DT && - ActiveAttr.value()->getLevel() == Level) { + if (ActiveAttr && (*ActiveAttr)->getDevType() != DTCI.DT && + (*ActiveAttr)->getLevel() == Level) { Diag(Loc, diag::err_omp_device_type_mismatch) << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DTCI.DT) << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr( - ActiveAttr.value()->getDevType()); + (*ActiveAttr)->getDevType()); return; } - if (ActiveAttr && ActiveAttr.value()->getMapType() != MT && - ActiveAttr.value()->getLevel() == Level) { + if (ActiveAttr && (*ActiveAttr)->getMapType() != MT && + (*ActiveAttr)->getLevel() == Level) { Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND; return; } - if (ActiveAttr && ActiveAttr.value()->getLevel() == Level) + if (ActiveAttr && (*ActiveAttr)->getLevel() == Level) return; Expr *IndirectE = nullptr; bool IsIndirect = false; if (DTCI.Indirect) { - IndirectE = DTCI.Indirect.value(); + IndirectE = *DTCI.Indirect; if (!IndirectE) IsIndirect = true; } @@ -22623,13 +22949,14 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, if (!D || !isa<VarDecl>(D)) return; auto *VD = cast<VarDecl>(D); - Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy = + std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); if (SemaRef.LangOpts.OpenMP >= 50 && (SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) || SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) && VD->hasGlobalStorage()) { - if (!MapTy || *MapTy != OMPDeclareTargetDeclAttr::MT_To) { + if (!MapTy || (*MapTy != OMPDeclareTargetDeclAttr::MT_To && + *MapTy != OMPDeclareTargetDeclAttr::MT_Enter)) { // OpenMP 5.0, 2.12.7 declare target Directive, Restrictions // If a lambda declaration and definition appears between a // declare target directive and the matching end declare target @@ -22678,7 +23005,7 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D)) D = FTD->getTemplatedDecl(); if (auto *FD = dyn_cast<FunctionDecl>(D)) { - llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = + std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD); if (IdLoc.isValid() && Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) { Diag(IdLoc, diag::err_omp_function_in_link_clause); @@ -22696,22 +23023,25 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, // Checking declaration inside declare target region. if (isa<VarDecl>(D) || isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { - llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = + std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = OMPDeclareTargetDeclAttr::getActiveAttr(VD); unsigned Level = DeclareTargetNesting.size(); - if (ActiveAttr && ActiveAttr.value()->getLevel() >= Level) + if (ActiveAttr && (*ActiveAttr)->getLevel() >= Level) return; DeclareTargetContextInfo &DTCI = DeclareTargetNesting.back(); Expr *IndirectE = nullptr; bool IsIndirect = false; if (DTCI.Indirect) { - IndirectE = DTCI.Indirect.value(); + IndirectE = *DTCI.Indirect; if (!IndirectE) IsIndirect = true; } auto *A = OMPDeclareTargetDeclAttr::CreateImplicit( - Context, OMPDeclareTargetDeclAttr::MT_To, DTCI.DT, IndirectE, - IsIndirect, Level, SourceRange(DTCI.Loc, DTCI.Loc)); + Context, + getLangOpts().OpenMP >= 52 ? OMPDeclareTargetDeclAttr::MT_Enter + : OMPDeclareTargetDeclAttr::MT_To, + DTCI.DT, IndirectE, IsIndirect, Level, + SourceRange(DTCI.Loc, DTCI.Loc)); D->addAttr(A); if (ASTMutationListener *ML = Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPDeclareTarget(D, A); @@ -23065,13 +23395,17 @@ OMPClause *Sema::ActOnOpenMPHasDeviceAddrClause(ArrayRef<Expr *> VarList, // Store the components in the stack so that they can be used to check // against other clauses later on. + Expr *Component = SimpleRefExpr; + auto *VD = dyn_cast<VarDecl>(D); + if (VD && (isa<OMPArraySectionExpr>(RefExpr->IgnoreParenImpCasts()) || + isa<ArraySubscriptExpr>(RefExpr->IgnoreParenImpCasts()))) + Component = DefaultFunctionArrayLvalueConversion(SimpleRefExpr).get(); OMPClauseMappableExprCommon::MappableComponent MC( - SimpleRefExpr, D, /*IsNonContiguous=*/false); + Component, D, /*IsNonContiguous=*/false); DSAStack->addMappableExpressionComponents( D, MC, /*WhereFoundClauseKind=*/OMPC_has_device_addr); // Record the expression we've just processed. - auto *VD = dyn_cast<VarDecl>(D); if (!VD && !CurContext->isDependentContext()) { DeclRefExpr *Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); @@ -23336,17 +23670,26 @@ OMPClause *Sema::ActOnOpenMPUsesAllocatorClause( AllocatorExpr = D.Allocator->IgnoreParenImpCasts(); auto *DRE = dyn_cast<DeclRefExpr>(AllocatorExpr); bool IsPredefinedAllocator = false; - if (DRE) - IsPredefinedAllocator = PredefinedAllocators.count(DRE->getDecl()); - if (!DRE || - !(Context.hasSameUnqualifiedType( - AllocatorExpr->getType(), DSAStack->getOMPAllocatorHandleT()) || - Context.typesAreCompatible(AllocatorExpr->getType(), - DSAStack->getOMPAllocatorHandleT(), - /*CompareUnqualified=*/true)) || - (!IsPredefinedAllocator && - (AllocatorExpr->getType().isConstant(Context) || - !AllocatorExpr->isLValue()))) { + if (DRE) { + OMPAllocateDeclAttr::AllocatorTypeTy AllocatorTy = + getAllocatorKind(*this, DSAStack, AllocatorExpr); + IsPredefinedAllocator = + AllocatorTy != + OMPAllocateDeclAttr::AllocatorTypeTy::OMPUserDefinedMemAlloc; + } + QualType OMPAllocatorHandleT = DSAStack->getOMPAllocatorHandleT(); + QualType AllocatorExprType = AllocatorExpr->getType(); + bool IsTypeCompatible = IsPredefinedAllocator; + IsTypeCompatible = IsTypeCompatible || + Context.hasSameUnqualifiedType(AllocatorExprType, + OMPAllocatorHandleT); + IsTypeCompatible = + IsTypeCompatible || + Context.typesAreCompatible(AllocatorExprType, OMPAllocatorHandleT); + bool IsNonConstantLValue = + !AllocatorExprType.isConstant(Context) && AllocatorExpr->isLValue(); + if (!DRE || !IsTypeCompatible || + (!IsPredefinedAllocator && !IsNonConstantLValue)) { Diag(D.Allocator->getExprLoc(), diag::err_omp_var_expected) << "omp_allocator_handle_t" << (DRE ? 1 : 0) << AllocatorExpr->getType() << D.Allocator->getSourceRange(); @@ -23480,3 +23823,31 @@ OMPClause *Sema::ActOnOpenMPBindClause(OpenMPBindClauseKind Kind, return OMPBindClause::Create(Context, Kind, KindLoc, StartLoc, LParenLoc, EndLoc); } + +OMPClause *Sema::ActOnOpenMPXDynCGroupMemClause(Expr *Size, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + Expr *ValExpr = Size; + Stmt *HelperValStmt = nullptr; + + // OpenMP [2.5, Restrictions] + // The ompx_dyn_cgroup_mem expression must evaluate to a positive integer + // value. + if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_ompx_dyn_cgroup_mem, + /*StrictlyPositive=*/false)) + return nullptr; + + OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); + OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause( + DKind, OMPC_ompx_dyn_cgroup_mem, LangOpts.OpenMP); + if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { + ValExpr = MakeFullExpr(ValExpr).get(); + llvm::MapVector<const Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); + } + + return new (Context) OMPXDynCGroupMemClause( + ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc); +} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index d72cc33ed0f5..d68337a26d97 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -12,14 +12,17 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DependenceFlags.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/OperatorKinds.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -30,12 +33,13 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/Casting.h" #include <algorithm> #include <cstdlib> +#include <optional> using namespace clang; using namespace sema; @@ -63,9 +67,8 @@ static ExprResult CreateFunctionRefExpr( // being used. if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc)) return ExprError(); - DeclRefExpr *DRE = - DeclRefExpr::Create(S.Context, Fn->getQualifierLoc(), SourceLocation(), - Fn, false, Loc, Fn->getType(), VK_LValue, FoundDecl); + DeclRefExpr *DRE = new (S.Context) + DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo); if (HadMultipleCandidates) DRE->setHadMultipleCandidates(true); @@ -355,7 +358,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( if (Initializer->isValueDependent()) return NK_Dependent_Narrowing; - if (Optional<llvm::APSInt> IntConstantValue = + if (std::optional<llvm::APSInt> IntConstantValue = Initializer->getIntegerConstantExpr(Ctx)) { // Convert the integer to the floating type. llvm::APFloat Result(Ctx.getFloatTypeSemantics(ToType)); @@ -438,7 +441,7 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( if (Initializer->isValueDependent()) return NK_Dependent_Narrowing; - Optional<llvm::APSInt> OptInitializerValue; + std::optional<llvm::APSInt> OptInitializerValue; if (!(OptInitializerValue = Initializer->getIntegerConstantExpr(Ctx))) { // Such conversions on variables are always narrowing. return NK_Variable_Narrowing; @@ -637,7 +640,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, auto *Saved = new (Context) DFIDeducedMismatchArgs; Saved->FirstArg = Info.FirstArg; Saved->SecondArg = Info.SecondArg; - Saved->TemplateArgs = Info.take(); + Saved->TemplateArgs = Info.takeSugared(); Saved->CallArgIndex = Info.CallArgIndex; Result.Data = Saved; break; @@ -666,7 +669,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, } case Sema::TDK_SubstitutionFailure: - Result.Data = Info.take(); + Result.Data = Info.takeSugared(); if (Info.hasSFINAEDiagnostic()) { PartialDiagnosticAt *Diag = new (Result.Diagnostic) PartialDiagnosticAt( SourceLocation(), PartialDiagnostic::NullDiagnostic()); @@ -677,7 +680,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, case Sema::TDK_ConstraintsNotSatisfied: { CNSInfo *Saved = new (Context) CNSInfo; - Saved->TemplateArgs = Info.take(); + Saved->TemplateArgs = Info.takeSugared(); Saved->Satisfaction = Info.AssociatedConstraintsSatisfaction; Result.Data = Saved; break; @@ -685,6 +688,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, case Sema::TDK_Success: case Sema::TDK_NonDependentConversionFailure: + case Sema::TDK_AlreadyDiagnosed: llvm_unreachable("not a deduction failure"); } @@ -734,6 +738,7 @@ void DeductionFailureInfo::Destroy() { // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_AlreadyDiagnosed: break; } } @@ -771,6 +776,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() { // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_AlreadyDiagnosed: break; } @@ -806,6 +812,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() { // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_AlreadyDiagnosed: break; } @@ -837,6 +844,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() { // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_AlreadyDiagnosed: break; } @@ -868,24 +876,95 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() { // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_AlreadyDiagnosed: break; } return nullptr; } -llvm::Optional<unsigned> DeductionFailureInfo::getCallArgIndex() { +std::optional<unsigned> DeductionFailureInfo::getCallArgIndex() { switch (static_cast<Sema::TemplateDeductionResult>(Result)) { case Sema::TDK_DeducedMismatch: case Sema::TDK_DeducedMismatchNested: return static_cast<DFIDeducedMismatchArgs*>(Data)->CallArgIndex; default: - return llvm::None; + return std::nullopt; } } -bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed( +static bool FunctionsCorrespond(ASTContext &Ctx, const FunctionDecl *X, + const FunctionDecl *Y) { + if (!X || !Y) + return false; + if (X->getNumParams() != Y->getNumParams()) + return false; + for (unsigned I = 0; I < X->getNumParams(); ++I) + if (!Ctx.hasSameUnqualifiedType(X->getParamDecl(I)->getType(), + Y->getParamDecl(I)->getType())) + return false; + if (auto *FTX = X->getDescribedFunctionTemplate()) { + auto *FTY = Y->getDescribedFunctionTemplate(); + if (!FTY) + return false; + if (!Ctx.isSameTemplateParameterList(FTX->getTemplateParameters(), + FTY->getTemplateParameters())) + return false; + } + return true; +} + +static bool shouldAddReversedEqEq(Sema &S, SourceLocation OpLoc, + Expr *FirstOperand, FunctionDecl *EqFD) { + assert(EqFD->getOverloadedOperator() == + OverloadedOperatorKind::OO_EqualEqual); + // C++2a [over.match.oper]p4: + // A non-template function or function template F named operator== is a + // rewrite target with first operand o unless a search for the name operator!= + // in the scope S from the instantiation context of the operator expression + // finds a function or function template that would correspond + // ([basic.scope.scope]) to F if its name were operator==, where S is the + // scope of the class type of o if F is a class member, and the namespace + // scope of which F is a member otherwise. A function template specialization + // named operator== is a rewrite target if its function template is a rewrite + // target. + DeclarationName NotEqOp = S.Context.DeclarationNames.getCXXOperatorName( + OverloadedOperatorKind::OO_ExclaimEqual); + 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>(); + if (!RHSRec) + return true; + LookupResult Members(S, NotEqOp, OpLoc, + Sema::LookupNameKind::LookupMemberName); + S.LookupQualifiedName(Members, RHSRec->getDecl()); + Members.suppressDiagnostics(); + for (NamedDecl *Op : Members) + if (FunctionsCorrespond(S.Context, EqFD, Op->getAsFunction())) + return false; + return true; + } + // Otherwise the search scope is the namespace scope of which F is a member. + LookupResult NonMembers(S, NotEqOp, OpLoc, + Sema::LookupNameKind::LookupOperatorName); + S.LookupName(NonMembers, + S.getScopeForContext(EqFD->getEnclosingNamespaceContext())); + NonMembers.suppressDiagnostics(); + for (NamedDecl *Op : NonMembers) { + auto *FD = Op->getAsFunction(); + if(auto* UD = dyn_cast<UsingShadowDecl>(Op)) + FD = UD->getUnderlyingDecl()->getAsFunction(); + if (FunctionsCorrespond(S.Context, EqFD, FD) && + declaresSameEntity(cast<Decl>(EqFD->getDeclContext()), + cast<Decl>(Op->getDeclContext()))) + return false; + } + return true; +} + +bool OverloadCandidateSet::OperatorRewriteInfo::allowsReversed( OverloadedOperatorKind Op) { if (!AllowRewrittenCandidates) return false; @@ -893,14 +972,21 @@ bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed( } bool OverloadCandidateSet::OperatorRewriteInfo::shouldAddReversed( - ASTContext &Ctx, const FunctionDecl *FD) { - if (!shouldAddReversed(FD->getDeclName().getCXXOverloadedOperator())) + Sema &S, ArrayRef<Expr *> OriginalArgs, FunctionDecl *FD) { + auto Op = FD->getOverloadedOperator(); + if (!allowsReversed(Op)) return false; + if (Op == OverloadedOperatorKind::OO_EqualEqual) { + assert(OriginalArgs.size() == 2); + if (!shouldAddReversedEqEq( + S, OpLoc, /*FirstOperand in reversed args*/ OriginalArgs[1], FD)) + return false; + } // Don't bother adding a reversed candidate that can never be a better // match than the non-reversed version. return FD->getNumParams() != 2 || - !Ctx.hasSameUnqualifiedType(FD->getParamDecl(0)->getType(), - FD->getParamDecl(1)->getType()) || + !S.Context.hasSameUnqualifiedType(FD->getParamDecl(0)->getType(), + FD->getParamDecl(1)->getType()) || FD->hasAttr<EnableIfAttr>(); } @@ -1069,6 +1155,15 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, !shouldLinkPossiblyHiddenDecl(*I, New)) continue; + // C++20 [temp.friend] p9: A non-template friend declaration with a + // requires-clause shall be a definition. A friend function template + // with a constraint that depends on a template parameter from an + // enclosing template shall be a definition. Such a constrained friend + // function or function template declaration does not declare the same + // function or function template as a declaration in any other scope. + if (Context.FriendsDifferByConstraints(OldF, New)) + continue; + Match = *I; return Ovl_Match; } @@ -1185,25 +1280,52 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, !FunctionParamTypesAreEqual(OldType, NewType))) return true; - // C++ [temp.over.link]p4: - // The signature of a function template consists of its function - // signature, its return type and its template parameter list. The names - // of the template parameters are significant only for establishing the - // relationship between the template parameters and the rest of the - // signature. - // - // We check the return type and template parameter lists for function - // templates first; the remaining checks follow. - // - // However, we don't consider either of these when deciding whether - // a member introduced by a shadow declaration is hidden. - if (!UseMemberUsingDeclRules && NewTemplate && - (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), - OldTemplate->getTemplateParameters(), - false, TPL_TemplateMatch) || - !Context.hasSameType(Old->getDeclaredReturnType(), - New->getDeclaredReturnType()))) - return true; + if (NewTemplate) { + // C++ [temp.over.link]p4: + // The signature of a function template consists of its function + // signature, its return type and its template parameter list. The names + // of the template parameters are significant only for establishing the + // relationship between the template parameters and the rest of the + // signature. + // + // We check the return type and template parameter lists for function + // templates first; the remaining checks follow. + bool SameTemplateParameterList = TemplateParameterListsAreEqual( + NewTemplate->getTemplateParameters(), + OldTemplate->getTemplateParameters(), false, TPL_TemplateMatch); + bool SameReturnType = Context.hasSameType(Old->getDeclaredReturnType(), + New->getDeclaredReturnType()); + // FIXME(GH58571): Match template parameter list even for non-constrained + // template heads. This currently ensures that the code prior to C++20 is + // not newly broken. + bool ConstraintsInTemplateHead = + NewTemplate->getTemplateParameters()->hasAssociatedConstraints() || + OldTemplate->getTemplateParameters()->hasAssociatedConstraints(); + // C++ [namespace.udecl]p11: + // The set of declarations named by a using-declarator that inhabits a + // class C does not include member functions and member function + // templates of a base class that "correspond" to (and thus would + // conflict with) a declaration of a function or function template in + // C. + // Comparing return types is not required for the "correspond" check to + // decide whether a member introduced by a shadow declaration is hidden. + if (UseMemberUsingDeclRules && ConstraintsInTemplateHead && + !SameTemplateParameterList) + return true; + if (!UseMemberUsingDeclRules && + (!SameTemplateParameterList || !SameReturnType)) + return true; + } + + if (ConsiderRequiresClauses) { + Expr *NewRC = New->getTrailingRequiresClause(), + *OldRC = Old->getTrailingRequiresClause(); + if ((NewRC != nullptr) != (OldRC != nullptr)) + return true; + + if (NewRC && !AreConstraintExpressionsEqual(Old, OldRC, New, NewRC)) + return true; + } // If the function is a class member, its signature includes the // cv-qualifiers (if any) and ref-qualifier (if any) on the function itself. @@ -1221,14 +1343,15 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, if (!UseMemberUsingDeclRules && (OldMethod->getRefQualifier() == RQ_None || NewMethod->getRefQualifier() == RQ_None)) { - // C++0x [over.load]p2: - // - Member function declarations with the same name and the same - // parameter-type-list as well as member function template - // declarations with the same name, the same parameter-type-list, and - // the same template parameter lists cannot be overloaded if any of - // them, but not all, have a ref-qualifier (8.3.5). + // C++20 [over.load]p2: + // - Member function declarations with the same name, the same + // parameter-type-list, and the same trailing requires-clause (if + // any), as well as member function template declarations with the + // same name, the same parameter-type-list, the same trailing + // requires-clause (if any), and the same template-head, cannot be + // overloaded if any of them, but not all, have a ref-qualifier. Diag(NewMethod->getLocation(), diag::err_ref_qualifier_overload) - << NewMethod->getRefQualifier() << OldMethod->getRefQualifier(); + << NewMethod->getRefQualifier() << OldMethod->getRefQualifier(); Diag(OldMethod->getLocation(), diag::note_previous_declaration); } return true; @@ -1292,23 +1415,6 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, } } - if (ConsiderRequiresClauses) { - Expr *NewRC = New->getTrailingRequiresClause(), - *OldRC = Old->getTrailingRequiresClause(); - if ((NewRC != nullptr) != (OldRC != nullptr)) - // RC are most certainly different - these are overloads. - return true; - - if (NewRC) { - llvm::FoldingSetNodeID NewID, OldID; - NewRC->Profile(NewID, Context, /*Canonical=*/true); - OldRC->Profile(OldID, Context, /*Canonical=*/true); - if (NewID != OldID) - // RCs are not equivalent - these are overloads. - return true; - } - } - // The signatures match; this is not an overload. return false; } @@ -1620,7 +1726,7 @@ bool Sema::IsFunctionConversion(QualType FromType, QualType ToType, /// conversion. static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType, ImplicitConversionKind &ICK, Expr *From, - bool InOverloadResolution) { + bool InOverloadResolution, bool CStyle) { // We need at least one of these types to be a vector type to have a vector // conversion. if (!ToType->isVectorType() && !FromType->isVectorType()) @@ -1665,7 +1771,7 @@ static bool IsVectorConversion(Sema &S, QualType FromType, QualType ToType, if (S.isLaxVectorConversion(FromType, ToType) && S.anyAltivecTypes(FromType, ToType) && !S.areSameVectorElemTypes(FromType, ToType) && - !InOverloadResolution) { + !InOverloadResolution && !CStyle) { S.Diag(From->getBeginLoc(), diag::warn_deprecated_lax_vec_conv_all) << FromType << ToType; } @@ -1918,7 +2024,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // Pointer to member conversions (4.11). SCS.Second = ICK_Pointer_Member; } else if (IsVectorConversion(S, FromType, ToType, SecondICK, From, - InOverloadResolution)) { + InOverloadResolution, CStyle)) { SCS.Second = SecondICK; FromType = ToType.getUnqualifiedType(); } else if (!S.getLangOpts().CPlusPlus && @@ -2073,9 +2179,9 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // int can represent all the values of the source type; otherwise, // the source rvalue can be converted to an rvalue of type unsigned // int (C++ 4.5p1). - if (FromType->isPromotableIntegerType() && !FromType->isBooleanType() && + if (Context.isPromotableIntegerType(FromType) && !FromType->isBooleanType() && !FromType->isEnumeralType()) { - if (// We can promote any signed, promotable integer type to an int + if ( // We can promote any signed, promotable integer type to an int (FromType->isSignedIntegerType() || // We can promote any unsigned integer type whose size is // less than int to an int. @@ -2187,7 +2293,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // compatibility. if (From) { if (FieldDecl *MemberDecl = From->getSourceBitField()) { - Optional<llvm::APSInt> BitWidth; + std::optional<llvm::APSInt> BitWidth; if (FromType->isIntegralType(Context) && (BitWidth = MemberDecl->getBitWidth()->getIntegerConstantExpr(Context))) { @@ -3506,7 +3612,7 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, if (Info.ConstructorTmpl) S.AddTemplateOverloadCandidate( Info.ConstructorTmpl, Info.FoundDecl, - /*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs), + /*ExplicitArgs*/ nullptr, llvm::ArrayRef(Args, NumArgs), CandidateSet, SuppressUserConversions, /*PartialOverloading*/ false, AllowExplicit == AllowedExplicit::All); @@ -3514,8 +3620,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, - llvm::makeArrayRef(Args, NumArgs), - CandidateSet, SuppressUserConversions, + llvm::ArrayRef(Args, NumArgs), CandidateSet, + SuppressUserConversions, /*PartialOverloading*/ false, AllowExplicit == AllowedExplicit::All); } @@ -4495,15 +4601,6 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc, return ImplicitConversionSequence::Indistinguishable; } -/// Determine whether the given type is valid, e.g., it is not an invalid -/// C++ class. -static bool isTypeValid(QualType T) { - if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) - return !Record->isInvalidDecl(); - - return true; -} - static QualType withoutUnaligned(ASTContext &Ctx, QualType T) { if (!T.getQualifiers().hasUnaligned()) return T; @@ -4553,7 +4650,6 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, if (UnqualT1 == UnqualT2) { // Nothing to do. } else if (isCompleteType(Loc, OrigT2) && - isTypeValid(UnqualT1) && isTypeValid(UnqualT2) && IsDerivedFrom(Loc, UnqualT2, UnqualT1)) Conv |= ReferenceConversions::DerivedToBase; else if (UnqualT1->isObjCObjectOrInterfaceType() && @@ -5096,7 +5192,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, } if (CT->getSize().ugt(e)) { // Need an init from empty {}, is there one? - InitListExpr EmptyList(S.Context, From->getEndLoc(), None, + InitListExpr EmptyList(S.Context, From->getEndLoc(), std::nullopt, From->getEndLoc()); EmptyList.setType(S.Context.VoidTy); DfltElt = TryListConversion( @@ -5725,7 +5821,8 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, return ExprError(); case ImplicitConversionSequence::EllipsisConversion: - llvm_unreachable("ellipsis conversion in converted constant expression"); + case ImplicitConversionSequence::StaticObjectArgumentConversion: + llvm_unreachable("bad conversion in converted constant expression"); } // Check that we would only use permitted conversions. @@ -5760,9 +5857,9 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, // C++2a [intro.execution]p5: // A full-expression is [...] a constant-expression [...] - Result = - S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(), - /*DiscardedValue=*/false, /*IsConstexpr=*/true); + Result = S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(), + /*DiscardedValue=*/false, /*IsConstexpr=*/true, + CCE == Sema::CCEKind::CCEK_TemplateArg); if (Result.isInvalid()) return Result; @@ -5909,6 +6006,7 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) { case ImplicitConversionSequence::BadConversion: case ImplicitConversionSequence::AmbiguousConversion: case ImplicitConversionSequence::EllipsisConversion: + case ImplicitConversionSequence::StaticObjectArgumentConversion: break; case ImplicitConversionSequence::UserDefinedConversion: @@ -6242,7 +6340,7 @@ ExprResult Sema::PerformContextualImplicitConversion( HadMultipleCandidates, ExplicitConversions)) return ExprError(); - LLVM_FALLTHROUGH; + [[fallthrough]]; case OR_Deleted: // We'll complain below about a non-integral condition type. break; @@ -6422,8 +6520,11 @@ void Sema::AddOverloadCandidate( } } - if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() && - !Function->getAttr<TargetAttr>()->isDefaultVersion()) { + if (Function->isMultiVersion() && + ((Function->hasAttr<TargetAttr>() && + !Function->getAttr<TargetAttr>()->isDefaultVersion()) || + (Function->hasAttr<TargetVersionAttr>() && + !Function->getAttr<TargetVersionAttr>()->isDefaultVersion()))) { Candidate.Viable = false; Candidate.FailureKind = ovl_non_default_multiversion_function; return; @@ -6516,7 +6617,8 @@ void Sema::AddOverloadCandidate( if (Function->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckFunctionConstraints(Function, Satisfaction) || + if (CheckFunctionConstraints(Function, Satisfaction, /*Loc*/ {}, + /*ForOverloadResolution*/ true) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -6742,7 +6844,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, // very difficult. Ideally, we should handle them more gracefully. if (EIA->getCond()->isValueDependent() || !EIA->getCond()->EvaluateWithSubstitution( - Result, Context, Function, llvm::makeArrayRef(ConvertedArgs))) + Result, Context, Function, llvm::ArrayRef(ConvertedArgs))) return EIA; if (!Result.isInt() || !Result.getInt().getBoolValue()) @@ -6914,7 +7016,7 @@ void Sema::AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, } else { AddMethodCandidate(cast<CXXMethodDecl>(Decl), FoundDecl, ActingContext, ObjectType, ObjectClassification, Args, CandidateSet, - SuppressUserConversions, false, None, PO); + SuppressUserConversions, false, std::nullopt, PO); } } @@ -6994,17 +7096,27 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, Candidate.Viable = true; - if (Method->isStatic() || ObjectType.isNull()) - // The implicit object argument is ignored. + unsigned FirstConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0; + if (ObjectType.isNull()) Candidate.IgnoreObjectArgument = true; - else { - unsigned ConvIdx = PO == OverloadCandidateParamOrder::Reversed ? 1 : 0; + else if (Method->isStatic()) { + // [over.best.ics.general]p8 + // When the parameter is the implicit object parameter of a static member + // function, the implicit conversion sequence is a standard conversion + // sequence that is neither better nor worse than any other standard + // conversion sequence. + // + // This is a rule that was introduced in C++23 to support static lambdas. We + // apply it retroactively because we want to support static lambdas as an + // extension and it doesn't hurt previous code. + Candidate.Conversions[FirstConvIdx].setStaticObjectArgument(); + } else { // Determine the implicit conversion sequence for the object // parameter. - Candidate.Conversions[ConvIdx] = TryObjectArgumentInitialization( + Candidate.Conversions[FirstConvIdx] = TryObjectArgumentInitialization( *this, CandidateSet.getLocation(), ObjectType, ObjectClassification, Method, ActingContext); - if (Candidate.Conversions[ConvIdx].isBad()) { + if (Candidate.Conversions[FirstConvIdx].isBad()) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_conversion; return; @@ -7022,7 +7134,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, if (Method->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckFunctionConstraints(Method, Satisfaction) || + if (CheckFunctionConstraints(Method, Satisfaction, /*Loc*/ {}, + /*ForOverloadResolution*/ true) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -7071,8 +7184,11 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, return; } - if (Method->isMultiVersion() && Method->hasAttr<TargetAttr>() && - !Method->getAttr<TargetAttr>()->isDefaultVersion()) { + if (Method->isMultiVersion() && + ((Method->hasAttr<TargetAttr>() && + !Method->getAttr<TargetAttr>()->isDefaultVersion()) || + (Method->hasAttr<TargetVersionAttr>() && + !Method->getAttr<TargetVersionAttr>()->isDefaultVersion()))) { Candidate.Viable = false; Candidate.FailureKind = ovl_non_default_multiversion_function; } @@ -7518,15 +7634,18 @@ void Sema::AddConversionCandidate( } if (EnableIfAttr *FailedAttr = - CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) { + CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; Candidate.DeductionFailure.Data = FailedAttr; return; } - if (Conversion->isMultiVersion() && Conversion->hasAttr<TargetAttr>() && - !Conversion->getAttr<TargetAttr>()->isDefaultVersion()) { + if (Conversion->isMultiVersion() && + ((Conversion->hasAttr<TargetAttr>() && + !Conversion->getAttr<TargetAttr>()->isDefaultVersion()) || + (Conversion->hasAttr<TargetVersionAttr>() && + !Conversion->getAttr<TargetVersionAttr>()->isDefaultVersion()))) { Candidate.Viable = false; Candidate.FailureKind = ovl_non_default_multiversion_function; } @@ -7689,7 +7808,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, } if (EnableIfAttr *FailedAttr = - CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) { + CheckEnableIf(Conversion, CandidateSet.getLocation(), std::nullopt)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; Candidate.DeductionFailure.Data = FailedAttr; @@ -7721,7 +7840,7 @@ void Sema::AddNonMemberOperatorCandidates( if (FunTmpl) { AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs, CandidateSet); - if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) + if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) AddTemplateOverloadCandidate( FunTmpl, F.getPair(), ExplicitTemplateArgs, {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false, @@ -7730,11 +7849,11 @@ void Sema::AddNonMemberOperatorCandidates( if (ExplicitTemplateArgs) continue; AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet); - if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) - AddOverloadCandidate(FD, F.getPair(), - {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, - false, false, true, false, ADLCallKind::NotADL, - None, OverloadCandidateParamOrder::Reversed); + if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) + AddOverloadCandidate( + FD, F.getPair(), {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, + false, false, true, false, ADLCallKind::NotADL, std::nullopt, + OverloadCandidateParamOrder::Reversed); } } } @@ -7781,12 +7900,17 @@ void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op, Operators.suppressDiagnostics(); for (LookupResult::iterator Oper = Operators.begin(), - OperEnd = Operators.end(); - Oper != OperEnd; - ++Oper) + OperEnd = Operators.end(); + Oper != OperEnd; ++Oper) { + if (Oper->getAsFunction() && + PO == OverloadCandidateParamOrder::Reversed && + !CandidateSet.getRewriteInfo().shouldAddReversed( + *this, {Args[1], Args[0]}, Oper->getAsFunction())) + continue; AddMethodCandidate(Oper.getPair(), Args[0]->getType(), Args[0]->Classify(Context), Args.slice(1), CandidateSet, /*SuppressUserConversion=*/false, PO); + } } } @@ -9312,7 +9436,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, case OO_Plus: // '+' is either unary or binary if (Args.size() == 1) OpBuilder.addUnaryPlusPointerOverloads(); - LLVM_FALLTHROUGH; + [[fallthrough]]; case OO_Minus: // '-' is either unary or binary if (Args.size() == 1) { @@ -9387,12 +9511,12 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, case OO_Equal: OpBuilder.addAssignmentMemberPointerOrEnumeralOverloads(); - LLVM_FALLTHROUGH; + [[fallthrough]]; case OO_PlusEqual: case OO_MinusEqual: OpBuilder.addAssignmentPointerOverloads(Op == OO_Equal); - LLVM_FALLTHROUGH; + [[fallthrough]]; case OO_StarEqual: case OO_SlashEqual: @@ -9482,12 +9606,13 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, /*AllowExplicit=*/true, /*AllowExplicitConversion=*/false, ADLCallKind::UsesADL); - if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) { + if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) { AddOverloadCandidate( FD, FoundDecl, {Args[1], Args[0]}, CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, /*AllowExplicit=*/true, /*AllowExplicitConversion=*/false, - ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed); + ADLCallKind::UsesADL, std::nullopt, + OverloadCandidateParamOrder::Reversed); } } else { auto *FTD = cast<FunctionTemplateDecl>(*I); @@ -9496,7 +9621,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, /*SuppressUserConversions=*/false, PartialOverloading, /*AllowExplicit=*/true, ADLCallKind::UsesADL); if (CandidateSet.getRewriteInfo().shouldAddReversed( - Context, FTD->getTemplatedDecl())) { + *this, Args, FTD->getTemplatedDecl())) { AddTemplateOverloadCandidate( FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]}, CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, @@ -9538,8 +9663,8 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1, llvm::FoldingSetNodeID Cand1ID, Cand2ID; for (auto Pair : zip_longest(Cand1Attrs, Cand2Attrs)) { - Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair); - Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair); + std::optional<EnableIfAttr *> Cand1A = std::get<0>(Pair); + std::optional<EnableIfAttr *> Cand2A = std::get<1>(Pair); // It's impossible for Cand1 to be better than (or equal to) Cand2 if Cand1 // has fewer enable_if attributes than Cand2, and vice versa. @@ -9617,12 +9742,12 @@ isBetterMultiversionCandidate(const OverloadCandidate &Cand1, } /// Compute the type of the implicit object parameter for the given function, -/// if any. Returns None if there is no implicit object parameter, and a null -/// QualType if there is a 'matches anything' implicit object parameter. -static Optional<QualType> getImplicitObjectParamType(ASTContext &Context, - const FunctionDecl *F) { +/// if any. Returns std::nullopt if there is no implicit object parameter, and a +/// null QualType if there is a 'matches anything' implicit object parameter. +static std::optional<QualType> +getImplicitObjectParamType(ASTContext &Context, const FunctionDecl *F) { if (!isa<CXXMethodDecl>(F) || isa<CXXConstructorDecl>(F)) - return llvm::None; + return std::nullopt; auto *M = cast<CXXMethodDecl>(F); // Static member functions' object parameters match all types. @@ -9642,7 +9767,7 @@ static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1, auto NextParam = [&](const FunctionDecl *F, unsigned &I, bool First) { if (First) { - if (Optional<QualType> T = getImplicitObjectParamType(Context, F)) + if (std::optional<QualType> T = getImplicitObjectParamType(Context, F)) return *T; } assert(I < F->getNumParams()); @@ -9662,19 +9787,13 @@ static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1, /// We're allowed to use constraints partial ordering only if the candidates /// have the same parameter types: -/// [temp.func.order]p6.2.2 [...] or if the function parameters that -/// positionally correspond between the two templates are not of the same type, -/// neither template is more specialized than the other. /// [over.match.best]p2.6 /// F1 and F2 are non-template functions with the same parameter-type-lists, /// and F1 is more constrained than F2 [...] -static bool canCompareFunctionConstraints(Sema &S, +static bool sameFunctionParameterTypeLists(Sema &S, const OverloadCandidate &Cand1, const OverloadCandidate &Cand2) { - // FIXME: Per P2113R0 we also need to compare the template parameter lists - // when comparing template functions. - if (Cand1.Function && Cand2.Function && Cand1.Function->hasPrototype() && - Cand2.Function->hasPrototype()) { + if (Cand1.Function && Cand2.Function) { auto *PT1 = cast<FunctionProtoType>(Cand1.Function->getFunctionType()); auto *PT2 = cast<FunctionProtoType>(Cand2.Function->getFunctionType()); if (PT1->getNumParams() == PT2->getNumParams() && @@ -9767,7 +9886,7 @@ bool clang::isBetterOverloadCandidate( } } - // C++ [over.match.best]p1: + // C++ [over.match.best]p1: (Changed in C++2b) // // -- if F is a static member function, ICS1(F) is defined such // that ICS1(F) is neither better nor worse than ICS1(G) for @@ -9917,22 +10036,28 @@ bool clang::isBetterOverloadCandidate( isa<CXXConversionDecl>(Cand1.Function) ? TPOC_Conversion : TPOC_Call, Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments, - Cand1.isReversed() ^ Cand2.isReversed(), - canCompareFunctionConstraints(S, Cand1, Cand2))) + Cand1.isReversed() ^ Cand2.isReversed())) return BetterTemplate == Cand1.Function->getPrimaryTemplate(); } // -— F1 and F2 are non-template functions with the same // parameter-type-lists, and F1 is more constrained than F2 [...], if (!Cand1IsSpecialization && !Cand2IsSpecialization && - canCompareFunctionConstraints(S, Cand1, Cand2)) { - Expr *RC1 = Cand1.Function->getTrailingRequiresClause(); - Expr *RC2 = Cand2.Function->getTrailingRequiresClause(); + sameFunctionParameterTypeLists(S, Cand1, Cand2)) { + FunctionDecl *Function1 = Cand1.Function; + FunctionDecl *Function2 = Cand2.Function; + if (FunctionDecl *MF = Function1->getInstantiatedFromMemberFunction()) + Function1 = MF; + if (FunctionDecl *MF = Function2->getInstantiatedFromMemberFunction()) + Function2 = MF; + + const Expr *RC1 = Function1->getTrailingRequiresClause(); + const Expr *RC2 = Function2->getTrailingRequiresClause(); if (RC1 && RC2) { bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function, {RC2}, + if (S.IsAtLeastAsConstrained(Function1, RC1, Function2, RC2, AtLeastAsConstrained1) || - S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, {RC1}, + S.IsAtLeastAsConstrained(Function2, RC2, Function1, RC1, AtLeastAsConstrained2)) return false; if (AtLeastAsConstrained1 != AtLeastAsConstrained2) @@ -10103,6 +10228,13 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations( } } +bool OverloadCandidate::NotValidBecauseConstraintExprHasError() const { + return FailureKind == ovl_fail_bad_deduction && + DeductionFailure.Result == Sema::TDK_ConstraintsNotSatisfied && + static_cast<CNSInfo *>(DeductionFailure.Data) + ->Satisfaction.ContainsErrors; +} + /// Computes the best viable function (C++ 13.3.3) /// within an overload candidate set. /// @@ -10155,10 +10287,18 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, Best = end(); for (auto *Cand : Candidates) { Cand->Best = false; - if (Cand->Viable) + if (Cand->Viable) { if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind)) Best = Cand; + } else if (Cand->NotValidBecauseConstraintExprHasError()) { + // This candidate has constraint that we were unable to evaluate because + // it referenced an expression that contained an error. Rather than fall + // back onto a potentially unintended candidate (made worse by + // subsuming constraints), treat this as 'no viable candidate'. + Best = end(); + return OR_No_Viable_Function; + } } // If we didn't find any viable functions, abort. @@ -10431,6 +10571,9 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, if (Fn->isMultiVersion() && Fn->hasAttr<TargetAttr>() && !Fn->getAttr<TargetAttr>()->isDefaultVersion()) return; + if (Fn->isMultiVersion() && Fn->hasAttr<TargetVersionAttr>() && + !Fn->getAttr<TargetVersionAttr>()->isDefaultVersion()) + return; if (shouldSkipNotingLambdaConversionDecl(Fn)) return; @@ -10774,10 +10917,13 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << ToTy << (unsigned)isObjectArgument << I + 1 << (unsigned)(Cand->Fix.Kind); - // If we can fix the conversion, suggest the FixIts. - for (std::vector<FixItHint>::iterator HI = Cand->Fix.Hints.begin(), - HE = Cand->Fix.Hints.end(); HI != HE; ++HI) - FDiag << *HI; + // Check that location of Fn is not in system header. + if (!S.SourceMgr.isInSystemHeader(Fn->getLocation())) { + // If we can fix the conversion, suggest the FixIts. + for (const FixItHint &HI : Cand->Fix.Hints) + FDiag << HI; + } + S.Diag(Fn->getLocation(), FDiag); MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); @@ -11483,6 +11629,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { switch ((Sema::TemplateDeductionResult)DFI.Result) { case Sema::TDK_Success: case Sema::TDK_NonDependentConversionFailure: + case Sema::TDK_AlreadyDiagnosed: llvm_unreachable("non-deduction failure while diagnosing bad deduction"); case Sema::TDK_Invalid: @@ -12239,6 +12386,9 @@ private: const auto *TA = FunDecl->getAttr<TargetAttr>(); if (TA && !TA->isDefaultVersion()) return false; + const auto *TVA = FunDecl->getAttr<TargetVersionAttr>(); + if (TVA && !TVA->isDefaultVersion()) + return false; } // If any candidate has a placeholder return type, trigger its deduction @@ -12501,20 +12651,24 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) { DeclAccessPair DAP; SmallVector<FunctionDecl *, 2> AmbiguousDecls; - auto CheckMoreConstrained = - [&] (FunctionDecl *FD1, FunctionDecl *FD2) -> Optional<bool> { - SmallVector<const Expr *, 1> AC1, AC2; - FD1->getAssociatedConstraints(AC1); - FD2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1)) - return None; - if (IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2)) - return None; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) - return None; - return AtLeastAsConstrained1; - }; + auto CheckMoreConstrained = [&](FunctionDecl *FD1, + FunctionDecl *FD2) -> std::optional<bool> { + if (FunctionDecl *MF = FD1->getInstantiatedFromMemberFunction()) + FD1 = MF; + if (FunctionDecl *MF = FD2->getInstantiatedFromMemberFunction()) + FD2 = MF; + SmallVector<const Expr *, 1> AC1, AC2; + FD1->getAssociatedConstraints(AC1); + FD2->getAssociatedConstraints(AC2); + bool AtLeastAsConstrained1, AtLeastAsConstrained2; + if (IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1)) + return std::nullopt; + if (IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2)) + return std::nullopt; + if (AtLeastAsConstrained1 == AtLeastAsConstrained2) + return std::nullopt; + return AtLeastAsConstrained1; + }; // Don't use the AddressOfResolver because we're specifically looking for // cases where we have one overload candidate that lacks @@ -12530,8 +12684,8 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) { // We have more than one result - see if it is more constrained than the // previous one. if (Result) { - Optional<bool> MoreConstrainedThanPrevious = CheckMoreConstrained(FD, - Result); + std::optional<bool> MoreConstrainedThanPrevious = + CheckMoreConstrained(FD, Result); if (!MoreConstrainedThanPrevious) { IsResultAmbiguous = true; AmbiguousDecls.push_back(FD); @@ -12569,7 +12723,7 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) { /// Returns false if resolveAddressOfSingleOverloadCandidate fails. /// Otherwise, returns true. This may emit diagnostics and return true. bool Sema::resolveAndFixAddressOfSingleOverloadCandidate( - ExprResult &SrcExpr, bool DoFunctionPointerConverion) { + ExprResult &SrcExpr, bool DoFunctionPointerConversion) { Expr *E = SrcExpr.get(); assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload"); @@ -12585,7 +12739,7 @@ bool Sema::resolveAndFixAddressOfSingleOverloadCandidate( DiagnoseUseOfDecl(Found, E->getExprLoc()); CheckAddressOfMemberAccess(E, DAP); Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found); - if (DoFunctionPointerConverion && Fixed->getType()->isFunctionType()) + if (DoFunctionPointerConversion && Fixed->getType()->isFunctionType()) SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false); else SrcExpr = Fixed; @@ -12687,10 +12841,9 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, // expression, regardless of whether or not it succeeded. Always // returns true if 'complain' is set. bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization( - ExprResult &SrcExpr, bool doFunctionPointerConverion, - bool complain, SourceRange OpRangeForComplaining, - QualType DestTypeForComplaining, - unsigned DiagIDForComplaining) { + ExprResult &SrcExpr, bool doFunctionPointerConversion, bool complain, + SourceRange OpRangeForComplaining, QualType DestTypeForComplaining, + unsigned DiagIDForComplaining) { assert(SrcExpr.get()->getType() == Context.OverloadTy); OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr.get()); @@ -12731,7 +12884,7 @@ bool Sema::ResolveAndFixSingleFunctionTemplateSpecialization( FixOverloadedFunctionReference(SrcExpr.get(), found, fn); // If desired, do function-to-pointer decay. - if (doFunctionPointerConverion) { + if (doFunctionPointerConversion) { SingleFunctionExpression = DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.get()); if (SingleFunctionExpression.isInvalid()) { @@ -13008,17 +13161,16 @@ DiagnoseTwoPhaseOperatorLookup(Sema &SemaRef, OverloadedOperatorKind Op, namespace { class BuildRecoveryCallExprRAII { Sema &SemaRef; + Sema::SatisfactionStackResetRAII SatStack; + public: - BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S) { + BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S), SatStack(S) { assert(SemaRef.IsBuildingRecoveryCallExpr == false); SemaRef.IsBuildingRecoveryCallExpr = true; } - ~BuildRecoveryCallExprRAII() { - SemaRef.IsBuildingRecoveryCallExpr = false; - } + ~BuildRecoveryCallExprRAII() { SemaRef.IsBuildingRecoveryCallExpr = false; } }; - } /// Attempts to recover from a call where no functions were found. @@ -13191,7 +13343,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, // Guess at what the return type for an unresolvable overload should be. static QualType chooseRecoveryType(OverloadCandidateSet &CS, OverloadCandidateSet::iterator *Best) { - llvm::Optional<QualType> Result; + std::optional<QualType> Result; // Adjust Type after seeing a candidate. auto ConsiderCandidate = [&](const OverloadCandidate &Candidate) { if (!Candidate.Function) @@ -13594,14 +13746,14 @@ void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet, // Add operator candidates that are member functions. AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet); - if (CandidateSet.getRewriteInfo().shouldAddReversed(Op)) + if (CandidateSet.getRewriteInfo().allowsReversed(Op)) AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet, OverloadCandidateParamOrder::Reversed); // In C++20, also add any rewritten member candidates. if (ExtraOp) { AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet); - if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp)) + if (CandidateSet.getRewriteInfo().allowsReversed(ExtraOp)) AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]}, CandidateSet, OverloadCandidateParamOrder::Reversed); @@ -13732,9 +13884,9 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); // Build the overload set. - OverloadCandidateSet CandidateSet( - OpLoc, OverloadCandidateSet::CSK_Operator, - OverloadCandidateSet::OperatorRewriteInfo(Op, AllowRewrittenCandidates)); + OverloadCandidateSet CandidateSet(OpLoc, OverloadCandidateSet::CSK_Operator, + OverloadCandidateSet::OperatorRewriteInfo( + Op, OpLoc, AllowRewrittenCandidates)); if (DefaultedFn) CandidateSet.exclude(DefaultedFn); LookupOverloadedBinOp(CandidateSet, Op, Fns, Args, PerformADL); @@ -13809,6 +13961,22 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (AmbiguousWithSelf) { Diag(FnDecl->getLocation(), diag::note_ovl_ambiguous_oper_binary_reversed_self); + // Mark member== const or provide matching != to disallow reversed + // args. Eg. + // struct S { bool operator==(const S&); }; + // S()==S(); + if (auto *MD = dyn_cast<CXXMethodDecl>(FnDecl)) + if (Op == OverloadedOperatorKind::OO_EqualEqual && + !MD->isConst() && + Context.hasSameUnqualifiedType( + MD->getThisObjectType(), + MD->getParamDecl(0)->getType().getNonReferenceType()) && + Context.hasSameUnqualifiedType(MD->getThisObjectType(), + Args[0]->getType()) && + Context.hasSameUnqualifiedType(MD->getThisObjectType(), + Args[1]->getType())) + Diag(FnDecl->getLocation(), + diag::note_ovl_ambiguous_eqeq_reversed_self_non_const); } else { Diag(FnDecl->getLocation(), diag::note_ovl_ambiguous_oper_binary_selected_candidate); @@ -13932,7 +14100,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, R = CreateOverloadedBinOp( OpLoc, Opc, Fns, IsReversed ? ZeroLiteral : R.get(), - IsReversed ? R.get() : ZeroLiteral, PerformADL, + IsReversed ? R.get() : ZeroLiteral, /*PerformADL=*/true, /*AllowRewrittenCandidates=*/false); popCodeSynthesisContext(); @@ -14206,7 +14374,7 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, MultiExprArg ArgExpr) { SmallVector<Expr *, 2> Args; Args.push_back(Base); - for (auto e : ArgExpr) { + for (auto *e : ArgExpr) { Args.push_back(e); } DeclarationName OpName = @@ -14271,12 +14439,17 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); SmallVector<Expr *, 2> MethodArgs; - ExprResult Arg0 = PerformObjectArgumentInitialization( - Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method); - if (Arg0.isInvalid()) - return ExprError(); - MethodArgs.push_back(Arg0.get()); + // Handle 'this' parameter if the selected function is not static. + if (Method->isInstance()) { + ExprResult Arg0 = PerformObjectArgumentInitialization( + Args[0], /*Qualifier=*/nullptr, Best->FoundDecl, Method); + if (Arg0.isInvalid()) + return ExprError(); + + MethodArgs.push_back(Arg0.get()); + } + bool IsError = PrepareArgumentsForCallToObjectOfClassType( *this, MethodArgs, Method, ArgExpr, LLoc); if (IsError) @@ -14296,9 +14469,16 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( - Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, RLoc, - CurFPFeatureOverrides()); + CallExpr *TheCall; + if (Method->isInstance()) + TheCall = CXXOperatorCallExpr::Create( + Context, OO_Subscript, FnExpr.get(), MethodArgs, ResultTy, VK, + RLoc, CurFPFeatureOverrides()); + else + TheCall = + CallExpr::Create(Context, FnExpr.get(), MethodArgs, ResultTy, VK, + RLoc, CurFPFeatureOverrides()); + if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl)) return ExprError(); @@ -14535,7 +14715,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Method = cast<CXXMethodDecl>(Best->Function); FoundDecl = Best->FoundDecl; CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); - if (DiagnoseUseOfDecl(Best->FoundDecl, UnresExpr->getNameLoc())) + if (DiagnoseUseOfOverloadedDecl(Best->FoundDecl, UnresExpr->getNameLoc())) break; // If FoundDecl is different from Method (such as if one is a template // and the other a specialization), make sure DiagnoseUseOfDecl is @@ -14544,7 +14724,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // DiagnoseUseOfDecl to accept both the FoundDecl and the decl // being used. if (Method != FoundDecl.getDecl() && - DiagnoseUseOfDecl(Method, UnresExpr->getNameLoc())) + DiagnoseUseOfOverloadedDecl(Method, UnresExpr->getNameLoc())) break; Succeeded = true; break; @@ -14874,15 +15054,18 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, bool IsError = false; - // Initialize the implicit object parameter. - ExprResult ObjRes = - PerformObjectArgumentInitialization(Object.get(), /*Qualifier=*/nullptr, - Best->FoundDecl, Method); - if (ObjRes.isInvalid()) - IsError = true; - else - Object = ObjRes; - MethodArgs.push_back(Object.get()); + // Initialize the implicit object parameter if needed. + // Since C++2b, this could also be a call to a static call operator + // which we emit as a regular CallExpr. + if (Method->isInstance()) { + ExprResult ObjRes = PerformObjectArgumentInitialization( + Object.get(), /*Qualifier=*/nullptr, Best->FoundDecl, Method); + if (ObjRes.isInvalid()) + IsError = true; + else + Object = ObjRes; + MethodArgs.push_back(Object.get()); + } IsError |= PrepareArgumentsForCallToObjectOfClassType( *this, MethodArgs, Method, Args, LParenLoc); @@ -14908,9 +15091,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( - Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc, - CurFPFeatureOverrides()); + CallExpr *TheCall; + if (Method->isInstance()) + TheCall = CXXOperatorCallExpr::Create(Context, OO_Call, NewFn.get(), + MethodArgs, ResultTy, VK, RParenLoc, + CurFPFeatureOverrides()); + else + TheCall = CallExpr::Create(Context, NewFn.get(), MethodArgs, ResultTy, VK, + RParenLoc, CurFPFeatureOverrides()); if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method)) return true; @@ -14956,7 +15144,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { AddMethodCandidate(Oper.getPair(), Base->getType(), Base->Classify(Context), - None, CandidateSet, /*SuppressUserConversion=*/false); + std::nullopt, CandidateSet, + /*SuppressUserConversion=*/false); } bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -15105,8 +15294,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, ResultTy = ResultTy.getNonLValueExprType(Context); UserDefinedLiteral *UDL = UserDefinedLiteral::Create( - Context, Fn.get(), llvm::makeArrayRef(ConvArgs, Args.size()), ResultTy, - VK, LitEndLoc, UDSuffixLoc, CurFPFeatureOverrides()); + Context, Fn.get(), llvm::ArrayRef(ConvArgs, Args.size()), ResultTy, VK, + LitEndLoc, UDSuffixLoc, CurFPFeatureOverrides()); if (CheckCallReturnType(FD->getReturnType(), UDSuffixLoc, UDL, FD)) return ExprError(); @@ -15146,7 +15335,8 @@ Sema::BuildForRangeBeginEndCall(SourceLocation Loc, *CallExpr = ExprError(); return FRS_DiagnosticIssued; } - *CallExpr = BuildCallExpr(S, MemberRef.get(), Loc, None, Loc, nullptr); + *CallExpr = + BuildCallExpr(S, MemberRef.get(), Loc, std::nullopt, Loc, nullptr); if (CallExpr->isInvalid()) { *CallExpr = ExprError(); return FRS_DiagnosticIssued; diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 7fdb34905b61..abbdc12e7047 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -737,11 +737,11 @@ ExprResult ObjCPropertyOpBuilder::buildGet() { assert(InstanceReceiver || RefExpr->isSuperReceiver()); msg = S.BuildInstanceMessageImplicit(InstanceReceiver, receiverType, GenericLoc, Getter->getSelector(), - Getter, None); + Getter, std::nullopt); } else { msg = S.BuildClassMessageImplicit(receiverType, RefExpr->isSuperReceiver(), - GenericLoc, Getter->getSelector(), - Getter, None); + GenericLoc, Getter->getSelector(), Getter, + std::nullopt); } return msg; } @@ -1200,7 +1200,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { /*TInfo=*/nullptr, SC_None, nullptr); - AtIndexGetter->setMethodParams(S.Context, Argument, None); + AtIndexGetter->setMethodParams(S.Context, Argument, std::nullopt); } if (!AtIndexGetter) { @@ -1316,7 +1316,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { SC_None, nullptr); Params.push_back(key); - AtIndexSetter->setMethodParams(S.Context, Params, None); + AtIndexSetter->setMethodParams(S.Context, Params, std::nullopt); } if (!AtIndexSetter) { diff --git a/clang/lib/Sema/SemaRISCVVectorLookup.cpp b/clang/lib/Sema/SemaRISCVVectorLookup.cpp index 50fd841c231b..7716dfb15458 100644 --- a/clang/lib/Sema/SemaRISCVVectorLookup.cpp +++ b/clang/lib/Sema/SemaRISCVVectorLookup.cpp @@ -20,6 +20,7 @@ #include "clang/Sema/Sema.h" #include "clang/Support/RISCVVIntrinsicUtils.h" #include "llvm/ADT/SmallVector.h" +#include <optional> #include <string> #include <vector> @@ -66,7 +67,7 @@ static const RVVIntrinsicRecord RVVIntrinsicRecords[] = { // Get subsequence of signature table. static ArrayRef<PrototypeDescriptor> ProtoSeq2ArrayRef(uint16_t Index, uint8_t Length) { - return makeArrayRef(&RVVSignatureTable[Index], Length); + return ArrayRef(&RVVSignatureTable[Index], Length); } static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) { @@ -115,7 +116,7 @@ static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) { llvm_unreachable("Unhandled type."); } if (Type->isVector()) - QT = Context.getScalableVectorType(QT, Type->getScale().getValue()); + QT = Context.getScalableVectorType(QT, *Type->getScale()); if (Type->isConstant()) QT = Context.getConstType(QT); @@ -132,6 +133,7 @@ class RISCVIntrinsicManagerImpl : public sema::RISCVIntrinsicManager { private: Sema &S; ASTContext &Context; + RVVTypeCache TypeCache; // List of all RVV intrinsic. std::vector<RVVIntrinsicDef> IntrinsicList; @@ -146,7 +148,7 @@ private: // Create RVVIntrinsicDef. void InitRVVIntrinsic(const RVVIntrinsicRecord &Record, StringRef SuffixStr, StringRef OverloadedSuffixStr, bool IsMask, - RVVTypes &Types); + RVVTypes &Types, bool HasPolicy, Policy PolicyAttrs); // Create FunctionDecl for a vector intrinsic. void CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II, @@ -185,15 +187,32 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() { ArrayRef<PrototypeDescriptor> OverloadedSuffixProto = ProtoSeq2ArrayRef( Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize); + PolicyScheme UnMaskedPolicyScheme = + static_cast<PolicyScheme>(Record.UnMaskedPolicyScheme); + PolicyScheme MaskedPolicyScheme = + static_cast<PolicyScheme>(Record.MaskedPolicyScheme); + + const Policy DefaultPolicy(Record.HasTailPolicy, Record.HasMaskPolicy); + llvm::SmallVector<PrototypeDescriptor> ProtoSeq = RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, - Record.HasVL, Record.NF); + Record.HasVL, Record.NF, + UnMaskedPolicyScheme, DefaultPolicy); llvm::SmallVector<PrototypeDescriptor> ProtoMaskSeq = - RVVIntrinsic::computeBuiltinTypes(BasicProtoSeq, /*IsMasked=*/true, - Record.HasMaskedOffOperand, - Record.HasVL, Record.NF); + RVVIntrinsic::computeBuiltinTypes( + BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand, + Record.HasVL, Record.NF, MaskedPolicyScheme, DefaultPolicy); + + bool UnMaskedHasPolicy = UnMaskedPolicyScheme != PolicyScheme::SchemeNone; + bool MaskedHasPolicy = MaskedPolicyScheme != PolicyScheme::SchemeNone; + SmallVector<Policy> SupportedUnMaskedPolicies = + RVVIntrinsic::getSupportedUnMaskedPolicies(Record.HasTailPolicy, + Record.HasMaskPolicy); + SmallVector<Policy> SupportedMaskedPolicies = + RVVIntrinsic::getSupportedMaskedPolicies(Record.HasTailPolicy, + Record.HasMaskPolicy); for (unsigned int TypeRangeMaskShift = 0; TypeRangeMaskShift <= static_cast<unsigned int>(BasicType::MaxOffset); @@ -229,46 +248,72 @@ void RISCVIntrinsicManagerImpl::InitIntrinsicList() { if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3)))) continue; - Optional<RVVTypes> Types = - RVVType::computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq); + std::optional<RVVTypes> Types = + TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq); // Ignored to create new intrinsic if there are any illegal types. - if (!Types.hasValue()) + if (!Types.has_value()) continue; - std::string SuffixStr = - RVVIntrinsic::getSuffixStr(BaseType, Log2LMUL, SuffixProto); + std::string SuffixStr = RVVIntrinsic::getSuffixStr( + TypeCache, BaseType, Log2LMUL, SuffixProto); std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr( - BaseType, Log2LMUL, OverloadedSuffixProto); + TypeCache, BaseType, Log2LMUL, OverloadedSuffixProto); // Create non-masked intrinsic. - InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types); - - if (Record.HasMasked) { - // Create masked intrinsic. - Optional<RVVTypes> MaskTypes = RVVType::computeTypes( - BaseType, Log2LMUL, Record.NF, ProtoMaskSeq); - - InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true, - *MaskTypes); + InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types, + UnMaskedHasPolicy, DefaultPolicy); + + // Create non-masked policy intrinsic. + if (Record.UnMaskedPolicyScheme != PolicyScheme::SchemeNone) { + for (auto P : SupportedUnMaskedPolicies) { + llvm::SmallVector<PrototypeDescriptor> PolicyPrototype = + RVVIntrinsic::computeBuiltinTypes( + BasicProtoSeq, /*IsMasked=*/false, + /*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF, + UnMaskedPolicyScheme, P); + std::optional<RVVTypes> PolicyTypes = TypeCache.computeTypes( + BaseType, Log2LMUL, Record.NF, PolicyPrototype); + InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, + /*IsMask=*/false, *PolicyTypes, UnMaskedHasPolicy, + P); + } } - } - } + if (!Record.HasMasked) + continue; + // Create masked intrinsic. + std::optional<RVVTypes> MaskTypes = + TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoMaskSeq); + InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true, + *MaskTypes, MaskedHasPolicy, DefaultPolicy); + if (Record.MaskedPolicyScheme == PolicyScheme::SchemeNone) + continue; + // Create masked policy intrinsic. + for (auto P : SupportedMaskedPolicies) { + llvm::SmallVector<PrototypeDescriptor> PolicyPrototype = + RVVIntrinsic::computeBuiltinTypes( + BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand, + Record.HasVL, Record.NF, MaskedPolicyScheme, P); + std::optional<RVVTypes> PolicyTypes = TypeCache.computeTypes( + BaseType, Log2LMUL, Record.NF, PolicyPrototype); + InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, + /*IsMask=*/true, *PolicyTypes, MaskedHasPolicy, P); + } + } // End for different LMUL + } // End for different TypeRange } } // Compute name and signatures for intrinsic with practical types. void RISCVIntrinsicManagerImpl::InitRVVIntrinsic( const RVVIntrinsicRecord &Record, StringRef SuffixStr, - StringRef OverloadedSuffixStr, bool IsMask, RVVTypes &Signature) { + StringRef OverloadedSuffixStr, bool IsMasked, RVVTypes &Signature, + bool HasPolicy, Policy PolicyAttrs) { // Function name, e.g. vadd_vv_i32m1. std::string Name = Record.Name; if (!SuffixStr.empty()) Name += "_" + SuffixStr.str(); - if (IsMask) - Name += "_m"; - // Overloaded function name, e.g. vadd. std::string OverloadedName; if (!Record.OverloadedName) @@ -280,8 +325,9 @@ void RISCVIntrinsicManagerImpl::InitRVVIntrinsic( // clang built-in function name, e.g. __builtin_rvv_vadd. std::string BuiltinName = "__builtin_rvv_" + std::string(Record.Name); - if (IsMask) - BuiltinName += "_m"; + + RVVIntrinsic::updateNamesAndPolicy(IsMasked, HasPolicy, Name, BuiltinName, + OverloadedName, PolicyAttrs); // Put into IntrinsicList. size_t Index = IntrinsicList.size(); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index c6ca10c0342c..f15603fd0bd4 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -382,7 +382,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { // type of the left operand could be used for SFINAE, so technically it is // *used*. if (DiagID != diag::warn_unused_comma_left_operand || !isSFINAEContext()) - DiagIfReachable(Loc, S ? llvm::makeArrayRef(S) : llvm::None, + DiagIfReachable(Loc, S ? llvm::ArrayRef(S) : std::nullopt, PDiag(DiagID) << R1 << R2); } @@ -1499,7 +1499,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // If switch has default case, then ignore it. if (!CaseListIsErroneous && !CaseListIsIncomplete && !HasConstantCond && ET && ET->getDecl()->isCompleteDefinition() && - !empty(ET->getDecl()->enumerators())) { + !ET->getDecl()->enumerators().empty()) { const EnumDecl *ED = ET->getDecl(); EnumValsTy EnumVals; @@ -2308,11 +2308,14 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, // If the type contained 'auto', deduce the 'auto' to 'id'. if (FirstType->getContainedAutoType()) { - OpaqueValueExpr OpaqueId(D->getLocation(), Context.getObjCIdType(), - VK_PRValue); + SourceLocation Loc = D->getLocation(); + OpaqueValueExpr OpaqueId(Loc, Context.getObjCIdType(), VK_PRValue); Expr *DeducedInit = &OpaqueId; - if (DeduceAutoType(D->getTypeSourceInfo(), DeducedInit, FirstType) == - DAR_Failed) + TemplateDeductionInfo Info(Loc); + FirstType = QualType(); + TemplateDeductionResult Result = DeduceAutoType( + D->getTypeSourceInfo()->getTypeLoc(), DeducedInit, FirstType, Info); + if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) DiagnoseAutoDeductionFailure(D, DeducedInit); if (FirstType.isNull()) { D->setInvalidDecl(); @@ -2376,10 +2379,16 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, // Deduce the type for the iterator variable now rather than leaving it to // AddInitializerToDecl, so we can produce a more suitable diagnostic. QualType InitType; - if ((!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) || - SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitType) == - Sema::DAR_Failed) + if (!isa<InitListExpr>(Init) && Init->getType()->isVoidType()) { SemaRef.Diag(Loc, DiagID) << Init->getType(); + } else { + TemplateDeductionInfo Info(Init->getExprLoc()); + Sema::TemplateDeductionResult Result = SemaRef.DeduceAutoType( + Decl->getTypeSourceInfo()->getTypeLoc(), Init, InitType, Info); + if (Result != Sema::TDK_Success && Result != Sema::TDK_AlreadyDiagnosed) + SemaRef.Diag(Loc, DiagID) << Init->getType(); + } + if (InitType.isNull()) { Decl->setInvalidDecl(); return true; @@ -2660,7 +2669,7 @@ BuildNonArrayForRange(Sema &SemaRef, Expr *BeginRange, Expr *EndRange, SemaRef.PDiag(diag::err_for_range_invalid) << BeginRange->getType() << BEFFound), SemaRef, OCD_AllCandidates, BeginRange); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Sema::FRS_DiagnosticIssued: for (NamedDecl *D : OldFound) { @@ -3769,17 +3778,13 @@ TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const { /// C++1y [dcl.spec.auto]p6. bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, SourceLocation ReturnLoc, - Expr *&RetExpr, - const AutoType *AT) { + Expr *RetExpr, const AutoType *AT) { // If this is the conversion function for a lambda, we choose to deduce its // type from the corresponding call operator, not from the synthesized return // statement within it. See Sema::DeduceReturnType. if (isLambdaConversionOperator(FD)) return false; - TypeLoc OrigResultType = getReturnTypeLoc(FD); - QualType Deduced; - if (RetExpr && isa<InitListExpr>(RetExpr)) { // If the deduction is for a return statement and the initializer is // a braced-init-list, the program is ill-formed. @@ -3799,87 +3804,74 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, return false; } - if (RetExpr) { - // Otherwise, [...] deduce a value for U using the rules of template - // argument deduction. - DeduceAutoResult DAR = DeduceAutoType(OrigResultType, RetExpr, Deduced); - - if (DAR == DAR_Failed && !FD->isInvalidDecl()) - Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure) - << OrigResultType.getType() << RetExpr->getType(); - - if (DAR != DAR_Succeeded) - return true; - - // If a local type is part of the returned type, mark its fields as - // referenced. - LocalTypedefNameReferencer Referencer(*this); - Referencer.TraverseType(RetExpr->getType()); - } else { - // For a function with a deduced result type to return void, - // the result type as written must be 'auto' or 'decltype(auto)', - // possibly cv-qualified or constrained, but not ref-qualified. + TypeLoc OrigResultType = getReturnTypeLoc(FD); + // In the case of a return with no operand, the initializer is considered + // to be void(). + CXXScalarValueInitExpr VoidVal(Context.VoidTy, nullptr, SourceLocation()); + if (!RetExpr) { + // For a function with a deduced result type to return with omitted + // expression, the result type as written must be 'auto' or + // 'decltype(auto)', possibly cv-qualified or constrained, but not + // ref-qualified. if (!OrigResultType.getType()->getAs<AutoType>()) { Diag(ReturnLoc, diag::err_auto_fn_return_void_but_not_auto) - << OrigResultType.getType(); + << OrigResultType.getType(); return true; } - // In the case of a return with no operand, the initializer is considered - // to be 'void()'. - Expr *Dummy = new (Context) CXXScalarValueInitExpr( - Context.VoidTy, - Context.getTrivialTypeSourceInfo(Context.VoidTy, ReturnLoc), ReturnLoc); - DeduceAutoResult DAR = DeduceAutoType(OrigResultType, Dummy, Deduced); - - if (DAR == DAR_Failed && !FD->isInvalidDecl()) - Diag(ReturnLoc, diag::err_auto_fn_deduction_failure) - << OrigResultType.getType() << Dummy->getType(); - - if (DAR != DAR_Succeeded) - return true; + RetExpr = &VoidVal; } - // CUDA: Kernel function must have 'void' return type. - if (getLangOpts().CUDA) - if (FD->hasAttr<CUDAGlobalAttr>() && !Deduced->isVoidType()) { - Diag(FD->getLocation(), diag::err_kern_type_not_void_return) - << FD->getType() << FD->getSourceRange(); + QualType Deduced = AT->getDeducedType(); + { + // Otherwise, [...] deduce a value for U using the rules of template + // argument deduction. + TemplateDeductionInfo Info(RetExpr->getExprLoc()); + TemplateDeductionResult Res = + DeduceAutoType(OrigResultType, RetExpr, Deduced, Info); + if (Res != TDK_Success && FD->isInvalidDecl()) return true; - } - - // If a function with a declared return type that contains a placeholder type - // has multiple return statements, the return type is deduced for each return - // statement. [...] if the type deduced is not the same in each deduction, - // the program is ill-formed. - QualType DeducedT = AT->getDeducedType(); - if (!DeducedT.isNull() && !FD->isInvalidDecl()) { - AutoType *NewAT = Deduced->getContainedAutoType(); - // It is possible that NewAT->getDeducedType() is null. When that happens, - // we should not crash, instead we ignore this deduction. - if (NewAT->getDeducedType().isNull()) - return false; - - CanQualType OldDeducedType = Context.getCanonicalFunctionResultType( - DeducedT); - CanQualType NewDeducedType = Context.getCanonicalFunctionResultType( - NewAT->getDeducedType()); - if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) { + switch (Res) { + case TDK_Success: + break; + case TDK_AlreadyDiagnosed: + return true; + case TDK_Inconsistent: { + // If a function with a declared return type that contains a placeholder + // type has multiple return statements, the return type is deduced for + // each return statement. [...] if the type deduced is not the same in + // each deduction, the program is ill-formed. const LambdaScopeInfo *LambdaSI = getCurLambda(); - if (LambdaSI && LambdaSI->HasImplicitReturnType) { + if (LambdaSI && LambdaSI->HasImplicitReturnType) Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) - << NewAT->getDeducedType() << DeducedT - << true /*IsLambda*/; - } else { + << Info.SecondArg << Info.FirstArg << true /*IsLambda*/; + else Diag(ReturnLoc, diag::err_auto_fn_different_deductions) - << (AT->isDecltypeAuto() ? 1 : 0) - << NewAT->getDeducedType() << DeducedT; - } + << (AT->isDecltypeAuto() ? 1 : 0) << Info.SecondArg + << Info.FirstArg; return true; } - } else if (!FD->isInvalidDecl()) { + default: + Diag(RetExpr->getExprLoc(), diag::err_auto_fn_deduction_failure) + << OrigResultType.getType() << RetExpr->getType(); + return true; + } + } + + // If a local type is part of the returned type, mark its fields as + // referenced. + LocalTypedefNameReferencer(*this).TraverseType(RetExpr->getType()); + + // CUDA: Kernel function must have 'void' return type. + if (getLangOpts().CUDA && FD->hasAttr<CUDAGlobalAttr>() && + !Deduced->isVoidType()) { + Diag(FD->getLocation(), diag::err_kern_type_not_void_return) + << FD->getType() << FD->getSourceRange(); + return true; + } + + if (!FD->isInvalidDecl() && AT->getDeducedType() != Deduced) // Update all declarations of the function to have the deduced return type. Context.adjustDeducedFunctionResultType(FD, Deduced); - } return false; } @@ -4695,11 +4687,11 @@ buildCapturedStmtCaptureList(Sema &S, CapturedRegionScopeInfo *RSI, if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) S.setOpenMPCaptureKind(Field, Cap.getVariable(), RSI->OpenMPLevel); - Captures.push_back(CapturedStmt::Capture(Cap.getLocation(), - Cap.isReferenceCapture() - ? CapturedStmt::VCK_ByRef - : CapturedStmt::VCK_ByCopy, - Cap.getVariable())); + Captures.push_back(CapturedStmt::Capture( + Cap.getLocation(), + Cap.isReferenceCapture() ? CapturedStmt::VCK_ByRef + : CapturedStmt::VCK_ByCopy, + cast<VarDecl>(Cap.getVariable()))); } CaptureInits.push_back(Init.get()); } diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 8dfcf9899e3f..97400483c63a 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -24,6 +24,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/MC/MCParser/MCAsmParser.h" +#include <optional> using namespace clang; using namespace sema; @@ -330,7 +331,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, if (RequireCompleteType(OutputExpr->getBeginLoc(), Exprs[i]->getType(), diag::err_dereference_incomplete_type)) return StmtError(); - LLVM_FALLTHROUGH; + [[fallthrough]]; default: return StmtError(Diag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_lvalue_in_output) @@ -377,6 +378,11 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, Expr *InputExpr = Exprs[i]; + if (InputExpr->getType()->isMemberPointerType()) + return StmtError(Diag(InputExpr->getBeginLoc(), + diag::err_asm_pmf_through_constraint_not_permitted) + << InputExpr->getSourceRange()); + // Referring to parameters is not allowed in naked functions. if (CheckNakedParmReference(InputExpr, *this)) return StmtError(); @@ -454,7 +460,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, << Info.getConstraintStr(); } - Optional<SourceLocation> UnwindClobberLoc; + std::optional<SourceLocation> UnwindClobberLoc; // Check that the clobbers are valid. for (unsigned i = 0; i != NumClobbers; i++) { @@ -932,13 +938,24 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, bool IsSimple = (NumOutputs != 0 || NumInputs != 0); setFunctionHasBranchProtectedScope(); + bool InvalidOperand = false; for (uint64_t I = 0; I < NumOutputs + NumInputs; ++I) { - if (Exprs[I]->getType()->isBitIntType()) - return StmtError( - Diag(Exprs[I]->getBeginLoc(), diag::err_asm_invalid_type) - << Exprs[I]->getType() << (I < NumOutputs) - << Exprs[I]->getSourceRange()); + Expr *E = Exprs[I]; + if (E->getType()->isBitIntType()) { + InvalidOperand = true; + Diag(E->getBeginLoc(), diag::err_asm_invalid_type) + << E->getType() << (I < NumOutputs) + << E->getSourceRange(); + } else if (E->refersToBitField()) { + InvalidOperand = true; + FieldDecl *BitField = E->getSourceBitField(); + Diag(E->getBeginLoc(), diag::err_ms_asm_bitfield_unsupported) + << E->getSourceRange(); + Diag(BitField->getLocation(), diag::note_bitfield_decl); + } } + if (InvalidOperand) + return StmtError(); MSAsmStmt *NS = new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index b03c055a4f50..6d443837a4c5 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -19,6 +19,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/StringExtras.h" +#include <optional> using namespace clang; using namespace sema; @@ -306,21 +307,33 @@ CheckForIncompatibleAttributes(Sema &S, if (!DiagnoseMutualExclusions(S, Attrs)) return; - // There are 6 categories of loop hints attributes: vectorize, interleave, - // unroll, unroll_and_jam, pipeline and distribute. Except for distribute they - // come in two variants: a state form and a numeric form. The state form - // selectively defaults/enables/disables the transformation for the loop - // (for unroll, default indicates full unrolling rather than enabling the - // transformation). The numeric form form provides an integer hint (for - // example, unroll count) to the transformer. The following array accumulates - // the hints encountered while iterating through the attributes to check for - // compatibility. + enum CategoryType { + // For the following categories, they come in two variants: a state form and + // a numeric form. The state form may be one of default, enable, and + // disable. The numeric form provides an integer hint (for example, unroll + // count) to the transformer. + Vectorize, + Interleave, + UnrollAndJam, + Pipeline, + // For unroll, default indicates full unrolling rather than enabling the + // transformation. + Unroll, + // The loop distribution transformation only has a state form that is + // exposed by #pragma clang loop distribute (enable | disable). + Distribute, + // The vector predication only has a state form that is exposed by + // #pragma clang loop vectorize_predicate (enable | disable). + VectorizePredicate, + // This serves as a indicator to how many category are listed in this enum. + NumberOfCategories + }; + // The following array accumulates the hints encountered while iterating + // through the attributes to check for compatibility. struct { const LoopHintAttr *StateAttr; const LoopHintAttr *NumericAttr; - } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, - {nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}, - {nullptr, nullptr}}; + } HintAttrs[CategoryType::NumberOfCategories] = {}; for (const auto *I : Attrs) { const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I); @@ -329,16 +342,8 @@ CheckForIncompatibleAttributes(Sema &S, if (!LH) continue; + CategoryType Category = CategoryType::NumberOfCategories; LoopHintAttr::OptionType Option = LH->getOption(); - enum { - Vectorize, - Interleave, - Unroll, - UnrollAndJam, - Distribute, - Pipeline, - VectorizePredicate - } Category; switch (Option) { case LoopHintAttr::Vectorize: case LoopHintAttr::VectorizeWidth: @@ -369,7 +374,7 @@ CheckForIncompatibleAttributes(Sema &S, break; }; - assert(Category < sizeof(HintAttrs) / sizeof(HintAttrs[0])); + assert(Category != NumberOfCategories && "Unhandled loop hint option"); auto &CategoryState = HintAttrs[Category]; const LoopHintAttr *PrevAttr; if (Option == LoopHintAttr::Vectorize || @@ -420,7 +425,7 @@ static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A, unsigned UnrollFactor = 0; if (A.getNumArgs() == 1) { Expr *E = A.getArgAsExpr(0); - Optional<llvm::APSInt> ArgVal; + std::optional<llvm::APSInt> ArgVal; if (!(ArgVal = E->getIntegerConstantExpr(S.Context))) { S.Diag(A.getLoc(), diag::err_attribute_argument_type) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 1542a07713fb..4b144c239fa4 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -39,6 +39,7 @@ #include "llvm/ADT/StringExtras.h" #include <iterator> +#include <optional> using namespace clang; using namespace sema; @@ -109,7 +110,7 @@ NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D, return D; } - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { + if (const auto *Record = dyn_cast<CXXRecordDecl>(D)) { // C++ [temp.local]p1: // Like normal (non-template) classes, class templates have an // injected-class-name (Clause 9). The injected-class-name @@ -126,8 +127,7 @@ NamedDecl *Sema::getAsTemplateNameDecl(NamedDecl *D, if (Record->getDescribedClassTemplate()) return Record->getDescribedClassTemplate(); - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(Record)) + if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Record)) return Spec->getSpecializedTemplate(); } @@ -399,6 +399,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, LookupCtx = computeDeclContext(ObjectType); IsDependent = !LookupCtx && ObjectType->isDependentType(); assert((IsDependent || !ObjectType->isIncompleteType() || + !ObjectType->getAs<TagType>() || ObjectType->castAs<TagType>()->isBeingDefined()) && "Caller should have completed object type"); @@ -816,7 +817,7 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) return true; - llvm::Optional<unsigned> Note; + std::optional<unsigned> Note; QualType InstantiationTy; if (TagDecl *TD = dyn_cast<TagDecl>(Instantiation)) InstantiationTy = Context.getTypeDeclType(TD); @@ -941,7 +942,7 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, TemplateName Template = Arg.getAsTemplate().get(); TemplateArgument TArg; if (Arg.getEllipsisLoc().isValid()) - TArg = TemplateArgument(Template, Optional<unsigned int>()); + TArg = TemplateArgument(Template, std::optional<unsigned int>()); else TArg = Template; return TemplateArgumentLoc( @@ -1207,7 +1208,7 @@ static ExprResult formImmediatelyDeclaredConstraint( ImmediatelyDeclaredConstraint.get(), BO_LAnd, EllipsisLoc, /*RHS=*/nullptr, /*RParenLoc=*/SourceLocation(), - /*NumExpansions=*/None); + /*NumExpansions=*/std::nullopt); } /// Attach a type-constraint to a template parameter. @@ -1530,11 +1531,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, CheckValidDeclSpecifiers(); - if (TInfo->getType()->isUndeducedType()) { - Diag(D.getIdentifierLoc(), - diag::warn_cxx14_compat_template_nontype_parm_auto_type) - << QualType(TInfo->getType()->getContainedAutoType(), 0); - } + if (const auto *T = TInfo->getType()->getContainedDeducedType()) + if (isa<AutoType>(T)) + Diag(D.getIdentifierLoc(), + diag::warn_cxx14_compat_template_nontype_parm_auto_type) + << QualType(TInfo->getType()->getContainedAutoType(), 0); assert(S->isTemplateParamScope() && "Non-type template parameter not in template parameter scope!"); @@ -1591,9 +1592,10 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument)) return Param; - TemplateArgument Converted; - ExprResult DefaultRes = - CheckTemplateArgument(Param, Param->getType(), Default, Converted); + TemplateArgument SugaredConverted, CanonicalConverted; + ExprResult DefaultRes = CheckTemplateArgument( + Param, Param->getType(), Default, SugaredConverted, CanonicalConverted, + CTAK_Specified); if (DefaultRes.isInvalid()) { Param->setInvalidDecl(); return Param; @@ -1686,6 +1688,99 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S, return Param; } +namespace { +class ConstraintRefersToContainingTemplateChecker + : public TreeTransform<ConstraintRefersToContainingTemplateChecker> { + 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) { + CheckingRD = CheckingRD->getMostRecentDecl(); + + for (const DeclContext *DC = Friend->getLexicalDeclContext(); + DC && !DC->isFileContext(); DC = DC->getParent()) + if (const auto *RD = dyn_cast<CXXRecordDecl>(DC)) + if (CheckingRD == RD->getMostRecentDecl()) + Result = true; + } + + void CheckNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + assert(D->getDepth() <= TemplateDepth && + "Nothing should reference a value below the actual template depth, " + "depth is likely wrong"); + if (D->getDepth() != TemplateDepth) + Result = true; + + // Necessary because the type of the NTTP might be what refers to the parent + // constriant. + TransformType(D->getType()); + } + +public: + using inherited = TreeTransform<ConstraintRefersToContainingTemplateChecker>; + + ConstraintRefersToContainingTemplateChecker(Sema &SemaRef, + const FunctionDecl *Friend, + unsigned TemplateDepth) + : inherited(SemaRef), 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 + // 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) { + assert(TL.getDecl()->getDepth() <= TemplateDepth && + "Nothing should reference a value below the actual template depth, " + "depth is likely wrong"); + if (TL.getDecl()->getDepth() != TemplateDepth) + Result = true; + return inherited::TransformTemplateTypeParmType( + TLB, TL, + /*SuppressObjCLifetime=*/false); + } + + Decl *TransformDecl(SourceLocation Loc, Decl *D) { + if (!D) + return 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)) { + // No direct types to visit here I believe. + } else + llvm_unreachable("Don't know how to handle this declaration type yet"); + return D; + } +}; +} // namespace + +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)); + return Checker.getResult(); +} + /// ActOnTemplateParameterList - Builds a TemplateParameterList, optionally /// constrained by RequiresClause, that contains the template parameters in /// Params. @@ -1705,8 +1800,7 @@ Sema::ActOnTemplateParameterList(unsigned Depth, return TemplateParameterList::Create( Context, TemplateLoc, LAngleLoc, - llvm::makeArrayRef(Params.data(), Params.size()), - RAngleLoc, RequiresClause); + llvm::ArrayRef(Params.data(), Params.size()), RAngleLoc, RequiresClause); } static void SetNestedNameSpecifier(Sema &S, TagDecl *T, @@ -1985,8 +2079,8 @@ DeclResult Sema::CheckClassTemplate( SetNestedNameSpecifier(*this, NewClass, SS); if (NumOuterTemplateParamLists > 0) NewClass->setTemplateParameterListsInfo( - Context, llvm::makeArrayRef(OuterTemplateParamLists, - NumOuterTemplateParamLists)); + Context, + llvm::ArrayRef(OuterTemplateParamLists, NumOuterTemplateParamLists)); // Add alignment attributes if necessary; these attributes are checked when // the ASTContext lays out the structure. @@ -2284,10 +2378,12 @@ private: /*Depth*/ 0, Depth1IndexAdjustment + TTP->getIndex(), TTP->getIdentifier(), TTP->wasDeclaredWithTypename(), TTP->isParameterPack(), TTP->hasTypeConstraint(), - TTP->isExpandedParameterPack() ? - llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None); + TTP->isExpandedParameterPack() + ? std::optional<unsigned>(TTP->getNumExpansionParameters()) + : std::nullopt); if (const auto *TC = TTP->getTypeConstraint()) - SemaRef.SubstTypeConstraint(NewTTP, TC, Args); + SemaRef.SubstTypeConstraint(NewTTP, TC, Args, + /*EvaluateConstraint*/ true); if (TTP->hasDefaultArgument()) { TypeSourceInfo *InstantiatedDefaultArg = SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args, @@ -2444,6 +2540,8 @@ private: TInfo->getType(), TInfo, LocEnd, Ctor); Guide->setImplicit(); Guide->setParams(Params); + if (Ctor && Ctor->getTrailingRequiresClause()) + Guide->setTrailingRequiresClause(Ctor->getTrailingRequiresClause()); for (auto *Param : Params) Param->setDeclContext(Guide); @@ -2535,7 +2633,7 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template, // additional function template derived as above from a hypothetical // constructor C(). if (!AddedAny) - Transform.buildSimpleDeductionGuide(None); + Transform.buildSimpleDeductionGuide(std::nullopt); // -- An additional function template derived as above from a hypothetical // constructor C(C), called the copy deduction candidate. @@ -3411,7 +3509,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( // Fabricate an empty template parameter list for the invented header. return TemplateParameterList::Create(Context, SourceLocation(), - SourceLocation(), None, + SourceLocation(), std::nullopt, SourceLocation(), nullptr); } @@ -3496,45 +3594,54 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { static QualType checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, - const SmallVectorImpl<TemplateArgument> &Converted, + ArrayRef<TemplateArgument> Converted, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { ASTContext &Context = SemaRef.getASTContext(); + switch (BTD->getBuiltinTemplateKind()) { case BTK__make_integer_seq: { // Specializations of __make_integer_seq<S, T, N> are treated like // S<T, 0, ..., N-1>. + QualType OrigType = Converted[1].getAsType(); // C++14 [inteseq.intseq]p1: // T shall be an integer type. - if (!Converted[1].getAsType()->isIntegralType(Context)) { + if (!OrigType->isDependentType() && !OrigType->isIntegralType(Context)) { SemaRef.Diag(TemplateArgs[1].getLocation(), diag::err_integer_sequence_integral_element_type); return QualType(); } - // C++14 [inteseq.make]p1: - // If N is negative the program is ill-formed. TemplateArgument NumArgsArg = Converted[2]; - llvm::APSInt NumArgs = NumArgsArg.getAsIntegral(); - if (NumArgs < 0) { + if (NumArgsArg.isDependent()) + return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), + Converted); + + TemplateArgumentListInfo SyntheticTemplateArgs; + // The type argument, wrapped in substitution sugar, gets reused as the + // first template argument in the synthetic template argument list. + SyntheticTemplateArgs.addArgument( + TemplateArgumentLoc(TemplateArgument(OrigType), + SemaRef.Context.getTrivialTypeSourceInfo( + OrigType, TemplateArgs[1].getLocation()))); + + if (llvm::APSInt NumArgs = NumArgsArg.getAsIntegral(); NumArgs >= 0) { + // Expand N into 0 ... N-1. + for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned()); + I < NumArgs; ++I) { + TemplateArgument TA(Context, I, OrigType); + SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc( + TA, OrigType, TemplateArgs[2].getLocation())); + } + } else { + // C++14 [inteseq.make]p1: + // If N is negative the program is ill-formed. SemaRef.Diag(TemplateArgs[2].getLocation(), diag::err_integer_sequence_negative_length); return QualType(); } - QualType ArgTy = NumArgsArg.getIntegralType(); - TemplateArgumentListInfo SyntheticTemplateArgs; - // The type argument gets reused as the first template argument in the - // synthetic template argument list. - SyntheticTemplateArgs.addArgument(TemplateArgs[1]); - // Expand N into 0 ... N-1. - for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned()); - I < NumArgs; ++I) { - TemplateArgument TA(Context, I, ArgTy); - SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc( - TA, ArgTy, TemplateArgs[2].getLocation())); - } // The first template argument will be reused as the template decl that // our synthetic template arguments will be applied to. return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(), @@ -3548,11 +3655,15 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, assert(Converted.size() == 2 && "__type_pack_element should be given an index and a parameter pack"); - // If the Index is out of bounds, the program is ill-formed. TemplateArgument IndexArg = Converted[0], Ts = Converted[1]; + if (IndexArg.isDependent() || Ts.isDependent()) + return Context.getCanonicalTemplateSpecializationType(TemplateName(BTD), + Converted); + llvm::APSInt Index = IndexArg.getAsIntegral(); assert(Index >= 0 && "the index used with __type_pack_element should be of " "type std::size_t, and hence be non-negative"); + // If the Index is out of bounds, the program is ill-formed. if (Index >= Ts.pack_size()) { SemaRef.Diag(TemplateArgs[0].getLocation(), diag::err_type_pack_element_out_of_bounds); @@ -3560,8 +3671,8 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, } // We simply return the type at index `Index`. - auto Nth = std::next(Ts.pack_begin(), Index.getExtValue()); - return Nth->getAsType(); + int64_t N = Index.getExtValue(); + return Ts.getPackAsArray()[N].getAsType(); } llvm_unreachable("unexpected BuiltinTemplateDecl!"); } @@ -3585,9 +3696,8 @@ static void collectConjunctionTerms(Expr *Clause, if (BinOp->getOpcode() == BO_LAnd) { collectConjunctionTerms(BinOp->getLHS(), Terms); collectConjunctionTerms(BinOp->getRHS(), Terms); + return; } - - return; } Terms.push_back(Clause); @@ -3715,10 +3825,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // assume the template is a type template. Either our assumption is // correct, or the code is ill-formed and will be diagnosed when the // dependent name is substituted. - return Context.getDependentTemplateSpecializationType(ETK_None, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + return Context.getDependentTemplateSpecializationType( + ETK_None, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); if (Name.getAsAssumedTemplateName() && resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc)) @@ -3730,7 +3839,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // We might have a substituted template template parameter pack. If so, // build a template specialization type for it. if (Name.getAsSubstTemplateTemplateParmPack()) - return Context.getTemplateSpecializationType(Name, TemplateArgs); + return Context.getTemplateSpecializationType(Name, + TemplateArgs.arguments()); Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name; @@ -3740,9 +3850,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Check that the template argument list is well-formed for this // template. - SmallVector<TemplateArgument, 4> Converted; - if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, - false, Converted, + SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; + if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, false, + SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return QualType(); @@ -3756,12 +3866,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, if (Pattern->isInvalidDecl()) return QualType(); - TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack, - Converted); - // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs); + TemplateArgLists.addOuterTemplateArguments(Template, CanonicalConverted, + /*Final=*/false); TemplateArgLists.addOuterRetainedLevels( AliasTemplate->getTemplateParameters()->getDepth()); @@ -3808,9 +3916,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, return QualType(); } + } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) { + CanonType = checkBuiltinTemplateIdType(*this, BTD, SugaredConverted, + TemplateLoc, TemplateArgs); } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs, Converted)) { + TemplateArgs, CanonicalConverted)) { // This class template specialization is a dependent // type. Therefore, its canonical type is another class template // specialization type that contains all of the converted @@ -3818,7 +3929,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // A<T, T> have identical types when A is declared as: // // template<typename T, typename U = T> struct A; - CanonType = Context.getCanonicalTemplateSpecializationType(Name, Converted); + CanonType = Context.getCanonicalTemplateSpecializationType( + Name, CanonicalConverted); // This might work out to be a current instantiation, in which // case the canonical type needs to be the InjectedClassNameType. @@ -3857,13 +3969,13 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, break; } } - } else if (ClassTemplateDecl *ClassTemplate - = dyn_cast<ClassTemplateDecl>(Template)) { + } else if (ClassTemplateDecl *ClassTemplate = + dyn_cast<ClassTemplateDecl>(Template)) { // Find the class template specialization declaration that // corresponds to these arguments. void *InsertPos = nullptr; - ClassTemplateSpecializationDecl *Decl - = ClassTemplate->findSpecialization(Converted, InsertPos); + ClassTemplateSpecializationDecl *Decl = + ClassTemplate->findSpecialization(CanonicalConverted, InsertPos); if (!Decl) { // This is the first time we have referenced this class template // specialization. Create the canonical declaration and add it to @@ -3872,7 +3984,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, Context, ClassTemplate->getTemplatedDecl()->getTagKind(), ClassTemplate->getDeclContext(), ClassTemplate->getTemplatedDecl()->getBeginLoc(), - ClassTemplate->getLocation(), ClassTemplate, Converted, nullptr); + ClassTemplate->getLocation(), ClassTemplate, CanonicalConverted, + nullptr); ClassTemplate->AddSpecialization(Decl, InsertPos); if (ClassTemplate->isOutOfLine()) Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext()); @@ -3882,8 +3995,9 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, ClassTemplate->getTemplatedDecl()->hasAttrs()) { InstantiatingTemplate Inst(*this, TemplateLoc, Decl); if (!Inst.isInvalid()) { - MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(Converted); + MultiLevelTemplateArgumentList TemplateArgLists(Template, + CanonicalConverted, + /*Final=*/false); InstantiateAttrsForDecl(TemplateArgLists, ClassTemplate->getTemplatedDecl(), Decl); } @@ -3895,15 +4009,15 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, CanonType = Context.getTypeDeclType(Decl); assert(isa<RecordType>(CanonType) && "type of non-dependent specialization is not a RecordType"); - } else if (auto *BTD = dyn_cast<BuiltinTemplateDecl>(Template)) { - CanonType = checkBuiltinTemplateIdType(*this, BTD, Converted, TemplateLoc, - TemplateArgs); + } else { + llvm_unreachable("Unhandled template kind"); } // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType); + return Context.getTemplateSpecializationType(Name, TemplateArgs.arguments(), + CanonType); } void Sema::ActOnUndeclaredTypeTemplateName(Scope *S, TemplateTy &ParsedName, @@ -3964,7 +4078,8 @@ TypeResult Sema::ActOnTemplateIdType( TemplateTy TemplateD, IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc, - bool IsCtorOrDtorName, bool IsClassName) { + bool IsCtorOrDtorName, bool IsClassName, + ImplicitTypenameContext AllowImplicitTypename) { if (SS.isInvalid()) return true; @@ -3978,9 +4093,18 @@ TypeResult Sema::ActOnTemplateIdType( // qualified-id denotes a type, forming an // elaborated-type-specifier (7.1.5.3). if (!LookupCtx && isDependentScopeSpecifier(SS)) { - Diag(SS.getBeginLoc(), diag::err_typename_missing_template) - << SS.getScopeRep() << TemplateII->getName(); - // Recover as if 'typename' were specified. + // C++2a relaxes some of those restrictions in [temp.res]p5. + if (AllowImplicitTypename == ImplicitTypenameContext::Yes) { + if (getLangOpts().CPlusPlus20) + Diag(SS.getBeginLoc(), diag::warn_cxx17_compat_implicit_typename); + else + Diag(SS.getBeginLoc(), diag::ext_implicit_typename) + << SS.getScopeRep() << TemplateII->getName() + << FixItHint::CreateInsertion(SS.getBeginLoc(), "typename "); + } else + Diag(SS.getBeginLoc(), diag::err_typename_missing_template) + << SS.getScopeRep() << TemplateII->getName(); + // FIXME: This is not quite correct recovery as we don't transform SS // into the corresponding dependent form (and we don't diagnose missing // 'template' keywords within SS as a result). @@ -4014,11 +4138,10 @@ TypeResult Sema::ActOnTemplateIdType( translateTemplateArguments(TemplateArgsIn, TemplateArgs); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { - QualType T - = Context.getDependentTemplateSpecializationType(ETK_None, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + assert(SS.getScopeRep() == DTN->getQualifier()); + QualType T = Context.getDependentTemplateSpecializationType( + ETK_None, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Build type-source information. TypeLocBuilder TLB; DependentTemplateSpecializationTypeLoc SpecTL @@ -4034,14 +4157,14 @@ TypeResult Sema::ActOnTemplateIdType( return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } - QualType Result = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); - if (Result.isNull()) + QualType SpecTy = CheckTemplateIdType(Template, TemplateIILoc, TemplateArgs); + if (SpecTy.isNull()) return true; // Build type-source information. TypeLocBuilder TLB; - TemplateSpecializationTypeLoc SpecTL - = TLB.push<TemplateSpecializationTypeLoc>(Result); + TemplateSpecializationTypeLoc SpecTL = + TLB.push<TemplateSpecializationTypeLoc>(SpecTy); SpecTL.setTemplateKeywordLoc(TemplateKWLoc); SpecTL.setTemplateNameLoc(TemplateIILoc); SpecTL.setLAngleLoc(LAngleLoc); @@ -4049,18 +4172,14 @@ TypeResult Sema::ActOnTemplateIdType( for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i) SpecTL.setArgLocInfo(i, TemplateArgs[i].getLocInfo()); - // NOTE: avoid constructing an ElaboratedTypeLoc if this is a - // constructor or destructor name (in such a case, the scope specifier - // will be attached to the enclosing Decl or Expr node). - if (SS.isNotEmpty() && !IsCtorOrDtorName) { - // Create an elaborated-type-specifier containing the nested-name-specifier. - Result = Context.getElaboratedType(ETK_None, SS.getScopeRep(), Result); - ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(Result); - ElabTL.setElaboratedKeywordLoc(SourceLocation()); + // Create an elaborated-type-specifier containing the nested-name-specifier. + QualType ElTy = getElaboratedType( + ETK_None, !IsCtorOrDtorName ? SS : CXXScopeSpec(), SpecTy); + ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(ElTy); + ElabTL.setElaboratedKeywordLoc(SourceLocation()); + if (!ElabTL.isEmpty()) ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); - } - - return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); + return CreateParsedType(ElTy, TLB.getTypeSourceInfo(Context, ElTy)); } TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, @@ -4088,10 +4207,10 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, = TypeWithKeyword::getKeywordForTagTypeKind(TagKind); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { - QualType T = Context.getDependentTemplateSpecializationType(Keyword, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + assert(SS.getScopeRep() == DTN->getQualifier()); + QualType T = Context.getDependentTemplateSpecializationType( + Keyword, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Build type-source information. TypeLocBuilder TLB; @@ -4386,9 +4505,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // Check that the template argument list is well-formed for this // template. - SmallVector<TemplateArgument, 4> Converted; + SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, - false, Converted, + false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -4396,21 +4515,22 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // corresponds to these arguments. if (IsPartialSpecialization) { if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, VarTemplate, - TemplateArgs.size(), Converted)) + TemplateArgs.size(), + CanonicalConverted)) return true; // FIXME: Move these checks to CheckTemplatePartialSpecializationArgs so we // also do them during instantiation. if (!Name.isDependent() && - !TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs, - Converted)) { + !TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, CanonicalConverted)) { Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) << VarTemplate->getDeclName(); IsPartialSpecialization = false; } if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(), - Converted) && + CanonicalConverted) && (!Context.getLangOpts().CPlusPlus20 || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: @@ -4431,10 +4551,10 @@ DeclResult Sema::ActOnVarTemplateSpecialization( VarTemplateSpecializationDecl *PrevDecl = nullptr; if (IsPartialSpecialization) - PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams, - InsertPos); + PrevDecl = VarTemplate->findPartialSpecialization( + CanonicalConverted, TemplateParams, InsertPos); else - PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos); + PrevDecl = VarTemplate->findSpecialization(CanonicalConverted, InsertPos); VarTemplateSpecializationDecl *Specialization = nullptr; @@ -4461,7 +4581,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( VarTemplatePartialSpecializationDecl::Create( Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC, - Converted, TemplateArgs); + CanonicalConverted, TemplateArgs); if (!PrevPartial) VarTemplate->AddPartialSpecialization(Partial, InsertPos); @@ -4478,7 +4598,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // this explicit specialization or friend declaration. Specialization = VarTemplateSpecializationDecl::Create( Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, - VarTemplate, DI->getType(), DI, SC, Converted); + VarTemplate, DI->getType(), DI, SC, CanonicalConverted); Specialization->setTemplateArgsInfo(TemplateArgs); if (!PrevDecl) @@ -4556,24 +4676,25 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, assert(Template && "A variable template id without template?"); // Check that the template argument list is well-formed for this template. - SmallVector<TemplateArgument, 4> Converted; + SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; if (CheckTemplateArgumentList( Template, TemplateNameLoc, const_cast<TemplateArgumentListInfo &>(TemplateArgs), false, - Converted, /*UpdateArgsWithConversions=*/true)) + SugaredConverted, CanonicalConverted, + /*UpdateArgsWithConversions=*/true)) return true; // Produce a placeholder value if the specialization is dependent. if (Template->getDeclContext()->isDependentContext() || - TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs, - Converted)) + TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, CanonicalConverted)) return DeclResult(); // Find the variable template specialization declaration that // corresponds to these arguments. void *InsertPos = nullptr; - if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization( - Converted, InsertPos)) { + if (VarTemplateSpecializationDecl *Spec = + Template->findSpecialization(CanonicalConverted, InsertPos)) { checkSpecializationReachability(TemplateNameLoc, Spec); // If we already have a variable template specialization, return it. return Spec; @@ -4585,7 +4706,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, // that it represents. That is, VarDecl *InstantiationPattern = Template->getTemplatedDecl(); TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack, - Converted); + CanonicalConverted); TemplateArgumentList *InstantiationArgs = &TemplateArgList; bool AmbiguousPartialSpec = false; typedef PartialSpecMatchResult MatchResult; @@ -4617,7 +4738,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, } else { Matched.push_back(PartialSpecMatchResult()); Matched.back().Partial = Partial; - Matched.back().Args = Info.take(); + Matched.back().Args = Info.takeCanonical(); } } @@ -4673,7 +4794,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, // FIXME: LateAttrs et al.? VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation( Template, InstantiationPattern, *InstantiationArgs, TemplateArgs, - Converted, TemplateNameLoc /*, LateAttrs, StartingScope*/); + CanonicalConverted, TemplateNameLoc /*, LateAttrs, StartingScope*/); if (!Decl) return true; @@ -4744,29 +4865,41 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, const TemplateArgumentListInfo *TemplateArgs) { assert(NamedConcept && "A concept template id without a template?"); - llvm::SmallVector<TemplateArgument, 4> Converted; - if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(), - const_cast<TemplateArgumentListInfo&>(*TemplateArgs), - /*PartialTemplateArgs=*/false, Converted, - /*UpdateArgsWithConversions=*/false)) + llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; + if (CheckTemplateArgumentList( + NamedConcept, ConceptNameInfo.getLoc(), + const_cast<TemplateArgumentListInfo &>(*TemplateArgs), + /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted, + /*UpdateArgsWithConversions=*/false)) return ExprError(); + auto *CSD = ImplicitConceptSpecializationDecl::Create( + Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(), + CanonicalConverted); ConstraintSatisfaction Satisfaction; bool AreArgsDependent = - TemplateSpecializationType::anyDependentTemplateArguments(*TemplateArgs, - Converted); + TemplateSpecializationType::anyDependentTemplateArguments( + *TemplateArgs, CanonicalConverted); + MultiLevelTemplateArgumentList MLTAL(NamedConcept, CanonicalConverted, + /*Final=*/false); + LocalInstantiationScope Scope(*this); + + EnterExpressionEvaluationContext EECtx{ + *this, ExpressionEvaluationContext::ConstantEvaluated, CSD}; + if (!AreArgsDependent && CheckConstraintSatisfaction( - NamedConcept, {NamedConcept->getConstraintExpr()}, Converted, + NamedConcept, {NamedConcept->getConstraintExpr()}, MLTAL, SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameInfo.getLoc(), TemplateArgs->getRAngleLoc()), Satisfaction)) return ExprError(); - return ConceptSpecializationExpr::Create(Context, + return ConceptSpecializationExpr::Create( + Context, SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, - ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted, + ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), CSD, AreArgsDependent ? nullptr : &Satisfaction); } @@ -5008,9 +5141,10 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S, return TNK_Non_template; } -bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, - TemplateArgumentLoc &AL, - SmallVectorImpl<TemplateArgument> &Converted) { +bool Sema::CheckTemplateTypeArgument( + TemplateTypeParmDecl *Param, TemplateArgumentLoc &AL, + SmallVectorImpl<TemplateArgument> &SugaredConverted, + SmallVectorImpl<TemplateArgument> &CanonicalConverted) { const TemplateArgument &Arg = AL.getArgument(); QualType ArgType; TypeSourceInfo *TSI = nullptr; @@ -5087,7 +5221,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, } } // fallthrough - LLVM_FALLTHROUGH; + [[fallthrough]]; } default: { // We have a template type parameter but the template argument @@ -5103,9 +5237,6 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, if (CheckTemplateArgument(TSI)) return true; - // Add the converted template type argument. - ArgType = Context.getCanonicalType(ArgType); - // Objective-C ARC: // If an explicitly-specified template argument type is a lifetime type // with no lifetime qualifier, the __strong lifetime qualifier is inferred. @@ -5117,7 +5248,9 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, ArgType = Context.getQualifiedType(ArgType, Qs); } - Converted.push_back(TemplateArgument(ArgType)); + SugaredConverted.push_back(TemplateArgument(ArgType)); + CanonicalConverted.push_back( + TemplateArgument(Context.getCanonicalType(ArgType))); return false; } @@ -5142,31 +5275,27 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, /// \param Converted the list of template arguments provided for template /// parameters that precede \p Param in the template parameter list. /// \returns the substituted template argument, or NULL if an error occurred. -static TypeSourceInfo * -SubstDefaultTemplateArgument(Sema &SemaRef, - TemplateDecl *Template, - SourceLocation TemplateLoc, - SourceLocation RAngleLoc, - TemplateTypeParmDecl *Param, - SmallVectorImpl<TemplateArgument> &Converted) { +static TypeSourceInfo *SubstDefaultTemplateArgument( + Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc, + SourceLocation RAngleLoc, TemplateTypeParmDecl *Param, + ArrayRef<TemplateArgument> SugaredConverted, + ArrayRef<TemplateArgument> CanonicalConverted) { TypeSourceInfo *ArgType = Param->getDefaultArgumentInfo(); // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. if (ArgType->getType()->isInstantiationDependentType()) { - Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, - Param, Template, Converted, + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template, + SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) return nullptr; - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - // Only substitute for the innermost template argument list. - MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted, + /*Final=*/true); for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) - TemplateArgLists.addOuterTemplateArguments(None); + TemplateArgLists.addOuterTemplateArguments(std::nullopt); bool ForLambdaCallOperator = false; if (const auto *Rec = dyn_cast<CXXRecordDecl>(Template->getDeclContext())) @@ -5203,26 +5332,22 @@ SubstDefaultTemplateArgument(Sema &SemaRef, /// parameters that precede \p Param in the template parameter list. /// /// \returns the substituted template argument, or NULL if an error occurred. -static ExprResult -SubstDefaultTemplateArgument(Sema &SemaRef, - TemplateDecl *Template, - SourceLocation TemplateLoc, - SourceLocation RAngleLoc, - NonTypeTemplateParmDecl *Param, - SmallVectorImpl<TemplateArgument> &Converted) { - Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, - Param, Template, Converted, +static ExprResult SubstDefaultTemplateArgument( + Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc, + SourceLocation RAngleLoc, NonTypeTemplateParmDecl *Param, + ArrayRef<TemplateArgument> SugaredConverted, + ArrayRef<TemplateArgument> CanonicalConverted) { + Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Param, Template, + SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) return ExprError(); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - // Only substitute for the innermost template argument list. - MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted, + /*Final=*/true); for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) - TemplateArgLists.addOuterTemplateArguments(None); + TemplateArgLists.addOuterTemplateArguments(std::nullopt); Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); EnterExpressionEvaluationContext ConstantEvaluated( @@ -5255,27 +5380,23 @@ SubstDefaultTemplateArgument(Sema &SemaRef, /// source-location information) that precedes the template name. /// /// \returns the substituted template argument, or NULL if an error occurred. -static TemplateName -SubstDefaultTemplateArgument(Sema &SemaRef, - TemplateDecl *Template, - SourceLocation TemplateLoc, - SourceLocation RAngleLoc, - TemplateTemplateParmDecl *Param, - SmallVectorImpl<TemplateArgument> &Converted, - NestedNameSpecifierLoc &QualifierLoc) { +static TemplateName SubstDefaultTemplateArgument( + Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc, + SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param, + ArrayRef<TemplateArgument> SugaredConverted, + ArrayRef<TemplateArgument> CanonicalConverted, + NestedNameSpecifierLoc &QualifierLoc) { Sema::InstantiatingTemplate Inst( - SemaRef, TemplateLoc, TemplateParameter(Param), Template, Converted, - SourceRange(TemplateLoc, RAngleLoc)); + SemaRef, TemplateLoc, TemplateParameter(Param), Template, + SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) return TemplateName(); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - // Only substitute for the innermost template argument list. - MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + MultiLevelTemplateArgumentList TemplateArgLists(Template, SugaredConverted, + /*Final=*/true); for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) - TemplateArgLists.addOuterTemplateArguments(None); + TemplateArgLists.addOuterTemplateArguments(std::nullopt); Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); // Substitute into the nested-name-specifier first, @@ -5297,14 +5418,11 @@ SubstDefaultTemplateArgument(Sema &SemaRef, /// If the given template parameter has a default template /// argument, substitute into that default template argument and /// return the corresponding template argument. -TemplateArgumentLoc -Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, - SourceLocation TemplateLoc, - SourceLocation RAngleLoc, - Decl *Param, - SmallVectorImpl<TemplateArgument> - &Converted, - bool &HasDefaultArg) { +TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable( + TemplateDecl *Template, SourceLocation TemplateLoc, + SourceLocation RAngleLoc, Decl *Param, + ArrayRef<TemplateArgument> SugaredConverted, + ArrayRef<TemplateArgument> CanonicalConverted, bool &HasDefaultArg) { HasDefaultArg = false; if (TemplateTypeParmDecl *TypeParm = dyn_cast<TemplateTypeParmDecl>(Param)) { @@ -5312,11 +5430,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, return TemplateArgumentLoc(); HasDefaultArg = true; - TypeSourceInfo *DI = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, - TypeParm, - Converted); + TypeSourceInfo *DI = SubstDefaultTemplateArgument( + *this, Template, TemplateLoc, RAngleLoc, TypeParm, SugaredConverted, + CanonicalConverted); if (DI) return TemplateArgumentLoc(TemplateArgument(DI->getType()), DI); @@ -5329,11 +5445,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, return TemplateArgumentLoc(); HasDefaultArg = true; - ExprResult Arg = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, - NonTypeParm, - Converted); + ExprResult Arg = SubstDefaultTemplateArgument( + *this, Template, TemplateLoc, RAngleLoc, NonTypeParm, SugaredConverted, + CanonicalConverted); if (Arg.isInvalid()) return TemplateArgumentLoc(); @@ -5348,12 +5462,9 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, HasDefaultArg = true; NestedNameSpecifierLoc QualifierLoc; - TemplateName TName = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, - TempTempParm, - Converted, - QualifierLoc); + TemplateName TName = SubstDefaultTemplateArgument( + *this, Template, TemplateLoc, RAngleLoc, TempTempParm, SugaredConverted, + CanonicalConverted, QualifierLoc); if (TName.isNull()) return TemplateArgumentLoc(); @@ -5423,17 +5534,17 @@ convertTypeTemplateArgumentToTemplate(ASTContext &Context, TypeLoc TLoc) { /// explicitly written, deduced, etc. /// /// \returns true on error, false otherwise. -bool Sema::CheckTemplateArgument(NamedDecl *Param, - TemplateArgumentLoc &Arg, - NamedDecl *Template, - SourceLocation TemplateLoc, - SourceLocation RAngleLoc, - unsigned ArgumentPackIndex, - SmallVectorImpl<TemplateArgument> &Converted, - CheckTemplateArgumentKind CTAK) { +bool Sema::CheckTemplateArgument( + NamedDecl *Param, TemplateArgumentLoc &Arg, NamedDecl *Template, + SourceLocation TemplateLoc, SourceLocation RAngleLoc, + unsigned ArgumentPackIndex, + SmallVectorImpl<TemplateArgument> &SugaredConverted, + SmallVectorImpl<TemplateArgument> &CanonicalConverted, + CheckTemplateArgumentKind CTAK) { // Check template type parameters. if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) - return CheckTemplateTypeArgument(TTP, Arg, Converted); + return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted, + CanonicalConverted); // Check non-type template parameters. if (NonTypeTemplateParmDecl *NTTP =dyn_cast<NonTypeTemplateParmDecl>(Param)) { @@ -5448,27 +5559,22 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, !isa<TemplateTemplateParmDecl>(Template) && !Template->getDeclContext()->isDependentContext()) { // Do substitution on the type of the non-type template parameter. - InstantiatingTemplate Inst(*this, TemplateLoc, Template, - NTTP, Converted, + InstantiatingTemplate Inst(*this, TemplateLoc, Template, NTTP, + SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) return true; - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted); - + MultiLevelTemplateArgumentList MLTAL(Template, SugaredConverted, + /*Final=*/true); // If the parameter is a pack expansion, expand this slice of the pack. if (auto *PET = NTTPType->getAs<PackExpansionType>()) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, ArgumentPackIndex); - NTTPType = SubstType(PET->getPattern(), - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), + NTTPType = SubstType(PET->getPattern(), MLTAL, NTTP->getLocation(), NTTP->getDeclName()); } else { - NTTPType = SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), + NTTPType = SubstType(NTTPType, MLTAL, NTTP->getLocation(), NTTP->getDeclName()); } @@ -5486,11 +5592,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, llvm_unreachable("Should never see a NULL template argument here"); case TemplateArgument::Expression: { - TemplateArgument Result; + Expr *E = Arg.getArgument().getAsExpr(); + TemplateArgument SugaredResult, CanonicalResult; unsigned CurSFINAEErrors = NumSFINAEErrors; - ExprResult Res = - CheckTemplateArgument(NTTP, NTTPType, Arg.getArgument().getAsExpr(), - Result, CTAK); + ExprResult Res = CheckTemplateArgument(NTTP, NTTPType, E, SugaredResult, + CanonicalResult, CTAK); if (Res.isInvalid()) return true; // If the current template argument causes an error, give up now. @@ -5499,12 +5605,13 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, // If the resulting expression is new, then use it in place of the // old expression in the template argument. - if (Res.get() != Arg.getArgument().getAsExpr()) { + if (Res.get() != E) { TemplateArgument TA(Res.get()); Arg = TemplateArgumentLoc(TA, Res.get()); } - Converted.push_back(Result); + SugaredConverted.push_back(SugaredResult); + CanonicalConverted.push_back(CanonicalResult); break; } @@ -5513,7 +5620,9 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::NullPtr: // We've already checked this template argument, so just copy // it to the list of converted arguments. - Converted.push_back(Arg.getArgument()); + SugaredConverted.push_back(Arg.getArgument()); + CanonicalConverted.push_back( + Context.getCanonicalTemplateArgument(Arg.getArgument())); break; case TemplateArgument::Template: @@ -5549,12 +5658,14 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return true; } - TemplateArgument Result; - E = CheckTemplateArgument(NTTP, NTTPType, E.get(), Result); + TemplateArgument SugaredResult, CanonicalResult; + E = CheckTemplateArgument(NTTP, NTTPType, E.get(), SugaredResult, + CanonicalResult, CTAK_Specified); if (E.isInvalid()) return true; - Converted.push_back(Result); + SugaredConverted.push_back(SugaredResult); + CanonicalConverted.push_back(CanonicalResult); break; } @@ -5611,15 +5722,17 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, { // Set up a template instantiation context. LocalInstantiationScope Scope(*this); - InstantiatingTemplate Inst(*this, TemplateLoc, Template, - TempParm, Converted, + InstantiatingTemplate Inst(*this, TemplateLoc, Template, TempParm, + SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) return true; - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); - Params = SubstTemplateParams(Params, CurContext, - MultiLevelTemplateArgumentList(TemplateArgs)); + Params = + SubstTemplateParams(Params, CurContext, + MultiLevelTemplateArgumentList( + Template, SugaredConverted, /*Final=*/true), + /*EvaluateConstraints=*/false); if (!Params) return true; } @@ -5644,7 +5757,9 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, if (CheckTemplateTemplateArgument(TempParm, Params, Arg)) return true; - Converted.push_back(Arg.getArgument()); + SugaredConverted.push_back(Arg.getArgument()); + CanonicalConverted.push_back( + Context.getCanonicalTemplateArgument(Arg.getArgument())); break; case TemplateArgument::Expression: @@ -5711,7 +5826,8 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, bool Sema::CheckTemplateArgumentList( TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, - SmallVectorImpl<TemplateArgument> &Converted, + SmallVectorImpl<TemplateArgument> &SugaredConverted, + SmallVectorImpl<TemplateArgument> &CanonicalConverted, bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) { if (ConstraintsNotSatisfied) @@ -5737,7 +5853,8 @@ bool Sema::CheckTemplateArgumentList( // corresponding parameter declared by the template in its // template-parameter-list. bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template); - SmallVector<TemplateArgument, 2> ArgumentPack; + SmallVector<TemplateArgument, 2> SugaredArgumentPack; + SmallVector<TemplateArgument, 2> CanonicalArgumentPack; unsigned ArgIdx = 0, NumArgs = NewArgs.size(); LocalInstantiationScope InstScope(*this, true); for (TemplateParameterList::iterator Param = Params->begin(), @@ -5745,13 +5862,17 @@ bool Sema::CheckTemplateArgumentList( Param != ParamEnd; /* increment in loop */) { // If we have an expanded parameter pack, make sure we don't have too // many arguments. - if (Optional<unsigned> Expansions = getExpandedPackSize(*Param)) { - if (*Expansions == ArgumentPack.size()) { + if (std::optional<unsigned> Expansions = getExpandedPackSize(*Param)) { + if (*Expansions == SugaredArgumentPack.size()) { // We're done with this parameter pack. Pack up its arguments and add // them to the list. - Converted.push_back( - TemplateArgument::CreatePackCopy(Context, ArgumentPack)); - ArgumentPack.clear(); + SugaredConverted.push_back( + TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack)); + SugaredArgumentPack.clear(); + + CanonicalConverted.push_back( + TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack)); + CanonicalArgumentPack.clear(); // This argument is assigned to the next parameter. ++Param; @@ -5770,9 +5891,10 @@ bool Sema::CheckTemplateArgumentList( if (ArgIdx < NumArgs) { // Check the template argument we were given. - if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, - TemplateLoc, RAngleLoc, - ArgumentPack.size(), Converted)) + if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc, + RAngleLoc, SugaredArgumentPack.size(), + SugaredConverted, CanonicalConverted, + CTAK_Specified)) return true; bool PackExpansionIntoNonPack = @@ -5801,7 +5923,8 @@ bool Sema::CheckTemplateArgumentList( // deduced argument and place it on the argument pack. Note that we // stay on the same template parameter so that we can deduce more // arguments. - ArgumentPack.push_back(Converted.pop_back_val()); + SugaredArgumentPack.push_back(SugaredConverted.pop_back_val()); + CanonicalArgumentPack.push_back(CanonicalConverted.pop_back_val()); } else { // Move to the next template parameter. ++Param; @@ -5811,16 +5934,25 @@ bool Sema::CheckTemplateArgumentList( // the remaining arguments, because we don't know what parameters they'll // match up with. if (PackExpansionIntoNonPack) { - if (!ArgumentPack.empty()) { + if (!SugaredArgumentPack.empty()) { // If we were part way through filling in an expanded parameter pack, // fall back to just producing individual arguments. - Converted.insert(Converted.end(), - ArgumentPack.begin(), ArgumentPack.end()); - ArgumentPack.clear(); + SugaredConverted.insert(SugaredConverted.end(), + SugaredArgumentPack.begin(), + SugaredArgumentPack.end()); + SugaredArgumentPack.clear(); + + CanonicalConverted.insert(CanonicalConverted.end(), + CanonicalArgumentPack.begin(), + CanonicalArgumentPack.end()); + CanonicalArgumentPack.clear(); } while (ArgIdx < NumArgs) { - Converted.push_back(NewArgs[ArgIdx].getArgument()); + const TemplateArgument &Arg = NewArgs[ArgIdx].getArgument(); + SugaredConverted.push_back(Arg); + CanonicalConverted.push_back( + Context.getCanonicalTemplateArgument(Arg)); ++ArgIdx; } @@ -5832,9 +5964,12 @@ bool Sema::CheckTemplateArgumentList( // If we're checking a partial template argument list, we're done. if (PartialTemplateArgs) { - if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty()) - Converted.push_back( - TemplateArgument::CreatePackCopy(Context, ArgumentPack)); + if ((*Param)->isTemplateParameterPack() && !SugaredArgumentPack.empty()) { + SugaredConverted.push_back( + TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack)); + CanonicalConverted.push_back( + TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack)); + } return false; } @@ -5847,12 +5982,20 @@ bool Sema::CheckTemplateArgumentList( // A non-expanded parameter pack before the end of the parameter list // only occurs for an ill-formed template parameter list, unless we've // got a partial argument list for a function template, so just bail out. - if (Param + 1 != ParamEnd) + if (Param + 1 != ParamEnd) { + assert( + (Template->getMostRecentDecl()->getKind() != Decl::Kind::Concept) && + "Concept templates must have parameter packs at the end."); return true; + } + + SugaredConverted.push_back( + TemplateArgument::CreatePackCopy(Context, SugaredArgumentPack)); + SugaredArgumentPack.clear(); - Converted.push_back( - TemplateArgument::CreatePackCopy(Context, ArgumentPack)); - ArgumentPack.clear(); + CanonicalConverted.push_back( + TemplateArgument::CreatePackCopy(Context, CanonicalArgumentPack)); + CanonicalArgumentPack.clear(); ++Param; continue; @@ -5871,12 +6014,9 @@ bool Sema::CheckTemplateArgumentList( return diagnoseMissingArgument(*this, TemplateLoc, Template, TTP, NewArgs); - TypeSourceInfo *ArgType = SubstDefaultTemplateArgument(*this, - Template, - TemplateLoc, - RAngleLoc, - TTP, - Converted); + TypeSourceInfo *ArgType = SubstDefaultTemplateArgument( + *this, Template, TemplateLoc, RAngleLoc, TTP, SugaredConverted, + CanonicalConverted); if (!ArgType) return true; @@ -5888,11 +6028,9 @@ bool Sema::CheckTemplateArgumentList( return diagnoseMissingArgument(*this, TemplateLoc, Template, NTTP, NewArgs); - ExprResult E = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, - NTTP, - Converted); + ExprResult E = SubstDefaultTemplateArgument( + *this, Template, TemplateLoc, RAngleLoc, NTTP, SugaredConverted, + CanonicalConverted); if (E.isInvalid()) return true; @@ -5907,12 +6045,9 @@ bool Sema::CheckTemplateArgumentList( NewArgs); NestedNameSpecifierLoc QualifierLoc; - TemplateName Name = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, - TempParm, - Converted, - QualifierLoc); + TemplateName Name = SubstDefaultTemplateArgument( + *this, Template, TemplateLoc, RAngleLoc, TempParm, SugaredConverted, + CanonicalConverted, QualifierLoc); if (Name.isNull()) return true; @@ -5925,14 +6060,16 @@ bool Sema::CheckTemplateArgumentList( // the default template argument. We're not actually instantiating a // template here, we just create this object to put a note into the // context stack. - InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param, Converted, + InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param, + SugaredConverted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) return true; // Check the default template argument. - if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, - RAngleLoc, 0, Converted)) + if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0, + SugaredConverted, CanonicalConverted, + CTAK_Specified)) return true; // Core issue 150 (assumed resolution): if this is a template template @@ -5952,8 +6089,12 @@ bool Sema::CheckTemplateArgumentList( // still dependent). if (ArgIdx < NumArgs && CurrentInstantiationScope && CurrentInstantiationScope->getPartiallySubstitutedPack()) { - while (ArgIdx < NumArgs && NewArgs[ArgIdx].getArgument().isPackExpansion()) - Converted.push_back(NewArgs[ArgIdx++].getArgument()); + while (ArgIdx < NumArgs && + NewArgs[ArgIdx].getArgument().isPackExpansion()) { + const TemplateArgument &Arg = NewArgs[ArgIdx++].getArgument(); + SugaredConverted.push_back(Arg); + CanonicalConverted.push_back(Context.getCanonicalTemplateArgument(Arg)); + } } // If we have any leftover arguments, then there were too many arguments. @@ -5974,13 +6115,39 @@ bool Sema::CheckTemplateArgumentList( if (UpdateArgsWithConversions) TemplateArgs = std::move(NewArgs); - if (!PartialTemplateArgs && - EnsureTemplateArgumentListConstraints( - Template, Converted, SourceRange(TemplateLoc, - TemplateArgs.getRAngleLoc()))) { - if (ConstraintsNotSatisfied) - *ConstraintsNotSatisfied = true; - return true; + if (!PartialTemplateArgs) { + TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack, + CanonicalConverted); + // Setup the context/ThisScope for the case where we are needing to + // re-instantiate constraints outside of normal instantiation. + DeclContext *NewContext = Template->getDeclContext(); + + // If this template is in a template, make sure we extract the templated + // decl. + if (auto *TD = dyn_cast<TemplateDecl>(NewContext)) + NewContext = Decl::castToDeclContext(TD->getTemplatedDecl()); + auto *RD = dyn_cast<CXXRecordDecl>(NewContext); + + Qualifiers ThisQuals; + if (const auto *Method = + dyn_cast_or_null<CXXMethodDecl>(Template->getTemplatedDecl())) + ThisQuals = Method->getMethodQualifiers(); + + ContextRAII Context(*this, NewContext); + CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr); + + MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs( + Template, /*Final=*/false, &StackTemplateArgs, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConceptInstantiation=*/true); + if (EnsureTemplateArgumentListConstraints( + Template, MLTAL, + SourceRange(TemplateLoc, TemplateArgs.getRAngleLoc()))) { + if (ConstraintsNotSatisfied) + *ConstraintsNotSatisfied = true; + return true; + } } return false; @@ -6125,7 +6292,7 @@ bool UnnamedLocalNoLinkageFinder::VisitTypeOfExprType(const TypeOfExprType*) { } bool UnnamedLocalNoLinkageFinder::VisitTypeOfType(const TypeOfType* T) { - return Visit(T->getUnderlyingType()); + return Visit(T->getUnmodifiedType()); } bool UnnamedLocalNoLinkageFinder::VisitDecltypeType(const DecltypeType*) { @@ -6274,8 +6441,9 @@ bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) { assert(ArgInfo && "invalid TypeSourceInfo"); QualType Arg = ArgInfo->getType(); SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); + QualType CanonArg = Context.getCanonicalType(Arg); - if (Arg->isVariablyModifiedType()) { + if (CanonArg->isVariablyModifiedType()) { return Diag(SR.getBegin(), diag::err_variably_modified_template_arg) << Arg; } else if (Context.hasSameUnqualifiedType(Arg, Context.OverloadTy)) { return Diag(SR.getBegin(), diag::err_template_arg_overload_type) << SR; @@ -6288,9 +6456,9 @@ bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) { // // C++11 allows these, and even in C++03 we allow them as an extension with // a warning. - if (LangOpts.CPlusPlus11 || Arg->hasUnnamedOrLocalType()) { + if (LangOpts.CPlusPlus11 || CanonArg->hasUnnamedOrLocalType()) { UnnamedLocalNoLinkageFinder Finder(*this, SR); - (void)Finder.Visit(Context.getCanonicalType(Arg)); + (void)Finder.Visit(CanonArg); } return false; @@ -6362,7 +6530,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, // - a constant expression that evaluates to a null pointer value (4.10); or // - a constant expression that evaluates to a null member pointer value // (4.11); or - if ((EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) || + if ((EvalResult.Val.isLValue() && EvalResult.Val.isNullPointer()) || (EvalResult.Val.isMemberPointer() && !EvalResult.Val.getMemberPointerDecl())) { // If our expression has an appropriate type, we've succeeded. @@ -6380,6 +6548,16 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, return NPV_NullPointer; } + if (EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) { + // We found a pointer that isn't null, but doesn't refer to an object. + // We could just return NPV_NotNullPointer, but we can print a better + // message with the information we have here. + S.Diag(Arg->getExprLoc(), diag::err_template_arg_invalid) + << EvalResult.Val.getAsString(S.Context, ParamType); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return NPV_Error; + } + // If we don't have a null pointer value, but we do have a NULL pointer // constant, suggest a cast to the appropriate type. if (Arg->isNullPointerConstant(S.Context, Expr::NPC_NeverValueDependent)) { @@ -6457,12 +6635,9 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter( /// Checks whether the given template argument is the address /// of an object or function according to C++ [temp.arg.nontype]p1. -static bool -CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, - NonTypeTemplateParmDecl *Param, - QualType ParamType, - Expr *ArgIn, - TemplateArgument &Converted) { +static bool CheckTemplateArgumentAddressOfObjectOrFunction( + Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn, + TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) { bool Invalid = false; Expr *Arg = ArgIn; QualType ArgType = Arg->getType(); @@ -6566,8 +6741,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, Entity)) { case NPV_NullPointer: S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), - /*isNullPtr=*/true); + SugaredConverted = TemplateArgument(ParamType, + /*isNullPtr=*/true); + CanonicalConverted = + TemplateArgument(S.Context.getCanonicalType(ParamType), + /*isNullPtr=*/true); return false; case NPV_Error: @@ -6581,7 +6759,9 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // Stop checking the precise nature of the argument if it is value dependent, // it should be checked when instantiated. if (Arg->isValueDependent()) { - Converted = TemplateArgument(ArgIn); + SugaredConverted = TemplateArgument(ArgIn); + CanonicalConverted = + S.Context.getCanonicalTemplateArgument(SugaredConverted); return false; } @@ -6711,19 +6891,21 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, return true; // Create the template argument. - Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()), - S.Context.getCanonicalType(ParamType)); + SugaredConverted = TemplateArgument(Entity, ParamType); + CanonicalConverted = + TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()), + S.Context.getCanonicalType(ParamType)); S.MarkAnyDeclReferenced(Arg->getBeginLoc(), Entity, false); return false; } /// Checks whether the given template argument is a pointer to /// member constant according to C++ [temp.arg.nontype]p1. -static bool CheckTemplateArgumentPointerToMember(Sema &S, - NonTypeTemplateParmDecl *Param, - QualType ParamType, - Expr *&ResultArg, - TemplateArgument &Converted) { +static bool +CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param, + QualType ParamType, Expr *&ResultArg, + TemplateArgument &SugaredConverted, + TemplateArgument &CanonicalConverted) { bool Invalid = false; Expr *Arg = ResultArg; @@ -6771,10 +6953,14 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, if (VD->getType()->isMemberPointerType()) { if (isa<NonTypeTemplateParmDecl>(VD)) { if (Arg->isTypeDependent() || Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = + S.Context.getCanonicalTemplateArgument(SugaredConverted); } else { - VD = cast<ValueDecl>(VD->getCanonicalDecl()); - Converted = TemplateArgument(VD, ParamType); + SugaredConverted = TemplateArgument(VD, ParamType); + CanonicalConverted = + TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()), + S.Context.getCanonicalType(ParamType)); } return Invalid; } @@ -6792,8 +6978,10 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, return true; case NPV_NullPointer: S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), - /*isNullPtr*/true); + SugaredConverted = TemplateArgument(ParamType, + /*isNullPtr*/ true); + CanonicalConverted = TemplateArgument(S.Context.getCanonicalType(ParamType), + /*isNullPtr*/ true); return false; case NPV_NotNullPointer: break; @@ -6830,10 +7018,15 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, // Okay: this is the address of a non-static member, and therefore // a member pointer constant. if (Arg->isTypeDependent() || Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = + S.Context.getCanonicalTemplateArgument(SugaredConverted); } else { - ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl()); - Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType)); + ValueDecl *D = DRE->getDecl(); + SugaredConverted = TemplateArgument(D, ParamType); + CanonicalConverted = + TemplateArgument(cast<ValueDecl>(D->getCanonicalDecl()), + S.Context.getCanonicalType(ParamType)); } return Invalid; } @@ -6854,7 +7047,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, /// type of the non-type template parameter after it has been instantiated. ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *Arg, - TemplateArgument &Converted, + TemplateArgument &SugaredConverted, + TemplateArgument &CanonicalConverted, CheckTemplateArgumentKind CTAK) { SourceLocation StartLoc = Arg->getBeginLoc(); @@ -6869,7 +7063,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CTAK == CTAK_Deduced && Arg->isTypeDependent()) { auto *AT = dyn_cast<AutoType>(DeducedT); if (AT && AT->isDecltypeAuto()) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = TemplateArgument( + Context.getCanonicalTemplateArgument(SugaredConverted)); return Arg; } } @@ -6877,7 +7073,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // When checking a deduced template argument, deduce from its type even if // the type is dependent, in order to check the types of non-type template // arguments line up properly in partial ordering. - Optional<unsigned> Depth = Param->getDepth() + 1; Expr *DeductionArg = Arg; if (auto *PE = dyn_cast<PackExpansionExpr>(DeductionArg)) DeductionArg = PE->getPattern(); @@ -6893,20 +7088,30 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind, Inits); if (ParamType.isNull()) return ExprError(); - } else if (DeduceAutoType( - TSI, DeductionArg, ParamType, Depth, - // We do not check constraints right now because the - // immediately-declared constraint of the auto type is also - // an associated constraint, and will be checked along with - // the other associated constraints after checking the - // template argument list. - /*IgnoreConstraints=*/true) == DAR_Failed) { - Diag(Arg->getExprLoc(), - diag::err_non_type_template_parm_type_deduction_failure) - << Param->getDeclName() << Param->getType() << Arg->getType() - << Arg->getSourceRange(); - Diag(Param->getLocation(), diag::note_template_param_here); - return ExprError(); + } else { + TemplateDeductionInfo Info(DeductionArg->getExprLoc(), + Param->getDepth() + 1); + ParamType = QualType(); + TemplateDeductionResult Result = + DeduceAutoType(TSI->getTypeLoc(), DeductionArg, ParamType, Info, + /*DependentDeduction=*/true, + // We do not check constraints right now because the + // immediately-declared constraint of the auto type is + // also an associated constraint, and will be checked + // along with the other associated constraints after + // checking the template argument list. + /*IgnoreConstraints=*/true); + if (Result == TDK_AlreadyDiagnosed) { + if (ParamType.isNull()) + return ExprError(); + } else if (Result != TDK_Success) { + Diag(Arg->getExprLoc(), + diag::err_non_type_template_parm_type_deduction_failure) + << Param->getDeclName() << Param->getType() << Arg->getType() + << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return ExprError(); + } } // CheckNonTypeTemplateParameterType will produce a diagnostic if there's // an error. The error message normally references the parameter @@ -6938,7 +7143,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // work. Similarly for CTAD, when comparing 'A<x>' against 'A'. if ((ParamType->isDependentType() || Arg->isTypeDependent()) && !Arg->getType()->getContainedDeducedType()) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = TemplateArgument( + Context.getCanonicalTemplateArgument(SugaredConverted)); return Arg; } // FIXME: This attempts to implement C++ [temp.deduct.type]p17. Per DR1770, @@ -6953,11 +7160,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } // If either the parameter has a dependent type or the argument is - // type-dependent, there's nothing we can check now. The argument only - // contains an unexpanded pack during partial ordering, and there's - // nothing more we can check in that case. - if (ParamType->isDependentType() || Arg->isTypeDependent() || - Arg->containsUnexpandedParameterPack()) { + // type-dependent, there's nothing we can check now. + if (ParamType->isDependentType() || Arg->isTypeDependent()) { // Force the argument to the type of the parameter to maintain invariants. auto *PE = dyn_cast<PackExpansionExpr>(Arg); if (PE) @@ -6975,7 +7179,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, PackExpansionExpr(E.get()->getType(), E.get(), PE->getEllipsisLoc(), PE->getNumExpansions()); } - Converted = TemplateArgument(E.get()); + SugaredConverted = TemplateArgument(E.get()); + CanonicalConverted = TemplateArgument( + Context.getCanonicalTemplateArgument(SugaredConverted)); return E; } @@ -7000,11 +7206,16 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Context.hasSameUnqualifiedType(ParamType, InnerArg->getType())) { NamedDecl *ND = cast<DeclRefExpr>(InnerArg)->getDecl(); if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) { - Converted = TemplateArgument(TPO, CanonParamType); + + SugaredConverted = TemplateArgument(TPO, ParamType); + CanonicalConverted = + TemplateArgument(TPO->getCanonicalDecl(), CanonParamType); return Arg; } if (isa<NonTypeTemplateParmDecl>(ND)) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = + Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; } } @@ -7021,7 +7232,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // For a value-dependent argument, CheckConvertedConstantExpression is // permitted (and expected) to be unable to determine a value. if (ArgResult.get()->isValueDependent()) { - Converted = TemplateArgument(ArgResult.get()); + SugaredConverted = TemplateArgument(ArgResult.get()); + CanonicalConverted = + Context.getCanonicalTemplateArgument(SugaredConverted); return ArgResult; } @@ -7029,14 +7242,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, switch (Value.getKind()) { case APValue::None: assert(ParamType->isNullPtrType()); - Converted = TemplateArgument(CanonParamType, /*isNullPtr*/true); + SugaredConverted = TemplateArgument(ParamType, /*isNullPtr=*/true); + CanonicalConverted = TemplateArgument(CanonParamType, /*isNullPtr=*/true); break; case APValue::Indeterminate: llvm_unreachable("result of constant evaluation should be initialized"); break; case APValue::Int: assert(ParamType->isIntegralOrEnumerationType()); - Converted = TemplateArgument(Context, Value.getInt(), CanonParamType); + SugaredConverted = TemplateArgument(Context, Value.getInt(), ParamType); + CanonicalConverted = + TemplateArgument(Context, Value.getInt(), CanonParamType); break; case APValue::MemberPointer: { assert(ParamType->isMemberPointerType()); @@ -7051,8 +7267,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } auto *VD = const_cast<ValueDecl*>(Value.getMemberPointerDecl()); - Converted = VD ? TemplateArgument(VD, CanonParamType) - : TemplateArgument(CanonParamType, /*isNullPtr*/true); + SugaredConverted = VD ? TemplateArgument(VD, ParamType) + : TemplateArgument(ParamType, /*isNullPtr=*/true); + CanonicalConverted = + VD ? TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()), + CanonParamType) + : TemplateArgument(CanonParamType, /*isNullPtr=*/true); break; } case APValue::LValue: { @@ -7092,17 +7312,25 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, "null reference should not be a constant expression"); assert((!VD || !ParamType->isNullPtrType()) && "non-null value of type nullptr_t?"); - Converted = VD ? TemplateArgument(VD, CanonParamType) - : TemplateArgument(CanonParamType, /*isNullPtr*/true); + + SugaredConverted = VD ? TemplateArgument(VD, ParamType) + : TemplateArgument(ParamType, /*isNullPtr=*/true); + CanonicalConverted = + VD ? TemplateArgument(cast<ValueDecl>(VD->getCanonicalDecl()), + CanonParamType) + : TemplateArgument(CanonParamType, /*isNullPtr=*/true); break; } case APValue::Struct: - case APValue::Union: + case APValue::Union: { // Get or create the corresponding template parameter object. - Converted = TemplateArgument( - Context.getTemplateParamObjectDecl(CanonParamType, Value), - CanonParamType); + TemplateParamObjectDecl *D = + Context.getTemplateParamObjectDecl(ParamType, Value); + SugaredConverted = TemplateArgument(D, ParamType); + CanonicalConverted = + TemplateArgument(D->getCanonicalDecl(), CanonParamType); break; + } case APValue::AddrLabelDiff: return Diag(StartLoc, diag::err_non_type_template_arg_addr_label_diff); case APValue::FixedPoint: @@ -7152,7 +7380,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // We can't check arbitrary value-dependent arguments. if (ArgResult.get()->isValueDependent()) { - Converted = TemplateArgument(ArgResult.get()); + SugaredConverted = TemplateArgument(ArgResult.get()); + CanonicalConverted = + Context.getCanonicalTemplateArgument(SugaredConverted); return ArgResult; } @@ -7166,8 +7396,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ? Context.getIntWidth(IntegerType) : Context.getTypeSize(IntegerType)); - Converted = TemplateArgument(Context, Value, - Context.getCanonicalType(ParamType)); + SugaredConverted = TemplateArgument(Context, Value, ParamType); + CanonicalConverted = + TemplateArgument(Context, Value, Context.getCanonicalType(ParamType)); return ArgResult; } @@ -7237,13 +7468,16 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Arg->isValueDependent()) { // The argument is value-dependent. Create a new // TemplateArgument with the converted expression. - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = + Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; } - QualType IntegerType = Context.getCanonicalType(ParamType); - if (const EnumType *Enum = IntegerType->getAs<EnumType>()) - IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType()); + QualType IntegerType = ParamType; + if (const EnumType *Enum = IntegerType->getAs<EnumType>()) { + IntegerType = Enum->getDecl()->getIntegerType(); + } if (ParamType->isBooleanType()) { // Value must be zero or one. @@ -7289,10 +7523,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } } - Converted = TemplateArgument(Context, Value, - ParamType->isEnumeralType() - ? Context.getCanonicalType(ParamType) - : IntegerType); + QualType T = ParamType->isEnumeralType() ? ParamType : IntegerType; + SugaredConverted = TemplateArgument(Context, Value, T); + CanonicalConverted = + TemplateArgument(Context, Value, Context.getCanonicalType(T)); return Arg; } @@ -7337,15 +7571,15 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } if (!ParamType->isMemberPointerType()) { - if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, - Arg, Converted)) + if (CheckTemplateArgumentAddressOfObjectOrFunction( + *this, Param, ParamType, Arg, SugaredConverted, + CanonicalConverted)) return ExprError(); return Arg; } - if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg, - Converted)) + if (CheckTemplateArgumentPointerToMember( + *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted)) return ExprError(); return Arg; } @@ -7358,9 +7592,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamType->getPointeeType()->isIncompleteOrObjectType() && "Only object pointers allowed here"); - if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, - Arg, Converted)) + if (CheckTemplateArgumentAddressOfObjectOrFunction( + *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted)) return ExprError(); return Arg; } @@ -7389,9 +7622,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return ExprError(); } - if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, - Arg, Converted)) + if (CheckTemplateArgumentAddressOfObjectOrFunction( + *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted)) return ExprError(); return Arg; } @@ -7399,7 +7631,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // Deal with parameters of type std::nullptr_t. if (ParamType->isNullPtrType()) { if (Arg->isTypeDependent() || Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); + SugaredConverted = TemplateArgument(Arg); + CanonicalConverted = + Context.getCanonicalTemplateArgument(SugaredConverted); return Arg; } @@ -7415,8 +7649,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, case NPV_NullPointer: Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(Context.getCanonicalType(ParamType), - /*isNullPtr*/true); + SugaredConverted = TemplateArgument(ParamType, + /*isNullPtr=*/true); + CanonicalConverted = TemplateArgument(Context.getCanonicalType(ParamType), + /*isNullPtr=*/true); return Arg; } } @@ -7425,8 +7661,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // member, qualification conversions (4.4) are applied. assert(ParamType->isMemberPointerType() && "Only pointers to members remain"); - if (CheckTemplateArgumentPointerToMember(*this, Param, ParamType, Arg, - Converted)) + if (CheckTemplateArgumentPointerToMember( + *this, Param, ParamType, Arg, SugaredConverted, CanonicalConverted)) return ExprError(); return Arg; } @@ -7499,10 +7735,10 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template, Arg.getLocation())) { - // C++2a[temp.func.order]p2 + // P2113 + // C++20[temp.func.order]p2 // [...] If both deductions succeed, the partial ordering selects the - // more constrained template as described by the rules in - // [temp.constr.order]. + // more constrained template (if one exists) as determined below. SmallVector<const Expr *, 3> ParamsAC, TemplateAC; Params->getAssociatedConstraints(ParamsAC); // C++2a[temp.arg.template]p3 @@ -7510,7 +7746,9 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, // are not considered. if (ParamsAC.empty()) return false; + Template->getAssociatedConstraints(TemplateAC); + bool IsParamAtLeastAsConstrained; if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, IsParamAtLeastAsConstrained)) @@ -7685,8 +7923,8 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, E = new (Context) CharacterLiteral(Arg.getAsIntegral().getZExtValue(), Kind, T, Loc); } else if (T->isBooleanType()) { - E = new (Context) CXXBoolLiteralExpr(Arg.getAsIntegral().getBoolValue(), - T, Loc); + E = CXXBoolLiteralExpr::Create(Context, Arg.getAsIntegral().getBoolValue(), + T, Loc); } else if (T->isNullPtrType()) { E = new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc); } else { @@ -7706,10 +7944,11 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, } /// Match two template parameters within template parameter lists. -static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, - bool Complain, - Sema::TemplateParameterListEqualKind Kind, - SourceLocation TemplateArgLoc) { +static bool MatchTemplateParameterKind( + Sema &S, NamedDecl *New, const NamedDecl *NewInstFrom, NamedDecl *Old, + const NamedDecl *OldInstFrom, bool Complain, + Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc, + bool PartialOrdering) { // Check the actual kind (type, non-type, template). if (Old->getKind() != New->getKind()) { if (Complain) { @@ -7791,20 +8030,34 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, else if (TemplateTemplateParmDecl *OldTTP = dyn_cast<TemplateTemplateParmDecl>(Old)) { TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New); - if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), - OldTTP->getTemplateParameters(), - Complain, - (Kind == Sema::TPL_TemplateMatch - ? Sema::TPL_TemplateTemplateParmMatch - : Kind), - TemplateArgLoc)) + if (!S.TemplateParameterListsAreEqual( + NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom, + OldTTP->getTemplateParameters(), Complain, + (Kind == Sema::TPL_TemplateMatch + ? Sema::TPL_TemplateTemplateParmMatch + : Kind), + TemplateArgLoc, PartialOrdering)) return false; - } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) { + } + + if (!PartialOrdering && Kind != Sema::TPL_TemplateTemplateArgumentMatch && + !isa<TemplateTemplateParmDecl>(Old)) { const Expr *NewC = nullptr, *OldC = nullptr; - if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint()) - NewC = TC->getImmediatelyDeclaredConstraint(); - if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint()) - OldC = TC->getImmediatelyDeclaredConstraint(); + + if (isa<TemplateTypeParmDecl>(New)) { + if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint()) + NewC = TC->getImmediatelyDeclaredConstraint(); + if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint()) + OldC = TC->getImmediatelyDeclaredConstraint(); + } else if (isa<NonTypeTemplateParmDecl>(New)) { + if (const Expr *E = cast<NonTypeTemplateParmDecl>(New) + ->getPlaceholderTypeConstraint()) + NewC = E; + if (const Expr *E = cast<NonTypeTemplateParmDecl>(Old) + ->getPlaceholderTypeConstraint()) + OldC = E; + } else + llvm_unreachable("unexpected template parameter type"); auto Diagnose = [&] { S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(), @@ -7820,10 +8073,8 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, } if (NewC) { - llvm::FoldingSetNodeID OldCID, NewCID; - OldC->Profile(OldCID, S.Context, /*Canonical=*/true); - NewC->Profile(NewCID, S.Context, /*Canonical=*/true); - if (OldCID != NewCID) { + if (!S.AreConstraintExpressionsEqual(OldInstFrom, OldC, NewInstFrom, + NewC)) { if (Complain) Diagnose(); return false; @@ -7879,12 +8130,11 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S, /// /// \returns True if the template parameter lists are equal, false /// otherwise. -bool -Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, - TemplateParameterList *Old, - bool Complain, - TemplateParameterListEqualKind Kind, - SourceLocation TemplateArgLoc) { +bool Sema::TemplateParameterListsAreEqual( + const NamedDecl *NewInstFrom, TemplateParameterList *New, + const NamedDecl *OldInstFrom, TemplateParameterList *Old, bool Complain, + TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc, + bool PartialOrdering) { if (Old->size() != New->size() && Kind != TPL_TemplateTemplateArgumentMatch) { if (Complain) DiagnoseTemplateParameterListArityMismatch(*this, New, Old, Kind, @@ -7914,8 +8164,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, return false; } - if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, - Kind, TemplateArgLoc)) + if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm, + OldInstFrom, Complain, Kind, + TemplateArgLoc, PartialOrdering)) return false; ++NewParm; @@ -7930,8 +8181,9 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, // template parameter pack in P (ignoring whether those template // parameters are template parameter packs). for (; NewParm != NewParmEnd; ++NewParm) { - if (!MatchTemplateParameterKind(*this, *NewParm, *OldParm, Complain, - Kind, TemplateArgLoc)) + if (!MatchTemplateParameterKind(*this, *NewParm, NewInstFrom, *OldParm, + OldInstFrom, Complain, Kind, + TemplateArgLoc, PartialOrdering)) return false; } } @@ -7945,7 +8197,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, return false; } - if (Kind != TPL_TemplateTemplateArgumentMatch) { + if (!PartialOrdering && Kind != TPL_TemplateTemplateArgumentMatch) { const Expr *NewRC = New->getRequiresClause(); const Expr *OldRC = Old->getRequiresClause(); @@ -7963,10 +8215,8 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, } if (NewRC) { - llvm::FoldingSetNodeID OldRCID, NewRCID; - OldRC->Profile(OldRCID, Context, /*Canonical=*/true); - NewRC->Profile(NewRCID, Context, /*Canonical=*/true); - if (OldRCID != NewRCID) { + if (!AreConstraintExpressionsEqual(OldInstFrom, OldRC, NewInstFrom, + NewRC)) { if (Complain) Diagnose(); return false; @@ -8413,9 +8663,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // Check that the template argument list is well-formed for this // template. - SmallVector<TemplateArgument, 4> Converted; - if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, - TemplateArgs, false, Converted, + SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, + false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; @@ -8423,14 +8673,15 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // corresponds to these arguments. if (isPartialSpecialization) { if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, ClassTemplate, - TemplateArgs.size(), Converted)) + TemplateArgs.size(), + CanonicalConverted)) return true; // FIXME: Move this to CheckTemplatePartialSpecializationArgs so we // also do it during instantiation. if (!Name.isDependent() && - !TemplateSpecializationType::anyDependentTemplateArguments(TemplateArgs, - Converted)) { + !TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, CanonicalConverted)) { Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) << ClassTemplate->getDeclName(); isPartialSpecialization = false; @@ -8441,11 +8692,10 @@ DeclResult Sema::ActOnClassTemplateSpecialization( ClassTemplateSpecializationDecl *PrevDecl = nullptr; if (isPartialSpecialization) - PrevDecl = ClassTemplate->findPartialSpecialization(Converted, - TemplateParams, - InsertPos); + PrevDecl = ClassTemplate->findPartialSpecialization( + CanonicalConverted, TemplateParams, InsertPos); else - PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos); + PrevDecl = ClassTemplate->findSpecialization(CanonicalConverted, InsertPos); ClassTemplateSpecializationDecl *Specialization = nullptr; @@ -8464,7 +8714,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // arguments of the class template partial specialization. TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); CanonType = Context.getTemplateSpecializationType(CanonTemplate, - Converted); + CanonicalConverted); if (Context.hasSameType(CanonType, ClassTemplate->getInjectedClassNameSpecialization()) && @@ -8494,16 +8744,11 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // Create a new class template partial specialization declaration node. ClassTemplatePartialSpecializationDecl *PrevPartial = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl); - ClassTemplatePartialSpecializationDecl *Partial - = ClassTemplatePartialSpecializationDecl::Create(Context, Kind, - ClassTemplate->getDeclContext(), - KWLoc, TemplateNameLoc, - TemplateParams, - ClassTemplate, - Converted, - TemplateArgs, - CanonType, - PrevPartial); + ClassTemplatePartialSpecializationDecl *Partial = + ClassTemplatePartialSpecializationDecl::Create( + Context, Kind, ClassTemplate->getDeclContext(), KWLoc, + TemplateNameLoc, TemplateParams, ClassTemplate, CanonicalConverted, + TemplateArgs, CanonType, PrevPartial); SetNestedNameSpecifier(*this, Partial, SS); if (TemplateParameterLists.size() > 1 && SS.isSet()) { Partial->setTemplateParameterListsInfo( @@ -8523,13 +8768,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization( } else { // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. - Specialization - = ClassTemplateSpecializationDecl::Create(Context, Kind, - ClassTemplate->getDeclContext(), - KWLoc, TemplateNameLoc, - ClassTemplate, - Converted, - PrevDecl); + Specialization = ClassTemplateSpecializationDecl::Create( + Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc, + ClassTemplate, CanonicalConverted, PrevDecl); SetNestedNameSpecifier(*this, Specialization, SS); if (TemplateParameterLists.size() > 0) { Specialization->setTemplateParameterListsInfo(Context, @@ -8541,8 +8782,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization( if (CurContext->isDependentContext()) { TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); - CanonType = Context.getTemplateSpecializationType( - CanonTemplate, Converted); + CanonType = Context.getTemplateSpecializationType(CanonTemplate, + CanonicalConverted); } else { CanonType = Context.getTypeDeclType(Specialization); } @@ -8686,17 +8927,33 @@ Decl *Sema::ActOnConceptDefinition(Scope *S, return nullptr; } - if (TemplateParameterLists.front()->size() == 0) { + TemplateParameterList *Params = TemplateParameterLists.front(); + + if (Params->size() == 0) { Diag(NameLoc, diag::err_concept_no_parameters); return nullptr; } + // Ensure that the parameter pack, if present, is the last parameter in the + // template. + for (TemplateParameterList::const_iterator ParamIt = Params->begin(), + ParamEnd = Params->end(); + ParamIt != ParamEnd; ++ParamIt) { + Decl const *Param = *ParamIt; + if (Param->isParameterPack()) { + if (++ParamIt == ParamEnd) + break; + Diag(Param->getLocation(), + diag::err_template_param_pack_must_be_last_template_parameter); + return nullptr; + } + } + if (DiagnoseUnexpandedParameterPack(ConstraintExpr)) return nullptr; - ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name, - TemplateParameterLists.front(), - ConstraintExpr); + ConceptDecl *NewDecl = + ConceptDecl::Create(Context, DC, NameLoc, Name, Params, ConstraintExpr); if (NewDecl->hasAssociatedConstraints()) { // C++2a [temp.concept]p4: @@ -8728,7 +8985,7 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl, if (Previous.empty()) return; - auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl()); + auto *OldConcept = dyn_cast<ConceptDecl>(Previous.getRepresentativeDecl()->getUnderlyingDecl()); if (!OldConcept) { auto *Old = Previous.getRepresentativeDecl(); Diag(NewDecl->getLocation(), diag::err_redefinition_different_kind) @@ -8746,7 +9003,8 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl, AddToScope = false; return; } - if (hasReachableDefinition(OldConcept)) { + if (hasReachableDefinition(OldConcept) && + IsRedefinitionInModule(NewDecl, OldConcept)) { Diag(NewDecl->getLocation(), diag::err_redefinition) << NewDecl->getDeclName(); notePreviousDefinition(OldConcept, NewDecl->getLocation()); @@ -8758,14 +9016,18 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl, // Other decls (e.g. namespaces) also have this shortcoming. return; } - Context.setPrimaryMergedDecl(NewDecl, OldConcept); + // We unwrap canonical decl late to check for module visibility. + Context.setPrimaryMergedDecl(NewDecl, OldConcept->getCanonicalDecl()); } /// \brief Strips various properties off an implicit instantiation /// that has just been explicitly specialized. -static void StripImplicitInstantiation(NamedDecl *D) { - D->dropAttr<DLLImportAttr>(); - D->dropAttr<DLLExportAttr>(); +static void StripImplicitInstantiation(NamedDecl *D, bool MinGW) { + if (MinGW || (isa<FunctionDecl>(D) && + cast<FunctionDecl>(D)->isFunctionTemplateSpecialization())) { + D->dropAttr<DLLImportAttr>(); + D->dropAttr<DLLExportAttr>(); + } if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) FD->setInlineSpecified(false); @@ -8840,11 +9102,13 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, if (PrevPointOfInstantiation.isInvalid()) { // The declaration itself has not actually been instantiated, so it is // still okay to specialize it. - StripImplicitInstantiation(PrevDecl); + StripImplicitInstantiation( + PrevDecl, + Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()); return false; } // Fall through - LLVM_FALLTHROUGH; + [[fallthrough]]; case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: @@ -9701,17 +9965,17 @@ DeclResult Sema::ActOnExplicitInstantiation( // Check that the template argument list is well-formed for this // template. - SmallVector<TemplateArgument, 4> Converted; - if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, - TemplateArgs, false, Converted, + SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs, + false, SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return true; // Find the class template specialization declaration that // corresponds to these arguments. void *InsertPos = nullptr; - ClassTemplateSpecializationDecl *PrevDecl - = ClassTemplate->findSpecialization(Converted, InsertPos); + ClassTemplateSpecializationDecl *PrevDecl = + ClassTemplate->findSpecialization(CanonicalConverted, InsertPos); TemplateSpecializationKind PrevDecl_TSK = PrevDecl ? PrevDecl->getTemplateSpecializationKind() : TSK_Undeclared; @@ -9768,13 +10032,9 @@ DeclResult Sema::ActOnExplicitInstantiation( if (!Specialization) { // Create a new class template specialization declaration node for // this explicit specialization. - Specialization - = ClassTemplateSpecializationDecl::Create(Context, Kind, - ClassTemplate->getDeclContext(), - KWLoc, TemplateNameLoc, - ClassTemplate, - Converted, - PrevDecl); + Specialization = ClassTemplateSpecializationDecl::Create( + Context, Kind, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc, + ClassTemplate, CanonicalConverted, PrevDecl); SetNestedNameSpecifier(*this, Specialization, SS); if (!HasNoEffect && !PrevDecl) { @@ -9921,13 +10181,14 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, bool Owned = false; bool IsDependent = false; - Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference, - KWLoc, SS, Name, NameLoc, Attr, AS_none, - /*ModulePrivateLoc=*/SourceLocation(), - MultiTemplateParamsArg(), Owned, IsDependent, - SourceLocation(), false, TypeResult(), - /*IsTypeSpecifier*/false, - /*IsTemplateParamOrArg*/false); + UsingShadowDecl* FoundUsing = nullptr; + Decl *TagD = + ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr, + AS_none, /*ModulePrivateLoc=*/SourceLocation(), + MultiTemplateParamsArg(), Owned, IsDependent, SourceLocation(), + false, TypeResult(), /*IsTypeSpecifier*/ false, + /*IsTemplateParamOrArg*/ false, /*OOK=*/OOK_Outside, FoundUsing) + .get(); assert(!IsDependent && "explicit instantiation of dependent name not yet handled"); if (!TagD) @@ -10469,10 +10730,11 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } -TypeResult -Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, - const CXXScopeSpec &SS, const IdentifierInfo &II, - SourceLocation IdLoc) { +TypeResult Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, + const IdentifierInfo &II, + SourceLocation IdLoc, + ImplicitTypenameContext IsImplicitTypename) { if (SS.isInvalid()) return true; @@ -10485,9 +10747,13 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); TypeSourceInfo *TSI = nullptr; - QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None, - TypenameLoc, QualifierLoc, II, IdLoc, &TSI, - /*DeducedTSTContext=*/true); + QualType T = + CheckTypenameType((TypenameLoc.isValid() || + IsImplicitTypename == ImplicitTypenameContext::Yes) + ? ETK_Typename + : ETK_None, + TypenameLoc, QualifierLoc, II, IdLoc, &TSI, + /*DeducedTSTContext=*/true); if (T.isNull()) return true; return CreateParsedType(T, TSI); @@ -10533,10 +10799,9 @@ Sema::ActOnTypenameType(Scope *S, // Construct a dependent template specialization type. assert(DTN && "dependent template has non-dependent name?"); assert(DTN->getQualifier() == SS.getScopeRep()); - QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename, - DTN->getQualifier(), - DTN->getIdentifier(), - TemplateArgs); + QualType T = Context.getDependentTemplateSpecializationType( + ETK_Typename, DTN->getQualifier(), DTN->getIdentifier(), + TemplateArgs.arguments()); // Create source-location information for this type. TypeLocBuilder Builder; @@ -10745,7 +11010,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, } // Fall through to create a dependent typename type, from which we can recover // better. - LLVM_FALLTHROUGH; + [[fallthrough]]; case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 9ec33e898198..9e48a2a35a34 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -45,7 +45,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -54,7 +53,9 @@ #include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <cassert> +#include <optional> #include <tuple> +#include <type_traits> #include <utility> namespace clang { @@ -235,11 +236,13 @@ checkDeducedTemplateArguments(ASTContext &Context, case TemplateArgument::Null: llvm_unreachable("Non-deduced template arguments handled above"); - case TemplateArgument::Type: + case TemplateArgument::Type: { // If two template type arguments have the same type, they're compatible. - if (Y.getKind() == TemplateArgument::Type && - Context.hasSameType(X.getAsType(), Y.getAsType())) - return X; + QualType TX = X.getAsType(), TY = Y.getAsType(); + if (Y.getKind() == TemplateArgument::Type && Context.hasSameType(TX, TY)) + return DeducedTemplateArgument(Context.getCommonSugaredType(TX, TY), + X.wasDeducedFromArrayBound() || + Y.wasDeducedFromArrayBound()); // If one of the two arguments was deduced from an array bound, the other // supersedes it. @@ -248,6 +251,7 @@ checkDeducedTemplateArguments(ASTContext &Context, // The arguments are not compatible. return DeducedTemplateArgument(); + } case TemplateArgument::Integral: // If we deduced a constant in one case and either a dependent expression or @@ -325,7 +329,9 @@ checkDeducedTemplateArguments(ASTContext &Context, // If we deduced a null pointer and a dependent expression, keep the // null pointer. if (Y.getKind() == TemplateArgument::Expression) - return X; + return TemplateArgument(Context.getCommonSugaredType( + X.getNullPtrType(), Y.getAsExpr()->getType()), + true); // If we deduced a null pointer and an integral constant, keep the // integral constant. @@ -334,7 +340,9 @@ checkDeducedTemplateArguments(ASTContext &Context, // If we deduced two null pointers, they are the same. if (Y.getKind() == TemplateArgument::NullPtr) - return X; + return TemplateArgument( + Context.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()), + true); // All other combinations are incompatible. return DeducedTemplateArgument(); @@ -555,6 +563,12 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, // FIXME: Try to preserve type sugar here, which is hard // because of the unresolved template arguments. const auto *TP = UP.getCanonicalType()->castAs<TemplateSpecializationType>(); + TemplateName TNP = TP->getTemplateName(); + + // If the parameter is an alias template, there is nothing to deduce. + if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias()) + return Sema::TDK_Success; + ArrayRef<TemplateArgument> PResolved = TP->template_arguments(); QualType UA = A; @@ -566,10 +580,15 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, // FIXME: Should not lose sugar here. if (const auto *SA = dyn_cast<TemplateSpecializationType>(UA.getCanonicalType())) { + TemplateName TNA = SA->getTemplateName(); + + // If the argument is an alias template, there is nothing to deduce. + if (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias()) + return Sema::TDK_Success; + // Perform template argument deduction for the template name. if (auto Result = - DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(), - SA->getTemplateName(), Info, Deduced)) + DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, Deduced)) return Result; // Perform template argument deduction on each template // argument. Ignore any missing/extra arguments, since they could be @@ -700,7 +719,7 @@ private: // FIXME: What if we encounter multiple packs with different numbers of // pre-expanded expansions? (This should already have been diagnosed // during substitution.) - if (Optional<unsigned> ExpandedPackExpansions = + if (std::optional<unsigned> ExpandedPackExpansions = getExpandedPackSize(TemplateParams->getParam(Index))) FixedNumExpansions = ExpandedPackExpansions; @@ -737,8 +756,11 @@ private: SmallVector<UnexpandedParameterPack, 2> Unexpanded; S.collectUnexpandedParameterPacks(Pattern, Unexpanded); for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { - unsigned Depth, Index; - std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + UnexpandedParameterPack U = Unexpanded[I]; + if (U.first.is<const SubstTemplateTypeParmPackType *>() || + U.first.is<const SubstNonTypeTemplateParmPackExpr *>()) + continue; + auto [Depth, Index] = getDepthAndIndex(U); if (Depth == Info.getDeducedDepth()) AddPack(Index); } @@ -894,7 +916,7 @@ public: new (S.Context) TemplateArgument[Pack.New.size()]; std::copy(Pack.New.begin(), Pack.New.end(), ArgumentPack); NewPack = DeducedTemplateArgument( - TemplateArgument(llvm::makeArrayRef(ArgumentPack, Pack.New.size())), + TemplateArgument(llvm::ArrayRef(ArgumentPack, Pack.New.size())), // FIXME: This is wrong, it's possible that some pack elements are // deduced from an array bound and others are not: // template<typename ...T, T ...V> void g(const T (&...p)[V]); @@ -939,7 +961,7 @@ public: // If we have a pre-expanded pack and we didn't deduce enough elements // for it, fail deduction. - if (Optional<unsigned> Expansions = getExpandedPackSize(Param)) { + if (std::optional<unsigned> Expansions = getExpandedPackSize(Param)) { if (*Expansions != PackElements) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = Result; @@ -961,7 +983,7 @@ private: unsigned PackElements = 0; bool IsPartiallyExpanded = false; /// The number of expansions, if we have a fully-expanded pack in this scope. - Optional<unsigned> FixedNumExpansions; + std::optional<unsigned> FixedNumExpansions; SmallVector<DeducedPack, 2> Packs; }; @@ -1086,7 +1108,7 @@ DeduceTemplateArguments(Sema &S, // If the parameter type contains an explicitly-specified pack that we // could not expand, skip the number of parameters notionally created // by the expansion. - Optional<unsigned> NumExpansions = Expansion->getNumExpansions(); + std::optional<unsigned> NumExpansions = Expansion->getNumExpansions(); if (NumExpansions && !PackScope.isPartiallyExpanded()) { for (unsigned I = 0; I != *NumExpansions && ArgIdx < NumArgs; ++I, ++ArgIdx) @@ -1100,6 +1122,16 @@ DeduceTemplateArguments(Sema &S, return Result; } + // DR692, DR1395 + // C++0x [temp.deduct.type]p10: + // If the parameter-declaration corresponding to P_i ... + // During partial ordering, if Ai was originally a function parameter pack: + // - if P does not contain a function parameter type corresponding to Ai then + // Ai is ignored; + if (PartialOrdering && ArgIdx + 1 == NumArgs && + isa<PackExpansionType>(Args[ArgIdx])) + return Sema::TDK_Success; + // Make sure we don't have any extra arguments. if (ArgIdx < NumArgs) return Sema::TDK_MiscellaneousDeductionFailure; @@ -1587,7 +1619,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // FIXME: Implement deduction in dependent case. if (P->isDependentType()) return Sema::TDK_Success; - LLVM_FALLTHROUGH; + [[fallthrough]]; case Type::Builtin: case Type::VariableArray: case Type::Vector: @@ -1755,7 +1787,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceTemplateArguments( S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(), FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced, - TDF & TDF_TopLevelParameterTypeList)) + TDF & TDF_TopLevelParameterTypeList, PartialOrdering)) return Result; if (TDF & TDF_AllowCompatibleFunctionType) @@ -1775,7 +1807,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( switch (FPA->canThrow()) { case CT_Cannot: Noexcept = 1; - LLVM_FALLTHROUGH; + [[fallthrough]]; case CT_Can: // We give E in noexcept(E) the "deduced from array bound" treatment. @@ -2049,7 +2081,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( const auto *ACM = dyn_cast<ConstantMatrixType>(A); const auto *ADM = dyn_cast<DependentSizedMatrixType>(A); if (!ParamExpr->isValueDependent()) { - Optional<llvm::APSInt> ParamConst = + std::optional<llvm::APSInt> ParamConst = ParamExpr->getIntegerConstantExpr(S.Context); if (!ParamConst) return Sema::TDK_NonDeducedMismatch; @@ -2061,7 +2093,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( } Expr *ArgExpr = (ADM->*GetArgDimensionExpr)(); - if (Optional<llvm::APSInt> ArgConst = + if (std::optional<llvm::APSInt> ArgConst = ArgExpr->getIntegerConstantExpr(S.Context)) if (*ArgConst == *ParamConst) return Sema::TDK_Success; @@ -2422,6 +2454,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, static bool isSameTemplateArg(ASTContext &Context, TemplateArgument X, const TemplateArgument &Y, + bool PartialOrdering, bool PackExpansionMatchesPack = false) { // If we're checking deduced arguments (X) against original arguments (Y), // we will have flattened packs to non-expansions in X. @@ -2462,18 +2495,33 @@ static bool isSameTemplateArg(ASTContext &Context, return XID == YID; } - case TemplateArgument::Pack: - if (X.pack_size() != Y.pack_size()) - return false; + case TemplateArgument::Pack: { + unsigned PackIterationSize = X.pack_size(); + if (X.pack_size() != Y.pack_size()) { + if (!PartialOrdering) + return false; - for (TemplateArgument::pack_iterator XP = X.pack_begin(), - XPEnd = X.pack_end(), - YP = Y.pack_begin(); - XP != XPEnd; ++XP, ++YP) - if (!isSameTemplateArg(Context, *XP, *YP, PackExpansionMatchesPack)) + // C++0x [temp.deduct.type]p9: + // During partial ordering, if Ai was originally a pack expansion: + // - if P does not contain a template argument corresponding to Ai + // then Ai is ignored; + bool XHasMoreArg = X.pack_size() > Y.pack_size(); + if (!(XHasMoreArg && X.pack_elements().back().isPackExpansion()) && + !(!XHasMoreArg && Y.pack_elements().back().isPackExpansion())) return false; + if (XHasMoreArg) + PackIterationSize = Y.pack_size(); + } + + ArrayRef<TemplateArgument> XP = X.pack_elements(); + ArrayRef<TemplateArgument> YP = Y.pack_elements(); + for (unsigned i = 0; i < PackIterationSize; ++i) + if (!isSameTemplateArg(Context, XP[i], YP[i], PartialOrdering, + PackExpansionMatchesPack)) + return false; return true; + } } llvm_unreachable("Invalid TemplateArgument Kind!"); @@ -2563,13 +2611,11 @@ Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm, /// Convert the given deduced template argument and add it to the set of /// fully-converted template arguments. -static bool -ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, - DeducedTemplateArgument Arg, - NamedDecl *Template, - TemplateDeductionInfo &Info, - bool IsDeduced, - SmallVectorImpl<TemplateArgument> &Output) { +static bool ConvertDeducedTemplateArgument( + Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template, + TemplateDeductionInfo &Info, bool IsDeduced, + SmallVectorImpl<TemplateArgument> &SugaredOutput, + SmallVectorImpl<TemplateArgument> &CanonicalOutput) { auto ConvertArg = [&](DeducedTemplateArgument Arg, unsigned ArgumentPackIndex) { // Convert the deduced template argument into a template @@ -2581,7 +2627,8 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, // Check the template argument, converting it as necessary. return S.CheckTemplateArgument( Param, ArgLoc, Template, Template->getLocation(), - Template->getSourceRange().getEnd(), ArgumentPackIndex, Output, + Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput, + CanonicalOutput, IsDeduced ? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound : Sema::CTAK_Deduced) @@ -2591,7 +2638,8 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, if (Arg.getKind() == TemplateArgument::Pack) { // This is a template argument pack, so check each of its arguments against // the template parameter. - SmallVector<TemplateArgument, 2> PackedArgsBuilder; + SmallVector<TemplateArgument, 2> SugaredPackedArgsBuilder, + CanonicalPackedArgsBuilder; for (const auto &P : Arg.pack_elements()) { // When converting the deduced template argument, append it to the // general output list. We need to do this so that the template argument @@ -2610,23 +2658,24 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, << Arg << Param; return true; } - if (ConvertArg(InnerArg, PackedArgsBuilder.size())) + if (ConvertArg(InnerArg, SugaredPackedArgsBuilder.size())) return true; // Move the converted template argument into our argument pack. - PackedArgsBuilder.push_back(Output.pop_back_val()); + SugaredPackedArgsBuilder.push_back(SugaredOutput.pop_back_val()); + CanonicalPackedArgsBuilder.push_back(CanonicalOutput.pop_back_val()); } // If the pack is empty, we still need to substitute into the parameter // itself, in case that substitution fails. - if (PackedArgsBuilder.empty()) { + if (SugaredPackedArgsBuilder.empty()) { LocalInstantiationScope Scope(S); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output); - MultiLevelTemplateArgumentList Args(TemplateArgs); + MultiLevelTemplateArgumentList Args(Template, SugaredOutput, + /*Final=*/true); if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, - NTTP, Output, + NTTP, SugaredOutput, Template->getSourceRange()); if (Inst.isInvalid() || S.SubstType(NTTP->getType(), Args, NTTP->getLocation(), @@ -2634,7 +2683,7 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, return true; } else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) { Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, - TTP, Output, + TTP, SugaredOutput, Template->getSourceRange()); if (Inst.isInvalid() || !S.SubstDecl(TTP, S.CurContext, Args)) return true; @@ -2643,8 +2692,10 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, } // Create the resulting argument pack. - Output.push_back( - TemplateArgument::CreatePackCopy(S.Context, PackedArgsBuilder)); + SugaredOutput.push_back( + TemplateArgument::CreatePackCopy(S.Context, SugaredPackedArgsBuilder)); + CanonicalOutput.push_back(TemplateArgument::CreatePackCopy( + S.Context, CanonicalPackedArgsBuilder)); return false; } @@ -2654,11 +2705,13 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, // FIXME: This should not be a template, but // ClassTemplatePartialSpecializationDecl sadly does not derive from // TemplateDecl. -template<typename TemplateDeclT> +template <typename TemplateDeclT> static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( Sema &S, TemplateDeclT *Template, bool IsDeduced, SmallVectorImpl<DeducedTemplateArgument> &Deduced, - TemplateDeductionInfo &Info, SmallVectorImpl<TemplateArgument> &Builder, + TemplateDeductionInfo &Info, + SmallVectorImpl<TemplateArgument> &SugaredBuilder, + SmallVectorImpl<TemplateArgument> &CanonicalBuilder, LocalInstantiationScope *CurrentInstantiationScope = nullptr, unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) { TemplateParameterList *TemplateParams = Template->getTemplateParameters(); @@ -2692,7 +2745,9 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( // We have already fully type-checked and converted this // argument, because it was explicitly-specified. Just record the // presence of this argument. - Builder.push_back(Deduced[I]); + SugaredBuilder.push_back(Deduced[I]); + CanonicalBuilder.push_back( + S.Context.getCanonicalTemplateArgument(Deduced[I])); continue; } } @@ -2700,10 +2755,13 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( // We may have deduced this argument, so it still needs to be // checked and converted. if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info, - IsDeduced, Builder)) { + IsDeduced, SugaredBuilder, + CanonicalBuilder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + Info.reset( + TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); return Sema::TDK_SubstitutionFailure; } @@ -2734,15 +2792,16 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( S.getLangOpts().CPlusPlus17); DefArg = S.SubstDefaultTemplateArgumentIfAvailable( - TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder, - HasDefaultArg); + TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, + SugaredBuilder, CanonicalBuilder, HasDefaultArg); } // If there was no default argument, deduction is incomplete. if (DefArg.getArgument().isNull()) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); if (PartialOverloading) break; return HasDefaultArg ? Sema::TDK_SubstitutionFailure @@ -2750,13 +2809,14 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( } // Check whether we can actually use the default argument. - if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(), - TD->getSourceRange().getEnd(), 0, Builder, - Sema::CTAK_Specified)) { + if (S.CheckTemplateArgument( + Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(), + 0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); return Sema::TDK_SubstitutionFailure; } @@ -2783,19 +2843,54 @@ template<> struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> { static constexpr bool value = true; }; +template <typename TemplateDeclT> +static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) { + return false; +} +template <> +bool DeducedArgsNeedReplacement<VarTemplatePartialSpecializationDecl>( + VarTemplatePartialSpecializationDecl *Spec) { + return !Spec->isClassScopeExplicitSpecialization(); +} +template <> +bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>( + ClassTemplatePartialSpecializationDecl *Spec) { + return !Spec->isClassScopeExplicitSpecialization(); +} -template<typename TemplateDeclT> +template <typename TemplateDeclT> static Sema::TemplateDeductionResult -CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, - ArrayRef<TemplateArgument> DeducedArgs, - TemplateDeductionInfo& Info) { +CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, + ArrayRef<TemplateArgument> SugaredDeducedArgs, + ArrayRef<TemplateArgument> CanonicalDeducedArgs, + TemplateDeductionInfo &Info) { llvm::SmallVector<const Expr *, 3> AssociatedConstraints; Template->getAssociatedConstraints(AssociatedConstraints); - if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, - DeducedArgs, Info.getLocation(), + + bool NeedsReplacement = DeducedArgsNeedReplacement(Template); + TemplateArgumentList DeducedTAL{TemplateArgumentList::OnStack, + CanonicalDeducedArgs}; + + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( + Template, /*Final=*/false, + /*InnerMost=*/NeedsReplacement ? nullptr : &DeducedTAL, + /*RelativeToPrimary=*/true, /*Pattern=*/ + nullptr, /*ForConstraintInstantiation=*/true); + + // getTemplateInstantiationArgs picks up the non-deduced version of the + // template args when this is a variable template partial specialization and + // not class-scope explicit specialization, so replace with Deduced Args + // instead of adding to inner-most. + if (NeedsReplacement) + MLTAL.replaceInnermostTemplateArguments(CanonicalDeducedArgs); + + if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL, + Info.getLocation(), Info.AssociatedConstraintsSatisfaction) || !Info.AssociatedConstraintsSatisfaction.IsSatisfied) { - Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs)); + Info.reset( + TemplateArgumentList::CreateCopy(S.Context, SugaredDeducedArgs), + TemplateArgumentList::CreateCopy(S.Context, CanonicalDeducedArgs)); return Sema::TDK_ConstraintsNotSatisfied; } return Sema::TDK_Success; @@ -2820,16 +2915,19 @@ FinishTemplateArgumentDeduction( // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - S, Partial, IsPartialOrdering, Deduced, Info, Builder)) + S, Partial, IsPartialOrdering, Deduced, Info, SugaredBuilder, + CanonicalBuilder)) return Result; // Form the template argument list from the deduced template arguments. - TemplateArgumentList *DeducedArgumentList - = TemplateArgumentList::CreateCopy(S.Context, Builder); + TemplateArgumentList *SugaredDeducedArgumentList = + TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder); + TemplateArgumentList *CanonicalDeducedArgumentList = + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder); - Info.reset(DeducedArgumentList); + Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList); // Substitute the deduced template arguments into the template // arguments of the class template partial specialization, and @@ -2844,9 +2942,11 @@ FinishTemplateArgumentDeduction( TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc, PartialTemplArgInfo->RAngleLoc); - if (S.SubstTemplateArguments( - PartialTemplArgInfo->arguments(), - MultiLevelTemplateArgumentList(*DeducedArgumentList), InstArgs)) { + if (S.SubstTemplateArguments(PartialTemplArgInfo->arguments(), + MultiLevelTemplateArgumentList(Partial, + SugaredBuilder, + /*Final=*/true), + InstArgs)) { unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx; if (ParamIdx >= Partial->getTemplateParameters()->size()) ParamIdx = Partial->getTemplateParameters()->size() - 1; @@ -2859,18 +2959,20 @@ FinishTemplateArgumentDeduction( } bool ConstraintsNotSatisfied; - SmallVector<TemplateArgument, 4> ConvertedInstArgs; - if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs, - false, ConvertedInstArgs, - /*UpdateArgsWithConversions=*/true, - &ConstraintsNotSatisfied)) - return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied : - Sema::TDK_SubstitutionFailure; + SmallVector<TemplateArgument, 4> SugaredConvertedInstArgs, + CanonicalConvertedInstArgs; + if (S.CheckTemplateArgumentList( + Template, Partial->getLocation(), InstArgs, false, + SugaredConvertedInstArgs, CanonicalConvertedInstArgs, + /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied)) + return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied + : Sema::TDK_SubstitutionFailure; TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { - TemplateArgument InstArg = ConvertedInstArgs.data()[I]; - if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) { + TemplateArgument InstArg = SugaredConvertedInstArgs.data()[I]; + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, + IsPartialOrdering)) { Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); Info.FirstArg = TemplateArgs[I]; Info.SecondArg = InstArg; @@ -2881,7 +2983,8 @@ FinishTemplateArgumentDeduction( if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info)) + if (auto Result = CheckDeducedArgumentConstraints(S, Partial, SugaredBuilder, + CanonicalBuilder, Info)) return Result; return Sema::TDK_Success; @@ -2905,17 +3008,20 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info, Builder)) + S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info, + SugaredBuilder, CanonicalBuilder, + /*CurrentInstantiationScope=*/nullptr, + /*NumAlreadyConverted=*/0U, /*PartialOverloading=*/false)) return Result; // Check that we produced the correct argument list. TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { - TemplateArgument InstArg = Builder[I]; - if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, - /*PackExpansionMatchesPack*/true)) { + TemplateArgument InstArg = CanonicalBuilder[I]; + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, PartialOrdering, + /*PackExpansionMatchesPack=*/true)) { Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); Info.FirstArg = TemplateArgs[I]; Info.SecondArg = InstArg; @@ -2926,8 +3032,8 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder, - Info)) + if (auto Result = CheckDeducedArgumentConstraints(S, Template, SugaredBuilder, + CanonicalBuilder, Info)) return Result; return Sema::TDK_Success; @@ -3079,14 +3185,12 @@ static bool isSimpleTemplateIdType(QualType T) { /// /// \returns TDK_Success if substitution was successful, or some failure /// condition. -Sema::TemplateDeductionResult -Sema::SubstituteExplicitTemplateArguments( - FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo &ExplicitTemplateArgs, - SmallVectorImpl<DeducedTemplateArgument> &Deduced, - SmallVectorImpl<QualType> &ParamTypes, - QualType *FunctionType, - TemplateDeductionInfo &Info) { +Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo &ExplicitTemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, + TemplateDeductionInfo &Info) { FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); @@ -3094,7 +3198,7 @@ Sema::SubstituteExplicitTemplateArguments( if (ExplicitTemplateArgs.size() == 0) { // No arguments to substitute; just copy over the parameter types and // fill in the function type. - for (auto P : Function->parameters()) + for (auto *P : Function->parameters()) ParamTypes.push_back(P->getType()); if (FunctionType) @@ -3112,7 +3216,7 @@ Sema::SubstituteExplicitTemplateArguments( // declaration order of their corresponding template-parameters. The // template argument list shall not specify more template-arguments than // there are corresponding template-parameters. - SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder; // Enter a new template instantiation context where we check the // explicitly-specified template arguments against this function template, @@ -3125,9 +3229,11 @@ Sema::SubstituteExplicitTemplateArguments( return TDK_InstantiationDepth; if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), - ExplicitTemplateArgs, true, Builder, false) || + ExplicitTemplateArgs, true, SugaredBuilder, + CanonicalBuilder, + /*UpdateArgsWithConversions=*/false) || Trap.hasErrorOccurred()) { - unsigned Index = Builder.size(); + unsigned Index = SugaredBuilder.size(); if (Index >= TemplateParams->size()) return TDK_SubstitutionFailure; Info.Param = makeTemplateParameter(TemplateParams->getParam(Index)); @@ -3136,9 +3242,12 @@ Sema::SubstituteExplicitTemplateArguments( // Form the template argument list from the explicitly-specified // template arguments. - TemplateArgumentList *ExplicitArgumentList - = TemplateArgumentList::CreateCopy(Context, Builder); - Info.setExplicitArgs(ExplicitArgumentList); + TemplateArgumentList *SugaredExplicitArgumentList = + TemplateArgumentList::CreateCopy(Context, SugaredBuilder); + TemplateArgumentList *CanonicalExplicitArgumentList = + TemplateArgumentList::CreateCopy(Context, CanonicalBuilder); + Info.setExplicitArgs(SugaredExplicitArgumentList, + CanonicalExplicitArgumentList); // Template argument deduction and the final substitution should be // done in the context of the templated declaration. Explicit @@ -3151,15 +3260,15 @@ Sema::SubstituteExplicitTemplateArguments( // the explicit template arguments. They'll be used as part of deduction // for this template parameter pack. unsigned PartiallySubstitutedPackIndex = -1u; - if (!Builder.empty()) { - const TemplateArgument &Arg = Builder.back(); + if (!CanonicalBuilder.empty()) { + const TemplateArgument &Arg = CanonicalBuilder.back(); if (Arg.getKind() == TemplateArgument::Pack) { - auto *Param = TemplateParams->getParam(Builder.size() - 1); + auto *Param = TemplateParams->getParam(CanonicalBuilder.size() - 1); // If this is a fully-saturated fixed-size pack, it should be // fully-substituted, not partially-substituted. - Optional<unsigned> Expansions = getExpandedPackSize(Param); + std::optional<unsigned> Expansions = getExpandedPackSize(Param); if (!Expansions || Arg.pack_size() < *Expansions) { - PartiallySubstitutedPackIndex = Builder.size() - 1; + PartiallySubstitutedPackIndex = CanonicalBuilder.size() - 1; CurrentInstantiationScope->SetPartiallySubstitutedPack( Param, Arg.pack_begin(), Arg.pack_size()); } @@ -3175,15 +3284,18 @@ Sema::SubstituteExplicitTemplateArguments( ExtParameterInfoBuilder ExtParamInfos; + MultiLevelTemplateArgumentList MLTAL(FunctionTemplate, + SugaredExplicitArgumentList->asArray(), + /*Final=*/true); + // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments. If the function has a trailing // return type, substitute it after the arguments to ensure we substitute // in lexical order. if (Proto->hasTrailingReturn()) { if (SubstParmTypes(Function->getLocation(), Function->parameters(), - Proto->getExtParameterInfosOrNull(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes, /*params*/ nullptr, ExtParamInfos)) + Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes, + /*params=*/nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; } @@ -3207,8 +3319,7 @@ Sema::SubstituteExplicitTemplateArguments( getLangOpts().CPlusPlus11); ResultType = - SubstType(Proto->getReturnType(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), + SubstType(Proto->getReturnType(), MLTAL, Function->getTypeSpecStartLoc(), Function->getDeclName()); if (ResultType.isNull() || Trap.hasErrorOccurred()) return TDK_SubstitutionFailure; @@ -3225,9 +3336,8 @@ Sema::SubstituteExplicitTemplateArguments( // explicitly-specified template arguments if we didn't do so earlier. if (!Proto->hasTrailingReturn() && SubstParmTypes(Function->getLocation(), Function->parameters(), - Proto->getExtParameterInfosOrNull(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes, /*params*/ nullptr, ExtParamInfos)) + Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes, + /*params*/ nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; if (FunctionType) { @@ -3239,9 +3349,8 @@ Sema::SubstituteExplicitTemplateArguments( // specification. SmallVector<QualType, 4> ExceptionStorage; if (getLangOpts().CPlusPlus17 && - SubstExceptionSpec( - Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage, - MultiLevelTemplateArgumentList(*ExplicitArgumentList))) + SubstExceptionSpec(Function->getLocation(), EPI.ExceptionSpec, + ExceptionStorage, MLTAL)) return TDK_SubstitutionFailure; *FunctionType = BuildFunctionType(ResultType, ParamTypes, @@ -3263,8 +3372,8 @@ Sema::SubstituteExplicitTemplateArguments( // parameter pack, however, will be set to NULL since the deduction // mechanism handles the partially-substituted argument pack directly. Deduced.reserve(TemplateParams->size()); - for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) { - const TemplateArgument &Arg = ExplicitArgumentList->get(I); + for (unsigned I = 0, N = SugaredExplicitArgumentList->size(); I != N; ++I) { + const TemplateArgument &Arg = SugaredExplicitArgumentList->get(I); if (I == PartiallySubstitutedPackIndex) Deduced.push_back(DeducedTemplateArgument()); else @@ -3452,11 +3561,11 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - *this, FunctionTemplate, /*IsDeduced*/true, Deduced, Info, Builder, - CurrentInstantiationScope, NumExplicitlySpecified, - PartialOverloading)) + *this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info, + SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope, + NumExplicitlySpecified, PartialOverloading)) return Result; // C++ [temp.deduct.call]p10: [DR1391] @@ -3472,16 +3581,20 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( return TDK_NonDependentConversionFailure; // Form the template argument list from the deduced template arguments. - TemplateArgumentList *DeducedArgumentList - = TemplateArgumentList::CreateCopy(Context, Builder); - Info.reset(DeducedArgumentList); + TemplateArgumentList *SugaredDeducedArgumentList = + TemplateArgumentList::CreateCopy(Context, SugaredBuilder); + TemplateArgumentList *CanonicalDeducedArgumentList = + TemplateArgumentList::CreateCopy(Context, CanonicalBuilder); + Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList); // Substitute the deduced template arguments into the function template // declaration to produce the function template specialization. DeclContext *Owner = FunctionTemplate->getDeclContext(); if (FunctionTemplate->getFriendObjectKind()) Owner = FunctionTemplate->getLexicalDeclContext(); - MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList); + MultiLevelTemplateArgumentList SubstArgs( + FunctionTemplate, CanonicalDeducedArgumentList->asArray(), + /*Final=*/false); Specialization = cast_or_null<FunctionDecl>( SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs)); if (!Specialization || Specialization->isInvalidDecl()) @@ -3492,9 +3605,10 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // If the template argument list is owned by the function template // specialization, release it. - if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList && + if (Specialization->getTemplateSpecializationArgs() == + CanonicalDeducedArgumentList && !Trap.hasErrorOccurred()) - Info.take(); + Info.takeCanonical(); // There may have been an error that did not prevent us from constructing a // declaration. Mark the declaration invalid and return with a substitution @@ -3513,13 +3627,16 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // ([temp.constr.constr]). If the constraints are not satisfied, type // deduction fails. if (!PartialOverloading || - (Builder.size() == FunctionTemplate->getTemplateParameters()->size())) { - if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(), - Specialization, Builder, Info.AssociatedConstraintsSatisfaction)) + (CanonicalBuilder.size() == + FunctionTemplate->getTemplateParameters()->size())) { + if (CheckInstantiatedFunctionTemplateConstraints( + Info.getLocation(), Specialization, CanonicalBuilder, + Info.AssociatedConstraintsSatisfaction)) return TDK_MiscellaneousDeductionFailure; if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); + Info.reset(Info.takeSugared(), + TemplateArgumentList::CreateCopy(Context, CanonicalBuilder)); return TDK_ConstraintsNotSatisfied; } } @@ -3765,13 +3882,11 @@ static bool AdjustFunctionParmAndArgTypesForDeduction( // - If A is an array type, the pointer type produced by the // array-to-pointer standard conversion (4.2) is used in place of // A for type deduction; otherwise, - if (ArgType->isArrayType()) - ArgType = S.Context.getArrayDecayedType(ArgType); // - If A is a function type, the pointer type produced by the // function-to-pointer standard conversion (4.3) is used in place // of A for type deduction; otherwise, - else if (ArgType->isFunctionType()) - ArgType = S.Context.getPointerType(ArgType); + if (ArgType->canDecayToPointerType()) + ArgType = S.Context.getDecayedType(ArgType); else { // - If A is a cv-qualified type, the top level cv-qualifiers of A's // type are ignored for type deduction. @@ -4068,7 +4183,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // If the parameter type contains an explicitly-specified pack that we // could not expand, skip the number of parameters notionally created // by the expansion. - Optional<unsigned> NumExpansions = ParamExpansion->getNumExpansions(); + std::optional<unsigned> NumExpansions = + ParamExpansion->getNumExpansions(); if (NumExpansions && !PackScope.isPartiallyExpanded()) { for (unsigned I = 0; I != *NumExpansions && ArgIdx < Args.size(); ++I, ++ArgIdx) { @@ -4521,42 +4637,9 @@ namespace { } // namespace -Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result, - Optional<unsigned> DependentDeductionDepth, - bool IgnoreConstraints) { - return DeduceAutoType(Type->getTypeLoc(), Init, Result, - DependentDeductionDepth, IgnoreConstraints); -} - -/// Attempt to produce an informative diagostic explaining why auto deduction -/// failed. -/// \return \c true if diagnosed, \c false if not. -static bool diagnoseAutoDeductionFailure(Sema &S, - Sema::TemplateDeductionResult TDK, - TemplateDeductionInfo &Info, - ArrayRef<SourceRange> Ranges) { - switch (TDK) { - case Sema::TDK_Inconsistent: { - // Inconsistent deduction means we were deducing from an initializer list. - auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction); - D << Info.FirstArg << Info.SecondArg; - for (auto R : Ranges) - D << R; - return true; - } - - // FIXME: Are there other cases for which a custom diagnostic is more useful - // than the basic "types don't match" diagnostic? - - default: - return false; - } -} - -static Sema::DeduceAutoResult -CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, - AutoTypeLoc TypeLoc, QualType Deduced) { +static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, + AutoTypeLoc TypeLoc, + QualType Deduced) { ConstraintSatisfaction Satisfaction; ConceptDecl *Concept = Type.getTypeConstraintConcept(); TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(), @@ -4568,14 +4651,17 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I) TemplateArgs.addArgument(TypeLoc.getArgLoc(I)); - llvm::SmallVector<TemplateArgument, 4> Converted; + llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs, - /*PartialTemplateArgs=*/false, Converted)) - return Sema::DAR_FailedAlreadyDiagnosed; + /*PartialTemplateArgs=*/false, + SugaredConverted, CanonicalConverted)) + return true; + MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted, + /*Final=*/false); if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, - Converted, TypeLoc.getLocalSourceRange(), + MLTAL, TypeLoc.getLocalSourceRange(), Satisfaction)) - return Sema::DAR_FailedAlreadyDiagnosed; + return true; if (!Satisfaction.IsSatisfied) { std::string Buf; llvm::raw_string_ostream OS(Buf); @@ -4589,11 +4675,11 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, OS.flush(); S.Diag(TypeLoc.getConceptNameLoc(), diag::err_placeholder_constraints_not_satisfied) - << Deduced << Buf << TypeLoc.getLocalSourceRange(); + << Deduced << Buf << TypeLoc.getLocalSourceRange(); S.DiagnoseUnsatisfiedConstraint(Satisfaction); - return Sema::DAR_FailedAlreadyDiagnosed; + return true; } - return Sema::DAR_Succeeded; + return false; } /// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) @@ -4606,184 +4692,165 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, /// \param Init the initializer for the variable whose type is to be deduced. /// \param Result if type deduction was successful, this will be set to the /// deduced type. -/// \param DependentDeductionDepth Set if we should permit deduction in +/// \param Info the argument will be updated to provide additional information +/// about template argument deduction. +/// \param DependentDeduction Set if we should permit deduction in /// dependent cases. This is necessary for template partial ordering with -/// 'auto' template parameters. The value specified is the template -/// parameter depth at which we should perform 'auto' deduction. +/// 'auto' template parameters. The template parameter depth to be used +/// should be specified in the 'Info' parameter. /// \param IgnoreConstraints Set if we should not fail if the deduced type does /// not satisfy the type-constraint in the auto type. -Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, - Optional<unsigned> DependentDeductionDepth, - bool IgnoreConstraints) { +Sema::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init, + QualType &Result, + TemplateDeductionInfo &Info, + bool DependentDeduction, + bool IgnoreConstraints) { + assert(DependentDeduction || Info.getDeducedDepth() == 0); if (Init->containsErrors()) - return DAR_FailedAlreadyDiagnosed; - if (Init->getType()->isNonOverloadPlaceholderType()) { + return TDK_AlreadyDiagnosed; + + const AutoType *AT = Type.getType()->getContainedAutoType(); + assert(AT); + + if (Init->getType()->isNonOverloadPlaceholderType() || AT->isDecltypeAuto()) { ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); if (NonPlaceholder.isInvalid()) - return DAR_FailedAlreadyDiagnosed; + return TDK_AlreadyDiagnosed; Init = NonPlaceholder.get(); } DependentAuto DependentResult = { /*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()}; - if (!DependentDeductionDepth && + if (!DependentDeduction && (Type.getType()->isDependentType() || Init->isTypeDependent() || Init->containsUnexpandedParameterPack())) { Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); - return DAR_Succeeded; + return TDK_Success; } - // Find the depth of template parameter to synthesize. - unsigned Depth = DependentDeductionDepth.value_or(0); - - // If this is a 'decltype(auto)' specifier, do the decltype dance. - // Since 'decltype(auto)' can only occur at the top of the type, we - // don't need to go digging for it. - if (const AutoType *AT = Type.getType()->getAs<AutoType>()) { - if (AT->isDecltypeAuto()) { - if (isa<InitListExpr>(Init)) { - Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list); - return DAR_FailedAlreadyDiagnosed; - } - - ExprResult ER = CheckPlaceholderExpr(Init); - if (ER.isInvalid()) - return DAR_FailedAlreadyDiagnosed; - QualType Deduced = getDecltypeForExpr(ER.get()); - assert(!Deduced.isNull()); - if (AT->isConstrained() && !IgnoreConstraints) { - auto ConstraintsResult = - CheckDeducedPlaceholderConstraints(*this, *AT, - Type.getContainedAutoTypeLoc(), - Deduced); - if (ConstraintsResult != DAR_Succeeded) - return ConstraintsResult; - } - Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type); - if (Result.isNull()) - return DAR_FailedAlreadyDiagnosed; - return DAR_Succeeded; - } else if (!getLangOpts().CPlusPlus) { - if (isa<InitListExpr>(Init)) { - Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c); - return DAR_FailedAlreadyDiagnosed; - } - } + auto *InitList = dyn_cast<InitListExpr>(Init); + if (!getLangOpts().CPlusPlus && InitList) { + Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c); + return TDK_AlreadyDiagnosed; } - SourceLocation Loc = Init->getExprLoc(); - - LocalInstantiationScope InstScope(*this); - - // Build template<class TemplParam> void Func(FuncParam); - TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create( - Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false, - false); - QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0); - NamedDecl *TemplParamPtr = TemplParam; - FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt( - Context, Loc, Loc, TemplParamPtr, Loc, nullptr); - - QualType FuncParam = - SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true) - .Apply(Type); - assert(!FuncParam.isNull() && - "substituting template parameter for 'auto' failed"); - // Deduce type of TemplParam in Func(Init) SmallVector<DeducedTemplateArgument, 1> Deduced; Deduced.resize(1); - TemplateDeductionInfo Info(Loc, Depth); - // If deduction failed, don't diagnose if the initializer is dependent; it // might acquire a matching type in the instantiation. - auto DeductionFailed = [&](TemplateDeductionResult TDK, - ArrayRef<SourceRange> Ranges) -> DeduceAutoResult { + auto DeductionFailed = [&](TemplateDeductionResult TDK) { if (Init->isTypeDependent()) { Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); - return DAR_Succeeded; + return TDK_Success; } - if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges)) - return DAR_FailedAlreadyDiagnosed; - return DAR_Failed; + return TDK; }; SmallVector<OriginalCallArg, 4> OriginalCallArgs; - InitListExpr *InitList = dyn_cast<InitListExpr>(Init); - if (InitList) { - // Notionally, we substitute std::initializer_list<T> for 'auto' and deduce - // against that. Such deduction only succeeds if removing cv-qualifiers and - // references results in std::initializer_list<T>. - if (!Type.getType().getNonReferenceType()->getAs<AutoType>()) - return DAR_Failed; - - // Resolving a core issue: a braced-init-list containing any designators is - // a non-deduced context. - for (Expr *E : InitList->inits()) - if (isa<DesignatedInitExpr>(E)) - return DAR_Failed; + QualType DeducedType; + // If this is a 'decltype(auto)' specifier, do the decltype dance. + if (AT->isDecltypeAuto()) { + if (InitList) { + Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list); + return TDK_AlreadyDiagnosed; + } - SourceRange DeducedFromInitRange; - for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) { - Expr *Init = InitList->getInit(i); + DeducedType = getDecltypeForExpr(Init); + assert(!DeducedType.isNull()); + } else { + LocalInstantiationScope InstScope(*this); + + // Build template<class TemplParam> void Func(FuncParam); + SourceLocation Loc = Init->getExprLoc(); + TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create( + Context, nullptr, SourceLocation(), Loc, Info.getDeducedDepth(), 0, + nullptr, false, false, false); + QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0); + NamedDecl *TemplParamPtr = TemplParam; + FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt( + Context, Loc, Loc, TemplParamPtr, Loc, nullptr); + + if (InitList) { + // Notionally, we substitute std::initializer_list<T> for 'auto' and + // deduce against that. Such deduction only succeeds if removing + // cv-qualifiers and references results in std::initializer_list<T>. + if (!Type.getType().getNonReferenceType()->getAs<AutoType>()) + return TDK_Invalid; + + SourceRange DeducedFromInitRange; + for (Expr *Init : InitList->inits()) { + // Resolving a core issue: a braced-init-list containing any designators + // is a non-deduced context. + if (isa<DesignatedInitExpr>(Init)) + return TDK_Invalid; + if (auto TDK = DeduceTemplateArgumentsFromCallArgument( + *this, TemplateParamsSt.get(), 0, TemplArg, Init, Info, Deduced, + OriginalCallArgs, /*Decomposed=*/true, + /*ArgIdx=*/0, /*TDF=*/0)) { + if (TDK == TDK_Inconsistent) { + Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction) + << Info.FirstArg << Info.SecondArg << DeducedFromInitRange + << Init->getSourceRange(); + return DeductionFailed(TDK_AlreadyDiagnosed); + } + return DeductionFailed(TDK); + } + if (DeducedFromInitRange.isInvalid() && + Deduced[0].getKind() != TemplateArgument::Null) + DeducedFromInitRange = Init->getSourceRange(); + } + } else { + if (!getLangOpts().CPlusPlus && Init->refersToBitField()) { + Diag(Loc, diag::err_auto_bitfield); + return TDK_AlreadyDiagnosed; + } + QualType FuncParam = + SubstituteDeducedTypeTransform(*this, TemplArg).Apply(Type); + assert(!FuncParam.isNull() && + "substituting template parameter for 'auto' failed"); if (auto TDK = DeduceTemplateArgumentsFromCallArgument( - *this, TemplateParamsSt.get(), 0, TemplArg, Init, - Info, Deduced, OriginalCallArgs, /*Decomposed*/ true, - /*ArgIdx*/ 0, /*TDF*/ 0)) - return DeductionFailed(TDK, {DeducedFromInitRange, - Init->getSourceRange()}); - - if (DeducedFromInitRange.isInvalid() && - Deduced[0].getKind() != TemplateArgument::Null) - DeducedFromInitRange = Init->getSourceRange(); - } - } else { - if (!getLangOpts().CPlusPlus && Init->refersToBitField()) { - Diag(Loc, diag::err_auto_bitfield); - return DAR_FailedAlreadyDiagnosed; + *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced, + OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0)) + return DeductionFailed(TDK); } - if (auto TDK = DeduceTemplateArgumentsFromCallArgument( - *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced, - OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0)) - return DeductionFailed(TDK, {}); - } - - // Could be null if somehow 'auto' appears in a non-deduced context. - if (Deduced[0].getKind() != TemplateArgument::Type) - return DeductionFailed(TDK_Incomplete, {}); - - QualType DeducedType = Deduced[0].getAsType(); + // Could be null if somehow 'auto' appears in a non-deduced context. + if (Deduced[0].getKind() != TemplateArgument::Type) + return DeductionFailed(TDK_Incomplete); + DeducedType = Deduced[0].getAsType(); - if (InitList) { - DeducedType = BuildStdInitializerList(DeducedType, Loc); - if (DeducedType.isNull()) - return DAR_FailedAlreadyDiagnosed; + if (InitList) { + DeducedType = BuildStdInitializerList(DeducedType, Loc); + if (DeducedType.isNull()) + return TDK_AlreadyDiagnosed; + } } - QualType MaybeAuto = Type.getType().getNonReferenceType(); - while (MaybeAuto->isPointerType()) - MaybeAuto = MaybeAuto->getPointeeType(); - if (const auto *AT = MaybeAuto->getAs<AutoType>()) { - if (AT->isConstrained() && !IgnoreConstraints) { - auto ConstraintsResult = CheckDeducedPlaceholderConstraints( - *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType); - if (ConstraintsResult != DAR_Succeeded) - return ConstraintsResult; + if (!Result.isNull()) { + if (!Context.hasSameType(DeducedType, Result)) { + Info.FirstArg = Result; + Info.SecondArg = DeducedType; + return DeductionFailed(TDK_Inconsistent); } + DeducedType = Context.getCommonSugaredType(Result, DeducedType); } + if (AT->isConstrained() && !IgnoreConstraints && + CheckDeducedPlaceholderConstraints( + *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType)) + return TDK_AlreadyDiagnosed; + Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type); if (Result.isNull()) - return DAR_FailedAlreadyDiagnosed; + return TDK_AlreadyDiagnosed; // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. @@ -4794,11 +4861,11 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, if (auto TDK = CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) { Result = QualType(); - return DeductionFailed(TDK, {}); + return DeductionFailed(TDK); } } - return DAR_Succeeded; + return TDK_Success; } QualType Sema::SubstAutoType(QualType TypeWithAuto, @@ -5102,27 +5169,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S, return true; } -/// Determine whether this a function template whose parameter-type-list -/// ends with a function parameter pack. -static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { - FunctionDecl *Function = FunTmpl->getTemplatedDecl(); - unsigned NumParams = Function->getNumParams(); - if (NumParams == 0) - return false; - - ParmVarDecl *Last = Function->getParamDecl(NumParams - 1); - if (!Last->isParameterPack()) - return false; - - // Make sure that no previous parameter is a parameter pack. - while (--NumParams > 0) { - if (Function->getParamDecl(NumParams - 1)->isParameterPack()) - return false; - } - - return true; -} - /// Returns the more specialized function template according /// to the rules of function template partial ordering (C++ [temp.func.order]). /// @@ -5143,53 +5189,128 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { /// candidate with a reversed parameter order. In this case, the corresponding /// P/A pairs between FT1 and FT2 are reversed. /// -/// \param AllowOrderingByConstraints If \c is false, don't check whether one -/// of the templates is more constrained than the other. Default is true. -/// /// \returns the more specialized function template. If neither /// template is more specialized, returns NULL. FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, - unsigned NumCallArguments2, bool Reversed, - bool AllowOrderingByConstraints) { - - auto JudgeByConstraints = [&]() -> FunctionTemplateDecl * { - if (!AllowOrderingByConstraints) - return nullptr; - llvm::SmallVector<const Expr *, 3> AC1, AC2; - FT1->getAssociatedConstraints(AC1); - FT2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1)) - return nullptr; - if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2)) - return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) - return nullptr; - return AtLeastAsConstrained1 ? FT1 : FT2; - }; + unsigned NumCallArguments2, bool Reversed) { bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, NumCallArguments1, Reversed); bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, NumCallArguments2, Reversed); + // C++ [temp.deduct.partial]p10: + // F is more specialized than G if F is at least as specialized as G and G + // is not at least as specialized as F. if (Better1 != Better2) // We have a clear winner return Better1 ? FT1 : FT2; if (!Better1 && !Better2) // Neither is better than the other - return JudgeByConstraints(); + return nullptr; - // FIXME: This mimics what GCC implements, but doesn't match up with the - // proposed resolution for core issue 692. This area needs to be sorted out, - // but for now we attempt to maintain compatibility. - bool Variadic1 = isVariadicFunctionTemplate(FT1); - bool Variadic2 = isVariadicFunctionTemplate(FT2); - if (Variadic1 != Variadic2) - return Variadic1? FT2 : FT1; + // C++ [temp.deduct.partial]p11: + // ... and if G has a trailing function parameter pack for which F does not + // have a corresponding parameter, and if F does not have a trailing + // function parameter pack, then F is more specialized than G. + FunctionDecl *FD1 = FT1->getTemplatedDecl(); + FunctionDecl *FD2 = FT2->getTemplatedDecl(); + unsigned NumParams1 = FD1->getNumParams(); + unsigned NumParams2 = FD2->getNumParams(); + bool Variadic1 = NumParams1 && FD1->parameters().back()->isParameterPack(); + bool Variadic2 = NumParams2 && FD2->parameters().back()->isParameterPack(); + if (Variadic1 != Variadic2) { + if (Variadic1 && NumParams1 > NumParams2) + return FT2; + if (Variadic2 && NumParams2 > NumParams1) + return FT1; + } + + // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that + // there is no wording or even resolution for this issue. + for (int i = 0, e = std::min(NumParams1, NumParams2); i < e; ++i) { + QualType T1 = FD1->getParamDecl(i)->getType().getCanonicalType(); + QualType T2 = FD2->getParamDecl(i)->getType().getCanonicalType(); + auto *TST1 = dyn_cast<TemplateSpecializationType>(T1); + auto *TST2 = dyn_cast<TemplateSpecializationType>(T2); + if (!TST1 || !TST2) + continue; + const TemplateArgument &TA1 = TST1->template_arguments().back(); + if (TA1.getKind() == TemplateArgument::Pack) { + assert(TST1->template_arguments().size() == + TST2->template_arguments().size()); + const TemplateArgument &TA2 = TST2->template_arguments().back(); + assert(TA2.getKind() == TemplateArgument::Pack); + unsigned PackSize1 = TA1.pack_size(); + unsigned PackSize2 = TA2.pack_size(); + bool IsPackExpansion1 = + PackSize1 && TA1.pack_elements().back().isPackExpansion(); + bool IsPackExpansion2 = + PackSize2 && TA2.pack_elements().back().isPackExpansion(); + if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) { + if (PackSize1 > PackSize2 && IsPackExpansion1) + return FT2; + if (PackSize1 < PackSize2 && IsPackExpansion2) + return FT1; + } + } + } + + if (!Context.getLangOpts().CPlusPlus20) + return nullptr; + + // Match GCC on not implementing [temp.func.order]p6.2.1. + + // C++20 [temp.func.order]p6: + // If deduction against the other template succeeds for both transformed + // templates, constraints can be considered as follows: + + // C++20 [temp.func.order]p6.1: + // If their template-parameter-lists (possibly including template-parameters + // invented for an abbreviated function template ([dcl.fct])) or function + // parameter lists differ in length, neither template is more specialized + // than the other. + TemplateParameterList *TPL1 = FT1->getTemplateParameters(); + TemplateParameterList *TPL2 = FT2->getTemplateParameters(); + if (TPL1->size() != TPL2->size() || NumParams1 != NumParams2) + return nullptr; + + // C++20 [temp.func.order]p6.2.2: + // Otherwise, if the corresponding template-parameters of the + // template-parameter-lists are not equivalent ([temp.over.link]) or if the + // function parameters that positionally correspond between the two + // templates are not of the same type, neither template is more specialized + // than the other. + if (!TemplateParameterListsAreEqual( + TPL1, TPL2, false, Sema::TPL_TemplateMatch, SourceLocation(), true)) + return nullptr; + + for (unsigned i = 0; i < NumParams1; ++i) + if (!Context.hasSameType(FD1->getParamDecl(i)->getType(), + FD2->getParamDecl(i)->getType())) + return nullptr; + + // C++20 [temp.func.order]p6.3: + // Otherwise, if the context in which the partial ordering is done is + // that of a call to a conversion function and the return types of the + // templates are not the same, then neither template is more specialized + // than the other. + if (TPOC == TPOC_Conversion && + !Context.hasSameType(FD1->getReturnType(), FD2->getReturnType())) + return nullptr; - return JudgeByConstraints(); + llvm::SmallVector<const Expr *, 3> AC1, AC2; + FT1->getAssociatedConstraints(AC1); + FT2->getAssociatedConstraints(AC2); + bool AtLeastAsConstrained1, AtLeastAsConstrained2; + if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1)) + return nullptr; + if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2)) + return nullptr; + if (AtLeastAsConstrained1 == AtLeastAsConstrained2) + return nullptr; + return AtLeastAsConstrained1 ? FT1 : FT2; } /// Determine if the two templates are equivalent. @@ -5354,7 +5475,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, if (Inst.isInvalid()) return false; - auto *TST1 = T1->castAs<TemplateSpecializationType>(); + const auto *TST1 = cast<TemplateSpecializationType>(T1); bool AtLeastAsSpecialized; S.runWithSufficientStackSpace(Info.getLocation(), [&] { AtLeastAsSpecialized = !FinishTemplateArgumentDeduction( @@ -5366,6 +5487,180 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, return AtLeastAsSpecialized; } +namespace { +// A dummy class to return nullptr instead of P2 when performing "more +// specialized than primary" check. +struct GetP2 { + template <typename T1, typename T2, + std::enable_if_t<std::is_same_v<T1, T2>, bool> = true> + T2 *operator()(T1 *, T2 *P2) { + return P2; + } + template <typename T1, typename T2, + std::enable_if_t<!std::is_same_v<T1, T2>, bool> = true> + T1 *operator()(T1 *, T2 *) { + return nullptr; + } +}; + +// The assumption is that two template argument lists have the same size. +struct TemplateArgumentListAreEqual { + ASTContext &Ctx; + TemplateArgumentListAreEqual(ASTContext &Ctx) : Ctx(Ctx) {} + + template <typename T1, typename T2, + std::enable_if_t<std::is_same_v<T1, T2>, bool> = true> + bool operator()(T1 *PS1, T2 *PS2) { + ArrayRef<TemplateArgument> Args1 = PS1->getTemplateArgs().asArray(), + Args2 = PS2->getTemplateArgs().asArray(); + + for (unsigned I = 0, E = Args1.size(); I < E; ++I) { + // We use profile, instead of structural comparison of the arguments, + // because canonicalization can't do the right thing for dependent + // expressions. + llvm::FoldingSetNodeID IDA, IDB; + Args1[I].Profile(IDA, Ctx); + Args2[I].Profile(IDB, Ctx); + if (IDA != IDB) + return false; + } + return true; + } + + template <typename T1, typename T2, + std::enable_if_t<!std::is_same_v<T1, T2>, bool> = true> + bool operator()(T1 *Spec, T2 *Primary) { + ArrayRef<TemplateArgument> Args1 = Spec->getTemplateArgs().asArray(), + Args2 = Primary->getInjectedTemplateArgs(); + + for (unsigned I = 0, E = Args1.size(); I < E; ++I) { + // We use profile, instead of structural comparison of the arguments, + // because canonicalization can't do the right thing for dependent + // expressions. + llvm::FoldingSetNodeID IDA, IDB; + Args1[I].Profile(IDA, Ctx); + // Unlike the specialization arguments, the injected arguments are not + // always canonical. + Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx); + if (IDA != IDB) + return false; + } + return true; + } +}; +} // namespace + +/// Returns the more specialized template specialization between T1/P1 and +/// T2/P2. +/// - If IsMoreSpecialThanPrimaryCheck is true, T1/P1 is the partial +/// specialization and T2/P2 is the primary template. +/// - otherwise, both T1/P1 and T2/P2 are the partial specialization. +/// +/// \param T1 the type of the first template partial specialization +/// +/// \param T2 if IsMoreSpecialThanPrimaryCheck is true, the type of the second +/// template partial specialization; otherwise, the type of the +/// primary template. +/// +/// \param P1 the first template partial specialization +/// +/// \param P2 if IsMoreSpecialThanPrimaryCheck is true, the second template +/// partial specialization; otherwise, the primary template. +/// +/// \returns - If IsMoreSpecialThanPrimaryCheck is true, returns P1 if P1 is +/// more specialized, returns nullptr if P1 is not more specialized. +/// - otherwise, returns the more specialized template partial +/// specialization. If neither partial specialization is more +/// specialized, returns NULL. +template <typename TemplateLikeDecl, typename PrimaryDel> +static TemplateLikeDecl * +getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1, + PrimaryDel *P2, TemplateDeductionInfo &Info) { + constexpr bool IsMoreSpecialThanPrimaryCheck = + !std::is_same_v<TemplateLikeDecl, PrimaryDel>; + + bool Better1 = isAtLeastAsSpecializedAs(S, T1, T2, P2, Info); + if (IsMoreSpecialThanPrimaryCheck && !Better1) + return nullptr; + + bool Better2 = isAtLeastAsSpecializedAs(S, T2, T1, P1, Info); + if (IsMoreSpecialThanPrimaryCheck && !Better2) + return P1; + + // C++ [temp.deduct.partial]p10: + // F is more specialized than G if F is at least as specialized as G and G + // is not at least as specialized as F. + if (Better1 != Better2) // We have a clear winner + return Better1 ? P1 : GetP2()(P1, P2); + + if (!Better1 && !Better2) + return nullptr; + + // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that + // there is no wording or even resolution for this issue. + auto *TST1 = cast<TemplateSpecializationType>(T1); + auto *TST2 = cast<TemplateSpecializationType>(T2); + const TemplateArgument &TA1 = TST1->template_arguments().back(); + if (TA1.getKind() == TemplateArgument::Pack) { + assert(TST1->template_arguments().size() == + TST2->template_arguments().size()); + const TemplateArgument &TA2 = TST2->template_arguments().back(); + assert(TA2.getKind() == TemplateArgument::Pack); + unsigned PackSize1 = TA1.pack_size(); + unsigned PackSize2 = TA2.pack_size(); + bool IsPackExpansion1 = + PackSize1 && TA1.pack_elements().back().isPackExpansion(); + bool IsPackExpansion2 = + PackSize2 && TA2.pack_elements().back().isPackExpansion(); + if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) { + if (PackSize1 > PackSize2 && IsPackExpansion1) + return GetP2()(P1, P2); + if (PackSize1 < PackSize2 && IsPackExpansion2) + return P1; + } + } + + if (!S.Context.getLangOpts().CPlusPlus20) + return nullptr; + + // Match GCC on not implementing [temp.func.order]p6.2.1. + + // C++20 [temp.func.order]p6: + // If deduction against the other template succeeds for both transformed + // templates, constraints can be considered as follows: + + TemplateParameterList *TPL1 = P1->getTemplateParameters(); + TemplateParameterList *TPL2 = P2->getTemplateParameters(); + if (TPL1->size() != TPL2->size()) + return nullptr; + + // C++20 [temp.func.order]p6.2.2: + // Otherwise, if the corresponding template-parameters of the + // template-parameter-lists are not equivalent ([temp.over.link]) or if the + // function parameters that positionally correspond between the two + // templates are not of the same type, neither template is more specialized + // than the other. + if (!S.TemplateParameterListsAreEqual( + TPL1, TPL2, false, Sema::TPL_TemplateMatch, SourceLocation(), true)) + return nullptr; + + if (!TemplateArgumentListAreEqual(S.getASTContext())(P1, P2)) + return nullptr; + + llvm::SmallVector<const Expr *, 3> AC1, AC2; + P1->getAssociatedConstraints(AC1); + P2->getAssociatedConstraints(AC2); + bool AtLeastAsConstrained1, AtLeastAsConstrained2; + if (S.IsAtLeastAsConstrained(P1, AC1, P2, AC2, AtLeastAsConstrained1) || + (IsMoreSpecialThanPrimaryCheck && !AtLeastAsConstrained1)) + return nullptr; + if (S.IsAtLeastAsConstrained(P2, AC2, P1, AC1, AtLeastAsConstrained2)) + return nullptr; + if (AtLeastAsConstrained1 == AtLeastAsConstrained2) + return nullptr; + return AtLeastAsConstrained1 ? P1 : GetP2()(P1, P2); +} + /// Returns the more specialized class template partial specialization /// according to the rules of partial ordering of class template partial /// specializations (C++ [temp.class.order]). @@ -5385,26 +5680,7 @@ Sema::getMoreSpecializedPartialSpecialization( QualType PT2 = PS2->getInjectedSpecializationType(); TemplateDeductionInfo Info(Loc); - bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); - bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); - - if (!Better1 && !Better2) - return nullptr; - if (Better1 && Better2) { - llvm::SmallVector<const Expr *, 3> AC1, AC2; - PS1->getAssociatedConstraints(AC1); - PS2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1)) - return nullptr; - if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2)) - return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) - return nullptr; - return AtLeastAsConstrained1 ? PS1 : PS2; - } - - return Better1 ? PS1 : PS2; + return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info); } bool Sema::isMoreSpecializedThanPrimary( @@ -5412,24 +5688,12 @@ bool Sema::isMoreSpecializedThanPrimary( ClassTemplateDecl *Primary = Spec->getSpecializedTemplate(); QualType PrimaryT = Primary->getInjectedClassNameSpecialization(); QualType PartialT = Spec->getInjectedSpecializationType(); - if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) - return false; - if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) - return true; - Info.clearSFINAEDiagnostic(); - llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC; - Primary->getAssociatedConstraints(PrimaryAC); - Spec->getAssociatedConstraints(SpecAC); - bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec; - if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC, - AtLeastAsConstrainedSpec)) - return false; - if (!AtLeastAsConstrainedSpec) - return false; - if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC, - AtLeastAsConstrainedPrimary)) - return false; - return !AtLeastAsConstrainedPrimary; + + ClassTemplatePartialSpecializationDecl *MaybeSpec = + getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info); + if (MaybeSpec) + Info.clearSFINAEDiagnostic(); + return MaybeSpec; } VarTemplatePartialSpecializationDecl * @@ -5449,62 +5713,24 @@ Sema::getMoreSpecializedPartialSpecialization( CanonTemplate, PS2->getTemplateArgs().asArray()); TemplateDeductionInfo Info(Loc); - bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); - bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); - - if (!Better1 && !Better2) - return nullptr; - if (Better1 && Better2) { - llvm::SmallVector<const Expr *, 3> AC1, AC2; - PS1->getAssociatedConstraints(AC1); - PS2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1)) - return nullptr; - if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2)) - return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) - return nullptr; - return AtLeastAsConstrained1 ? PS1 : PS2; - } - - return Better1 ? PS1 : PS2; + return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info); } bool Sema::isMoreSpecializedThanPrimary( VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) { - TemplateDecl *Primary = Spec->getSpecializedTemplate(); - // FIXME: Cache the injected template arguments rather than recomputing - // them for each partial specialization. - SmallVector<TemplateArgument, 8> PrimaryArgs; - Context.getInjectedTemplateArgs(Primary->getTemplateParameters(), - PrimaryArgs); - + VarTemplateDecl *Primary = Spec->getSpecializedTemplate(); TemplateName CanonTemplate = Context.getCanonicalTemplateName(TemplateName(Primary)); QualType PrimaryT = Context.getTemplateSpecializationType( - CanonTemplate, PrimaryArgs); + CanonTemplate, Primary->getInjectedTemplateArgs()); QualType PartialT = Context.getTemplateSpecializationType( CanonTemplate, Spec->getTemplateArgs().asArray()); - if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) - return false; - if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) - return true; - Info.clearSFINAEDiagnostic(); - llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC; - Primary->getAssociatedConstraints(PrimaryAC); - Spec->getAssociatedConstraints(SpecAC); - bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec; - if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC, - AtLeastAsConstrainedSpec)) - return false; - if (!AtLeastAsConstrainedSpec) - return false; - if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC, - AtLeastAsConstrainedPrimary)) - return false; - return !AtLeastAsConstrainedPrimary; + VarTemplatePartialSpecializationDecl *MaybeSpec = + getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info); + if (MaybeSpec) + Info.clearSFINAEDiagnostic(); + return MaybeSpec; } bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( @@ -5556,13 +5782,15 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // C++1z [temp.arg.template]p3: // If the rewrite produces an invalid type, then P is not at least as // specialized as A. - if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, PArgs) || + SmallVector<TemplateArgument, 4> SugaredPArgs; + if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, SugaredPArgs, + PArgs) || Trap.hasErrorOccurred()) return false; } - QualType AType = Context.getTemplateSpecializationType(X, AArgs); - QualType PType = Context.getTemplateSpecializationType(X, PArgs); + QualType AType = Context.getCanonicalTemplateSpecializationType(X, AArgs); + QualType PType = Context.getCanonicalTemplateSpecializationType(X, PArgs); // ... the function template corresponding to P is at least as specialized // as the function template corresponding to A according to the partial @@ -5588,8 +5816,8 @@ struct MarkUsedTemplateParameterVisitor : } bool TraverseTemplateName(TemplateName Template) { - if (auto *TTP = - dyn_cast<TemplateTemplateParmDecl>(Template.getAsTemplateDecl())) + if (auto *TTP = llvm::dyn_cast_or_null<TemplateTemplateParmDecl>( + Template.getAsTemplateDecl())) if (TTP->getDepth() == Depth) Used[TTP->getIndex()] = true; RecursiveASTVisitor<MarkUsedTemplateParameterVisitor>:: @@ -5734,7 +5962,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, cast<DependentSizedArrayType>(T)->getSizeExpr(), OnlyDeduced, Depth, Used); // Fall through to check the element type - LLVM_FALLTHROUGH; + [[fallthrough]]; case Type::ConstantArray: case Type::IncompleteArray: @@ -5834,9 +6062,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, case Type::SubstTemplateTypeParmPack: { const SubstTemplateTypeParmPackType *Subst = cast<SubstTemplateTypeParmPackType>(T); - MarkUsedTemplateParameters(Ctx, - QualType(Subst->getReplacedParameter(), 0), - OnlyDeduced, Depth, Used); + if (Subst->getReplacedParameter()->getDepth() == Depth) + Used[Subst->getIndex()] = true; MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(), OnlyDeduced, Depth, Used); break; @@ -5844,7 +6071,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, case Type::InjectedClassName: T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType(); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Type::TemplateSpecialization: { const TemplateSpecializationType *Spec @@ -5860,9 +6087,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, hasPackExpansionBeforeEnd(Spec->template_arguments())) break; - for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth, - Used); + for (const auto &Arg : Spec->template_arguments()) + MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used); break; } @@ -5906,16 +6132,14 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, MarkUsedTemplateParameters(Ctx, Spec->getQualifier(), OnlyDeduced, Depth, Used); - for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth, - Used); + for (const auto &Arg : Spec->template_arguments()) + MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used); break; } case Type::TypeOf: if (!OnlyDeduced) - MarkUsedTemplateParameters(Ctx, - cast<TypeOfType>(T)->getUnderlyingType(), + MarkUsedTemplateParameters(Ctx, cast<TypeOfType>(T)->getUnmodifiedType(), OnlyDeduced, Depth, Used); break; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index f09b3473c074..2790e78aa53a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -15,10 +15,12 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprConcepts.h" #include "clang/AST/PrettyDeclStackTrace.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Stack.h" @@ -26,12 +28,15 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" #include "clang/Sema/SemaConcept.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TimeProfiler.h" +#include <optional> using namespace clang; using namespace sema; @@ -40,13 +45,231 @@ using namespace sema; // Template Instantiation Support //===----------------------------------------------------------------------===/ +namespace { +namespace TemplateInstArgsHelpers { +struct Response { + const Decl *NextDecl = nullptr; + bool IsDone = false; + bool ClearRelativeToPrimary = true; + static Response Done() { + Response R; + R.IsDone = true; + return R; + } + static Response ChangeDecl(const Decl *ND) { + Response R; + R.NextDecl = ND; + return R; + } + static Response ChangeDecl(const DeclContext *Ctx) { + Response R; + R.NextDecl = Decl::castFromDeclContext(Ctx); + return R; + } + + static Response UseNextDecl(const Decl *CurDecl) { + return ChangeDecl(CurDecl->getDeclContext()); + } + + static Response DontClearRelativeToPrimaryNextDecl(const Decl *CurDecl) { + Response R = Response::UseNextDecl(CurDecl); + R.ClearRelativeToPrimary = false; + return R; + } +}; +// Add template arguments from a variable template instantiation. +Response +HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec, + MultiLevelTemplateArgumentList &Result, + bool SkipForSpecialization) { + // For a class-scope explicit specialization, there are no template arguments + // at this level, but there may be enclosing template arguments. + if (VarTemplSpec->isClassScopeExplicitSpecialization()) + return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); + + // We're done when we hit an explicit specialization. + if (VarTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa<VarTemplatePartialSpecializationDecl>(VarTemplSpec)) + return Response::Done(); + + // If this variable template specialization was instantiated from a + // specialized member that is a variable template, we're done. + assert(VarTemplSpec->getSpecializedTemplate() && "No variable template?"); + llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> + Specialized = VarTemplSpec->getSpecializedTemplateOrPartial(); + if (VarTemplatePartialSpecializationDecl *Partial = + Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); + if (Partial->isMemberSpecialization()) + return Response::Done(); + } else { + VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>(); + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); + if (Tmpl->isMemberSpecialization()) + return Response::Done(); + } + return Response::DontClearRelativeToPrimaryNextDecl(VarTemplSpec); +} + +// If we have a template template parameter with translation unit context, +// then we're performing substitution into a default template argument of +// this template template parameter before we've constructed the template +// that will own this template template parameter. In this case, we +// use empty template parameter lists for all of the outer templates +// to avoid performing any substitutions. +Response +HandleDefaultTempArgIntoTempTempParam(const TemplateTemplateParmDecl *TTP, + MultiLevelTemplateArgumentList &Result) { + for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I) + Result.addOuterTemplateArguments(std::nullopt); + return Response::Done(); +} + +// Add template arguments from a class template instantiation. +Response +HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, + MultiLevelTemplateArgumentList &Result, + bool SkipForSpecialization) { + if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) { + // We're done when we hit an explicit specialization. + if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec)) + return Response::Done(); + + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec), + ClassTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); + + // If this class template specialization was instantiated from a + // specialized member that is a class template, we're done. + assert(ClassTemplSpec->getSpecializedTemplate() && "No class template?"); + if (ClassTemplSpec->getSpecializedTemplate()->isMemberSpecialization()) + return Response::Done(); + } + return Response::UseNextDecl(ClassTemplSpec); +} + +Response HandleFunction(const FunctionDecl *Function, + MultiLevelTemplateArgumentList &Result, + const FunctionDecl *Pattern, bool RelativeToPrimary, + bool ForConstraintInstantiation) { + // Add template arguments from a function template specialization. + if (!RelativeToPrimary && + Function->getTemplateSpecializationKindForInstantiation() == + TSK_ExplicitSpecialization) + return Response::Done(); + + if (!RelativeToPrimary && + Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { + // This is an implicit instantiation of an explicit specialization. We + // don't get any template arguments from this function but might get + // some from an enclosing template. + return Response::UseNextDecl(Function); + } else if (const TemplateArgumentList *TemplateArgs = + Function->getTemplateSpecializationArgs()) { + // Add the template arguments for this specialization. + Result.addOuterTemplateArguments(const_cast<FunctionDecl *>(Function), + TemplateArgs->asArray(), + /*Final=*/false); + + // If this function was instantiated from a specialized member that is + // a function template, we're done. + assert(Function->getPrimaryTemplate() && "No function template?"); + if (Function->getPrimaryTemplate()->isMemberSpecialization()) + return Response::Done(); + + // If this function is a generic lambda specialization, we are done. + if (!ForConstraintInstantiation && + isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) + return Response::Done(); + + } else if (Function->getDescribedFunctionTemplate()) { + assert( + (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && + "Outer template not instantiated?"); + } + // If this is a friend or local declaration and it declares an entity at + // namespace scope, take arguments from its lexical parent + // instead of its semantic parent, unless of course the pattern we're + // instantiating actually comes from the file's context! + if ((Function->getFriendObjectKind() || Function->isLocalExternDecl()) && + Function->getNonTransparentDeclContext()->isFileContext() && + (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { + return Response::ChangeDecl(Function->getLexicalDeclContext()); + } + return Response::UseNextDecl(Function); +} + +Response HandleRecordDecl(const CXXRecordDecl *Rec, + MultiLevelTemplateArgumentList &Result, + ASTContext &Context, + bool ForConstraintInstantiation) { + if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { + assert( + (ForConstraintInstantiation || Result.getNumSubstitutedLevels() == 0) && + "Outer template not instantiated?"); + if (ClassTemplate->isMemberSpecialization()) + return Response::Done(); + if (ForConstraintInstantiation) { + QualType RecordType = Context.getTypeDeclType(Rec); + QualType Injected = cast<InjectedClassNameType>(RecordType) + ->getInjectedSpecializationType(); + const auto *InjectedType = cast<TemplateSpecializationType>(Injected); + Result.addOuterTemplateArguments(const_cast<CXXRecordDecl *>(Rec), + InjectedType->template_arguments(), + /*Final=*/false); + } + } + + bool IsFriend = Rec->getFriendObjectKind() || + (Rec->getDescribedClassTemplate() && + Rec->getDescribedClassTemplate()->getFriendObjectKind()); + if (ForConstraintInstantiation && IsFriend && + Rec->getNonTransparentDeclContext()->isFileContext()) { + return Response::ChangeDecl(Rec->getLexicalDeclContext()); + } + + // This is to make sure we pick up the VarTemplateSpecializationDecl that this + // lambda is defined inside of. + if (Rec->isLambda()) + if (const Decl *LCD = Rec->getLambdaContextDecl()) + return Response::ChangeDecl(LCD); + + return Response::UseNextDecl(Rec); +} + +Response HandleImplicitConceptSpecializationDecl( + const ImplicitConceptSpecializationDecl *CSD, + MultiLevelTemplateArgumentList &Result) { + Result.addOuterTemplateArguments( + const_cast<ImplicitConceptSpecializationDecl *>(CSD), + CSD->getTemplateArguments(), + /*Final=*/false); + return Response::UseNextDecl(CSD); +} + +Response HandleGenericDeclContext(const Decl *CurDecl) { + return Response::UseNextDecl(CurDecl); +} +} // namespace TemplateInstArgsHelpers +} // namespace + /// Retrieve the template argument list(s) that should be used to /// instantiate the definition of the given declaration. /// -/// \param D the declaration for which we are computing template instantiation +/// \param ND the declaration for which we are computing template instantiation /// arguments. /// -/// \param Innermost if non-NULL, the innermost template argument list. +/// \param Innermost if non-NULL, specifies a template argument list for the +/// template declaration passed as ND. /// /// \param RelativeToPrimary true if we should get the template /// arguments relative to the primary template, even when we're @@ -54,137 +277,64 @@ using namespace sema; /// template specializations. /// /// \param Pattern If non-NULL, indicates the pattern from which we will be -/// instantiating the definition of the given declaration, \p D. This is +/// instantiating the definition of the given declaration, \p ND. This is /// used to determine the proper set of template instantiation arguments for /// friend function template specializations. +/// +/// \param ForConstraintInstantiation when collecting arguments, +/// ForConstraintInstantiation indicates we should continue looking when +/// encountering a lambda generic call operator, and continue looking for +/// arguments on an enclosing class template. + MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( - const NamedDecl *D, const TemplateArgumentList *Innermost, - bool RelativeToPrimary, const FunctionDecl *Pattern) { + const NamedDecl *ND, bool Final, const TemplateArgumentList *Innermost, + bool RelativeToPrimary, const FunctionDecl *Pattern, + bool ForConstraintInstantiation, bool SkipForSpecialization) { + assert(ND && "Can't find arguments for a decl if one isn't provided"); // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; if (Innermost) - Result.addOuterTemplateArguments(Innermost); - - const auto *Ctx = dyn_cast<DeclContext>(D); - if (!Ctx) { - Ctx = D->getDeclContext(); - - // Add template arguments from a variable template instantiation. For a - // class-scope explicit specialization, there are no template arguments - // at this level, but there may be enclosing template arguments. - const auto *Spec = dyn_cast<VarTemplateSpecializationDecl>(D); - if (Spec && !Spec->isClassScopeExplicitSpecialization()) { - // We're done when we hit an explicit specialization. - if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa<VarTemplatePartialSpecializationDecl>(Spec)) - return Result; - - Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); - - // If this variable template specialization was instantiated from a - // specialized member that is a variable template, we're done. - assert(Spec->getSpecializedTemplate() && "No variable template?"); - llvm::PointerUnion<VarTemplateDecl*, - VarTemplatePartialSpecializationDecl*> Specialized - = Spec->getSpecializedTemplateOrPartial(); - if (VarTemplatePartialSpecializationDecl *Partial = - Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { - if (Partial->isMemberSpecialization()) - return Result; - } else { - VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>(); - if (Tmpl->isMemberSpecialization()) - return Result; - } - } - - // If we have a template template parameter with translation unit context, - // then we're performing substitution into a default template argument of - // this template template parameter before we've constructed the template - // that will own this template template parameter. In this case, we - // use empty template parameter lists for all of the outer templates - // to avoid performing any substitutions. - if (Ctx->isTranslationUnit()) { - if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { - for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I) - Result.addOuterTemplateArguments(None); - return Result; - } - } - } - - while (!Ctx->isFileContext()) { - // Add template arguments from a class template instantiation. - const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Ctx); - if (Spec && !Spec->isClassScopeExplicitSpecialization()) { - // We're done when we hit an explicit specialization. - if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && - !isa<ClassTemplatePartialSpecializationDecl>(Spec)) - break; - - Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); - - // If this class template specialization was instantiated from a - // specialized member that is a class template, we're done. - assert(Spec->getSpecializedTemplate() && "No class template?"); - if (Spec->getSpecializedTemplate()->isMemberSpecialization()) - break; - } - // Add template arguments from a function template specialization. - else if (const auto *Function = dyn_cast<FunctionDecl>(Ctx)) { - if (!RelativeToPrimary && - Function->getTemplateSpecializationKindForInstantiation() == - TSK_ExplicitSpecialization) - break; - - if (!RelativeToPrimary && Function->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization) { - // This is an implicit instantiation of an explicit specialization. We - // don't get any template arguments from this function but might get - // some from an enclosing template. - } else if (const TemplateArgumentList *TemplateArgs - = Function->getTemplateSpecializationArgs()) { - // Add the template arguments for this specialization. - Result.addOuterTemplateArguments(TemplateArgs); - - // If this function was instantiated from a specialized member that is - // a function template, we're done. - assert(Function->getPrimaryTemplate() && "No function template?"); - if (Function->getPrimaryTemplate()->isMemberSpecialization()) - break; - - // If this function is a generic lambda specialization, we are done. - if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) - break; - - } else if (Function->getDescribedFunctionTemplate()) { - assert(Result.getNumSubstitutedLevels() == 0 && - "Outer template not instantiated?"); - } - - // If this is a friend declaration and it declares an entity at - // namespace scope, take arguments from its lexical parent - // instead of its semantic parent, unless of course the pattern we're - // instantiating actually comes from the file's context! - if (Function->getFriendObjectKind() && - Function->getDeclContext()->isFileContext() && - (!Pattern || !Pattern->getLexicalDeclContext()->isFileContext())) { - Ctx = Function->getLexicalDeclContext(); - RelativeToPrimary = false; - continue; - } - } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(Ctx)) { - if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { - assert(Result.getNumSubstitutedLevels() == 0 && - "Outer template not instantiated?"); - if (ClassTemplate->isMemberSpecialization()) - break; + Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), + Innermost->asArray(), Final); + + const Decl *CurDecl = ND; + + while (!CurDecl->isFileContextDecl()) { + using namespace TemplateInstArgsHelpers; + Response R; + if (const auto *VarTemplSpec = + dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) { + R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization); + } else if (const auto *ClassTemplSpec = + dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) { + R = HandleClassTemplateSpec(ClassTemplSpec, Result, + SkipForSpecialization); + } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) { + R = HandleFunction(Function, Result, Pattern, RelativeToPrimary, + ForConstraintInstantiation); + } else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) { + R = HandleRecordDecl(Rec, Result, Context, ForConstraintInstantiation); + } else if (const auto *CSD = + dyn_cast<ImplicitConceptSpecializationDecl>(CurDecl)) { + R = HandleImplicitConceptSpecializationDecl(CSD, Result); + } else if (!isa<DeclContext>(CurDecl)) { + R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl); + if (CurDecl->getDeclContext()->isTranslationUnit()) { + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) { + R = HandleDefaultTempArgIntoTempTempParam(TTP, Result); + } } + } else { + R = HandleGenericDeclContext(CurDecl); } - Ctx = Ctx->getParent(); - RelativeToPrimary = false; + if (R.IsDone) + return Result; + if (R.ClearRelativeToPrimary) + RelativeToPrimary = false; + assert(R.NextDecl); + CurDecl = R.NextDecl; } return Result; @@ -204,6 +354,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { return true; case RequirementInstantiation: + case RequirementParameterInstantiation: case DefaultTemplateArgumentChecking: case DeclaringSpecialMember: case DeclaringImplicitEqualityComparison: @@ -377,8 +528,8 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( : InstantiatingTemplate( SemaRef, CodeSynthesisContext::RequirementInstantiation, PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, - /*Template=*/nullptr, /*TemplateArgs=*/None, &DeductionInfo) {} - + /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt, &DeductionInfo) { +} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -387,8 +538,16 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( : InstantiatingTemplate( SemaRef, CodeSynthesisContext::NestedRequirementConstraintsCheck, PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, - /*Template=*/nullptr, /*TemplateArgs=*/None) {} + /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt) {} +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, const RequiresExpr *RE, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::RequirementParameterInstantiation, + PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, + /*Template=*/nullptr, /*TemplateArgs=*/std::nullopt, &DeductionInfo) { +} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -424,6 +583,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( SemaRef, CodeSynthesisContext::ParameterMappingSubstitution, PointOfInstantiation, InstantiationRange, Template) {} + void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) { Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext; InNonInstantiationSFINAEContext = false; @@ -593,7 +753,7 @@ void Sema::PrintInstantiationStack() { TemplateDecl *Template = cast<TemplateDecl>(Active->Template); SmallString<128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); - Template->printName(OS); + Template->printName(OS, getPrintingPolicy()); printTemplateArgumentList(OS, Active->template_arguments(), getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, @@ -659,7 +819,7 @@ void Sema::PrintInstantiationStack() { SmallString<128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); - FD->printName(OS); + FD->printName(OS, getPrintingPolicy()); printTemplateArgumentList(OS, Active->template_arguments(), getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, @@ -729,6 +889,11 @@ void Sema::PrintInstantiationStack() { diag::note_template_requirement_instantiation_here) << Active->InstantiationRange; break; + case CodeSynthesisContext::RequirementParameterInstantiation: + Diags.Report(Active->PointOfInstantiation, + diag::note_template_requirement_params_instantiation_here) + << Active->InstantiationRange; + break; case CodeSynthesisContext::NestedRequirementConstraintsCheck: Diags.Report(Active->PointOfInstantiation, @@ -790,8 +955,7 @@ void Sema::PrintInstantiationStack() { Diags.Report(Active->PointOfInstantiation, diag::note_building_builtin_dump_struct_call) << convertCallArgsToString( - *this, - llvm::makeArrayRef(Active->CallArgs, Active->NumCallArgs)); + *this, llvm::ArrayRef(Active->CallArgs, Active->NumCallArgs)); break; case CodeSynthesisContext::Memoization: @@ -819,7 +983,7 @@ void Sema::PrintInstantiationStack() { } SmallString<128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); - cast<NamedDecl>(Active->Entity)->printName(OS); + cast<NamedDecl>(Active->Entity)->printName(OS, getPrintingPolicy()); if (!isa<FunctionDecl>(Active->Entity)) { printTemplateArgumentList(OS, Active->template_arguments(), getPrintingPolicy()); @@ -848,9 +1012,9 @@ void Sema::PrintInstantiationStack() { } } -Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { +std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { if (InNonInstantiationSFINAEContext) - return Optional<TemplateDeductionInfo *>(nullptr); + return std::optional<TemplateDeductionInfo *>(nullptr); for (SmallVectorImpl<CodeSynthesisContext>::const_reverse_iterator Active = CodeSynthesisContexts.rbegin(), @@ -864,7 +1028,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { // context, depending on what else is on the stack. if (isa<TypeAliasTemplateDecl>(Active->Entity)) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: case CodeSynthesisContext::ExceptionSpecInstantiation: case CodeSynthesisContext::ConstraintsCheck: @@ -872,7 +1036,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::ConstraintNormalization: case CodeSynthesisContext::NestedRequirementConstraintsCheck: // This is a template instantiation, so there is no SFINAE. - return None; + return std::nullopt; case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: case CodeSynthesisContext::PriorTemplateArgumentSubstitution: @@ -887,6 +1051,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: case CodeSynthesisContext::ConstraintSubstitution: case CodeSynthesisContext::RequirementInstantiation: + case CodeSynthesisContext::RequirementParameterInstantiation: // We're either substituting explicitly-specified template arguments, // deduced template arguments, a constraint expression or a requirement // in a requires expression, so SFINAE applies. @@ -901,7 +1066,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::BuildingBuiltinDumpStructCall: // This happens in a context unrelated to template instantiation, so // there is no SFINAE. - return None; + return std::nullopt; case CodeSynthesisContext::ExceptionSpecEvaluation: // FIXME: This should not be treated as a SFINAE context, because @@ -916,10 +1081,10 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { // The inner context was transparent for SFINAE. If it occurred within a // non-instantiation SFINAE context, then SFINAE applies. if (Active->SavedInNonInstantiationSFINAEContext) - return Optional<TemplateDeductionInfo *>(nullptr); + return std::optional<TemplateDeductionInfo *>(nullptr); } - return None; + return std::nullopt; } //===----------------------------------------------------------------------===/ @@ -930,16 +1095,23 @@ namespace { const MultiLevelTemplateArgumentList &TemplateArgs; SourceLocation Loc; DeclarationName Entity; + bool EvaluateConstraints = true; public: typedef TreeTransform<TemplateInstantiator> inherited; TemplateInstantiator(Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs, - SourceLocation Loc, - DeclarationName Entity) - : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc), - Entity(Entity) { } + SourceLocation Loc, DeclarationName Entity) + : inherited(SemaRef), TemplateArgs(TemplateArgs), Loc(Loc), + Entity(Entity) {} + + void setEvaluateConstraints(bool B) { + EvaluateConstraints = B; + } + bool getEvaluateConstraints() { + return EvaluateConstraints; + } /// Determine whether the given type \p T has already been /// transformed. @@ -965,11 +1137,18 @@ namespace { return TemplateArgs.getNewDepth(Depth); } + std::optional<unsigned> getPackIndex(TemplateArgument Pack) { + int Index = getSema().ArgumentPackSubstitutionIndex; + if (Index == -1) + return std::nullopt; + return Pack.pack_size() - 1 - Index; + } + bool TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, bool &ShouldExpand, bool &RetainExpansion, - Optional<unsigned> &NumExpansions) { + std::optional<unsigned> &NumExpansions) { return getSema().CheckParameterPacksForExpansion(EllipsisLoc, PatternRange, Unexpanded, TemplateArgs, @@ -1052,7 +1231,7 @@ namespace { // We recreated a local declaration, but not by instantiating it. There // may be pending dependent diagnostics to produce. - if (auto *DC = dyn_cast<DeclContext>(Old)) + if (auto *DC = dyn_cast<DeclContext>(Old); DC && DC->isDependentContext()) SemaRef.PerformDependentDiagnostics(DC, TemplateArgs); } @@ -1128,30 +1307,79 @@ namespace { Qualifiers ThisTypeQuals, Fn TransformExceptionSpec); - ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, - int indexAdjustment, - Optional<unsigned> NumExpansions, - bool ExpectParameterPack); + ParmVarDecl * + TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, + std::optional<unsigned> NumExpansions, + bool ExpectParameterPack); + using inherited::TransformTemplateTypeParmType; /// Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL); + TemplateTypeParmTypeLoc TL, + bool SuppressObjCLifetime); + + QualType BuildSubstTemplateTypeParmType( + TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final, + Decl *AssociatedDecl, unsigned Index, std::optional<unsigned> PackIndex, + TemplateArgument Arg, SourceLocation NameLoc); /// Transforms an already-substituted template type parameter pack /// into either itself (if we aren't substituting into its pack expansion) /// or the appropriate substituted argument. - QualType TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, - SubstTemplateTypeParmPackTypeLoc TL); + using inherited::TransformSubstTemplateTypeParmPackType; + QualType + TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL, + bool SuppressObjCLifetime); ExprResult TransformLambdaExpr(LambdaExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformLambdaExpr(E); + Sema::ConstraintEvalRAII<TemplateInstantiator> RAII(*this); + ExprResult Result = inherited::TransformLambdaExpr(E); + if (Result.isInvalid()) + return Result; + + CXXMethodDecl *MD = Result.getAs<LambdaExpr>()->getCallOperator(); + for (ParmVarDecl *PVD : MD->parameters()) { + if (!PVD->hasDefaultArg()) + continue; + Expr *UninstExpr = PVD->getUninstantiatedDefaultArg(); + // FIXME: Obtain the source location for the '=' token. + SourceLocation EqualLoc = UninstExpr->getBeginLoc(); + if (SemaRef.SubstDefaultArgument(EqualLoc, PVD, TemplateArgs)) { + // If substitution fails, the default argument is set to a + // RecoveryExpr that wraps the uninstantiated default argument so + // that downstream diagnostics are omitted. + ExprResult ErrorResult = SemaRef.CreateRecoveryExpr( + UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), + { UninstExpr }, UninstExpr->getType()); + if (ErrorResult.isUsable()) + PVD->setDefaultArg(ErrorResult.get()); + } + } + + return Result; } ExprResult TransformRequiresExpr(RequiresExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); - return inherited::TransformRequiresExpr(E); + ExprResult TransReq = inherited::TransformRequiresExpr(E); + if (TransReq.isInvalid()) + return TransReq; + assert(TransReq.get() != E && + "Do not change value of isSatisfied for the existing expression. " + "Create a new expression instead."); + if (E->getBody()->isDependentContext()) { + Sema::SFINAETrap Trap(SemaRef); + // We recreate the RequiresExpr body, but not by instantiating it. + // Produce pending diagnostics for dependent access check. + SemaRef.PerformDependentDiagnostics(E->getBody(), TemplateArgs); + // FIXME: Store SFINAE diagnostics in RequiresExpr for diagnosis. + if (Trap.hasErrorOccurred()) + TransReq.getAs<RequiresExpr>()->setSatisfied(false); + } + return TransReq; } bool TransformRequiresExprRequirements( @@ -1191,6 +1419,7 @@ namespace { DeclContext *Owner = OrigTPL->getParam(0)->getDeclContext(); TemplateDeclInstantiator DeclInstantiator(getSema(), /* DeclContext *Owner */ Owner, TemplateArgs); + DeclInstantiator.setEvaluateConstraints(EvaluateConstraints); return DeclInstantiator.SubstTemplateParams(OrigTPL); } @@ -1200,11 +1429,19 @@ namespace { TransformExprRequirement(concepts::ExprRequirement *Req); concepts::NestedRequirement * TransformNestedRequirement(concepts::NestedRequirement *Req); + ExprResult TransformRequiresTypeParams( + SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE, + RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params, + SmallVectorImpl<QualType> &PTypes, + SmallVectorImpl<ParmVarDecl *> &TransParams, + Sema::ExtParameterInfoBuilder &PInfos); private: - ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm, - SourceLocation loc, - TemplateArgument arg); + ExprResult + transformNonTypeTemplateParmRef(Decl *AssociatedDecl, + const NonTypeTemplateParmDecl *parm, + SourceLocation loc, TemplateArgument arg, + std::optional<unsigned> PackIndex); }; } @@ -1394,6 +1631,9 @@ TemplateName TemplateInstantiator::TransformTemplateName( return Arg.getAsTemplate(); } + auto [AssociatedDecl, Final] = + TemplateArgs.getAssociatedDecl(TTP->getDepth()); + std::optional<unsigned> PackIndex; if (TTP->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -1402,9 +1642,11 @@ TemplateName TemplateInstantiator::TransformTemplateName( // We have the template argument pack to substitute, but we're not // actually expanding the enclosing pack expansion yet. So, just // keep the entire argument pack. - return getSema().Context.getSubstTemplateTemplateParmPack(TTP, Arg); + return getSema().Context.getSubstTemplateTemplateParmPack( + Arg, AssociatedDecl, TTP->getIndex(), Final); } + PackIndex = getPackIndex(Arg); Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } @@ -1413,8 +1655,10 @@ TemplateName TemplateInstantiator::TransformTemplateName( assert(!Template.getAsQualifiedTemplateName() && "template decl to substitute is qualified?"); - Template = getSema().Context.getSubstTemplateTemplateParm(TTP, Template); - return Template; + if (Final) + return Template; + return getSema().Context.getSubstTemplateTemplateParm( + Template, AssociatedDecl, TTP->getIndex(), PackIndex); } } @@ -1423,9 +1667,14 @@ TemplateName TemplateInstantiator::TransformTemplateName( if (getSema().ArgumentPackSubstitutionIndex == -1) return Name; - TemplateArgument Arg = SubstPack->getArgumentPack(); - Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); - return Arg.getAsTemplate().getNameToSubstitute(); + TemplateArgument Pack = SubstPack->getArgumentPack(); + TemplateName Template = + getPackSubstitutedTemplateArgument(getSema(), Pack).getAsTemplate(); + if (SubstPack->getFinal()) + return Template; + return getSema().Context.getSubstTemplateTemplateParm( + Template.getNameToSubstitute(), SubstPack->getAssociatedDecl(), + SubstPack->getIndex(), getPackIndex(Pack)); } return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, @@ -1469,6 +1718,8 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, return Arg.getAsExpr(); } + auto [AssociatedDecl, _] = TemplateArgs.getAssociatedDecl(NTTP->getDepth()); + std::optional<unsigned> PackIndex; if (NTTP->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -1486,16 +1737,17 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, QualType ExprType = TargetType.getNonLValueExprType(SemaRef.Context); if (TargetType->isRecordType()) ExprType.addConst(); - + // FIXME: Pass in Final. return new (SemaRef.Context) SubstNonTypeTemplateParmPackExpr( ExprType, TargetType->isReferenceType() ? VK_LValue : VK_PRValue, - NTTP, E->getLocation(), Arg); + E->getLocation(), Arg, AssociatedDecl, NTTP->getPosition()); } - + PackIndex = getPackIndex(Arg); Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } - - return transformNonTypeTemplateParmRef(NTTP, E->getLocation(), Arg); + // FIXME: Don't put subst node on Final replacement. + return transformNonTypeTemplateParmRef(AssociatedDecl, NTTP, E->getLocation(), + Arg, PackIndex); } const LoopHintAttr * @@ -1516,9 +1768,9 @@ TemplateInstantiator::TransformLoopHintAttr(const LoopHintAttr *LH) { } ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( - NonTypeTemplateParmDecl *parm, - SourceLocation loc, - TemplateArgument arg) { + Decl *AssociatedDecl, const NonTypeTemplateParmDecl *parm, + SourceLocation loc, TemplateArgument arg, + std::optional<unsigned> PackIndex) { ExprResult result; // Determine the substituted parameter type. We can usually infer this from @@ -1586,9 +1838,10 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( return ExprError(); Expr *resultExpr = result.get(); + // FIXME: Don't put subst node on final replacement. return new (SemaRef.Context) SubstNonTypeTemplateParmExpr( - resultExpr->getType(), resultExpr->getValueKind(), loc, parm, refParam, - resultExpr); + resultExpr->getType(), resultExpr->getValueKind(), loc, resultExpr, + AssociatedDecl, parm->getIndex(), PackIndex, refParam); } ExprResult @@ -1599,11 +1852,12 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( return E; } - TemplateArgument Arg = E->getArgumentPack(); - Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); - return transformNonTypeTemplateParmRef(E->getParameterPack(), - E->getParameterPackLocation(), - Arg); + TemplateArgument Pack = E->getArgumentPack(); + TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack); + // FIXME: Don't put subst node on final replacement. + return transformNonTypeTemplateParmRef( + E->getAssociatedDecl(), E->getParameterPack(), + E->getParameterPackLocation(), Arg, getPackIndex(Pack)); } ExprResult @@ -1637,13 +1891,16 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr( // Type=char)), // Type=decltype(2))) // The call to CheckTemplateArgument here produces the ImpCast. - TemplateArgument Converted; - if (SemaRef.CheckTemplateArgument(E->getParameter(), SubstType, - SubstReplacement.get(), - Converted).isInvalid()) + TemplateArgument SugaredConverted, CanonicalConverted; + if (SemaRef + .CheckTemplateArgument(E->getParameter(), SubstType, + SubstReplacement.get(), SugaredConverted, + CanonicalConverted, Sema::CTAK_Specified) + .isInvalid()) return true; - return transformNonTypeTemplateParmRef(E->getParameter(), - E->getExprLoc(), Converted); + return transformNonTypeTemplateParmRef(E->getAssociatedDecl(), + E->getParameter(), E->getExprLoc(), + SugaredConverted, E->getPackIndex()); } ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD, @@ -1744,9 +2001,9 @@ ExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( assert(!cast<FunctionDecl>(E->getParam()->getDeclContext())-> getDescribedFunctionTemplate() && "Default arg expressions are never formed in dependent cases."); - return SemaRef.BuildCXXDefaultArgExpr(E->getUsedLocation(), - cast<FunctionDecl>(E->getParam()->getDeclContext()), - E->getParam()); + return SemaRef.BuildCXXDefaultArgExpr( + E->getUsedLocation(), cast<FunctionDecl>(E->getParam()->getDeclContext()), + E->getParam()); } template<typename Fn> @@ -1761,22 +2018,50 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, TLB, TL, ThisContext, ThisTypeQuals, TransformExceptionSpec); } -ParmVarDecl * -TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm, - int indexAdjustment, - Optional<unsigned> NumExpansions, - bool ExpectParameterPack) { - auto NewParm = - SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment, - NumExpansions, ExpectParameterPack); +ParmVarDecl *TemplateInstantiator::TransformFunctionTypeParam( + ParmVarDecl *OldParm, int indexAdjustment, + std::optional<unsigned> NumExpansions, bool ExpectParameterPack) { + auto NewParm = SemaRef.SubstParmVarDecl( + OldParm, TemplateArgs, indexAdjustment, NumExpansions, + ExpectParameterPack, EvaluateConstraints); if (NewParm && SemaRef.getLangOpts().OpenCL) SemaRef.deduceOpenCLAddressSpace(NewParm); return NewParm; } +QualType TemplateInstantiator::BuildSubstTemplateTypeParmType( + TypeLocBuilder &TLB, bool SuppressObjCLifetime, bool Final, + Decl *AssociatedDecl, unsigned Index, std::optional<unsigned> PackIndex, + TemplateArgument Arg, SourceLocation NameLoc) { + QualType Replacement = Arg.getAsType(); + + // If the template parameter had ObjC lifetime qualifiers, + // then any such qualifiers on the replacement type are ignored. + if (SuppressObjCLifetime) { + Qualifiers RQs; + RQs = Replacement.getQualifiers(); + RQs.removeObjCLifetime(); + Replacement = + SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(), RQs); + } + + if (Final) { + TLB.pushTrivial(SemaRef.Context, Replacement, NameLoc); + return Replacement; + } + // TODO: only do this uniquing once, at the start of instantiation. + QualType Result = getSema().Context.getSubstTemplateTypeParmType( + Replacement, AssociatedDecl, Index, PackIndex); + SubstTemplateTypeParmTypeLoc NewTL = + TLB.push<SubstTemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(NameLoc); + return Result; +} + QualType TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL) { + TemplateTypeParmTypeLoc TL, + bool SuppressObjCLifetime) { const TemplateTypeParmType *T = TL.getTypePtr(); if (T->getDepth() < TemplateArgs.getNumLevels()) { // Replace the template type parameter with its corresponding @@ -1813,6 +2098,9 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, return NewT; } + auto [AssociatedDecl, Final] = + TemplateArgs.getAssociatedDecl(T->getDepth()); + std::optional<unsigned> PackIndex; if (T->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -1821,29 +2109,25 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, // We have the template argument pack, but we're not expanding the // enclosing pack expansion yet. Just save the template argument // pack for later substitution. - QualType Result - = getSema().Context.getSubstTemplateTypeParmPackType(T, Arg); + QualType Result = getSema().Context.getSubstTemplateTypeParmPackType( + AssociatedDecl, T->getIndex(), Final, Arg); SubstTemplateTypeParmPackTypeLoc NewTL = TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } + // PackIndex starts from last element. + PackIndex = getPackIndex(Arg); Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); } assert(Arg.getKind() == TemplateArgument::Type && "Template argument kind mismatch"); - QualType Replacement = Arg.getAsType(); - - // TODO: only do this uniquing once, at the start of instantiation. - QualType Result - = getSema().Context.getSubstTemplateTypeParmType(T, Replacement); - SubstTemplateTypeParmTypeLoc NewTL - = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - return Result; + return BuildSubstTemplateTypeParmType(TLB, SuppressObjCLifetime, Final, + AssociatedDecl, T->getIndex(), + PackIndex, Arg, TL.getNameLoc()); } // The template type parameter comes from an inner template (e.g., @@ -1853,8 +2137,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, TemplateTypeParmDecl *NewTTPDecl = nullptr; if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl()) NewTTPDecl = cast_or_null<TemplateTypeParmDecl>( - TransformDecl(TL.getNameLoc(), OldTTPDecl)); - + TransformDecl(TL.getNameLoc(), OldTTPDecl)); QualType Result = getSema().Context.getTemplateTypeParmType( T->getDepth() - TemplateArgs.getNumSubstitutedLevels(), T->getIndex(), T->isParameterPack(), NewTTPDecl); @@ -1863,29 +2146,30 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, return Result; } -QualType -TemplateInstantiator::TransformSubstTemplateTypeParmPackType( - TypeLocBuilder &TLB, - SubstTemplateTypeParmPackTypeLoc TL) { +QualType TemplateInstantiator::TransformSubstTemplateTypeParmPackType( + TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL, + bool SuppressObjCLifetime) { + const SubstTemplateTypeParmPackType *T = TL.getTypePtr(); + + Decl *NewReplaced = TransformDecl(TL.getNameLoc(), T->getAssociatedDecl()); + if (getSema().ArgumentPackSubstitutionIndex == -1) { // We aren't expanding the parameter pack, so just return ourselves. - SubstTemplateTypeParmPackTypeLoc NewTL - = TLB.push<SubstTemplateTypeParmPackTypeLoc>(TL.getType()); + QualType Result = TL.getType(); + if (NewReplaced != T->getAssociatedDecl()) + Result = getSema().Context.getSubstTemplateTypeParmPackType( + NewReplaced, T->getIndex(), T->getFinal(), T->getArgumentPack()); + SubstTemplateTypeParmPackTypeLoc NewTL = + TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); - return TL.getType(); + return Result; } - TemplateArgument Arg = TL.getTypePtr()->getArgumentPack(); - Arg = getPackSubstitutedTemplateArgument(getSema(), Arg); - QualType Result = Arg.getAsType(); - - Result = getSema().Context.getSubstTemplateTypeParmType( - TL.getTypePtr()->getReplacedParameter(), - Result); - SubstTemplateTypeParmTypeLoc NewTL - = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - return Result; + TemplateArgument Pack = T->getArgumentPack(); + TemplateArgument Arg = getPackSubstitutedTemplateArgument(getSema(), Pack); + return BuildSubstTemplateTypeParmType( + TLB, SuppressObjCLifetime, T->getFinal(), NewReplaced, T->getIndex(), + getPackIndex(Pack), Arg, TL.getNameLoc()); } template<typename EntityPrinter> @@ -1914,6 +2198,37 @@ createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) { StringRef(MessageBuf, Message.size())}; } +ExprResult TemplateInstantiator::TransformRequiresTypeParams( + SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE, + RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params, + SmallVectorImpl<QualType> &PTypes, + SmallVectorImpl<ParmVarDecl *> &TransParams, + Sema::ExtParameterInfoBuilder &PInfos) { + + TemplateDeductionInfo Info(KWLoc); + Sema::InstantiatingTemplate TypeInst(SemaRef, KWLoc, + RE, Info, + SourceRange{KWLoc, RBraceLoc}); + Sema::SFINAETrap Trap(SemaRef); + + unsigned ErrorIdx; + if (getDerived().TransformFunctionTypeParams( + KWLoc, Params, /*ParamTypes=*/nullptr, /*ParamInfos=*/nullptr, PTypes, + &TransParams, PInfos, &ErrorIdx) || + Trap.hasErrorOccurred()) { + SmallVector<concepts::Requirement *, 4> TransReqs; + ParmVarDecl *FailedDecl = Params[ErrorIdx]; + // Add a 'failed' Requirement to contain the error that caused the failure + // here. + TransReqs.push_back(RebuildTypeRequirement(createSubstDiag( + SemaRef, Info, [&](llvm::raw_ostream &OS) { OS << *FailedDecl; }))); + return getDerived().RebuildRequiresExpr(KWLoc, Body, TransParams, TransReqs, + RBraceLoc); + } + + return ExprResult{}; +} + concepts::TypeRequirement * TemplateInstantiator::TransformTypeRequirement(concepts::TypeRequirement *Req) { if (!Req->isDependent() && !AlwaysRebuild()) @@ -1971,7 +2286,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { TransExpr = TransExprRes.get(); } - llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq; + std::optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq; const auto &RetReq = Req->getReturnTypeRequirement(); if (RetReq.isEmpty()) TransRetReq.emplace(); @@ -1985,8 +2300,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { Req, Info, OrigTPL->getSourceRange()); if (TPLInst.isInvalid()) return nullptr; - TemplateParameterList *TPL = - TransformTemplateParameterList(OrigTPL); + TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL); if (!TPL) TransRetReq.emplace(createSubstDiag(SemaRef, Info, [&] (llvm::raw_ostream& OS) { @@ -2012,10 +2326,10 @@ TemplateInstantiator::TransformNestedRequirement( concepts::NestedRequirement *Req) { if (!Req->isDependent() && !AlwaysRebuild()) return Req; - if (Req->isSubstitutionFailure()) { + if (Req->hasInvalidConstraint()) { if (AlwaysRebuild()) - return RebuildNestedRequirement( - Req->getSubstitutionDiagnostic()); + return RebuildNestedRequirement(Req->getInvalidConstraintEntity(), + Req->getConstraintSatisfaction()); return Req; } Sema::InstantiatingTemplate ReqInst(SemaRef, @@ -2035,36 +2349,30 @@ TemplateInstantiator::TransformNestedRequirement( Req->getConstraintExpr()->getSourceRange()); if (ConstrInst.isInvalid()) return nullptr; - TransConstraint = TransformExpr(Req->getConstraintExpr()); - if (!TransConstraint.isInvalid()) { - bool CheckSucceeded = - SemaRef.CheckConstraintExpression(TransConstraint.get()); - (void)CheckSucceeded; - assert((CheckSucceeded || Trap.hasErrorOccurred()) && - "CheckConstraintExpression failed, but " - "did not produce a SFINAE error"); - } - // Use version of CheckConstraintSatisfaction that does no substitutions. - if (!TransConstraint.isInvalid() && - !TransConstraint.get()->isInstantiationDependent() && - !Trap.hasErrorOccurred()) { - bool CheckFailed = SemaRef.CheckConstraintSatisfaction( - TransConstraint.get(), Satisfaction); - (void)CheckFailed; - assert((!CheckFailed || Trap.hasErrorOccurred()) && - "CheckConstraintSatisfaction failed, " - "but did not produce a SFINAE error"); - } - if (TransConstraint.isInvalid() || Trap.hasErrorOccurred()) - return RebuildNestedRequirement(createSubstDiag(SemaRef, Info, - [&] (llvm::raw_ostream& OS) { - Req->getConstraintExpr()->printPretty(OS, nullptr, - SemaRef.getPrintingPolicy()); - })); + llvm::SmallVector<Expr *> Result; + if (!SemaRef.CheckConstraintSatisfaction( + nullptr, {Req->getConstraintExpr()}, Result, TemplateArgs, + Req->getConstraintExpr()->getSourceRange(), Satisfaction) && + !Result.empty()) + TransConstraint = Result[0]; + assert(!Trap.hasErrorOccurred() && "Substitution failures must be handled " + "by CheckConstraintSatisfaction."); } - if (TransConstraint.get()->isInstantiationDependent()) + if (TransConstraint.isUsable() && + TransConstraint.get()->isInstantiationDependent()) return new (SemaRef.Context) concepts::NestedRequirement(TransConstraint.get()); + if (TransConstraint.isInvalid() || !TransConstraint.get() || + Satisfaction.HasSubstitutionFailure()) { + SmallString<128> Entity; + llvm::raw_svector_ostream OS(Entity); + Req->getConstraintExpr()->printPretty(OS, nullptr, + SemaRef.getPrintingPolicy()); + char *EntityBuf = new (SemaRef.Context) char[Entity.size()]; + std::copy(Entity.begin(), Entity.end(), EntityBuf); + return new (SemaRef.Context) concepts::NestedRequirement( + SemaRef.Context, StringRef(EntityBuf, Entity.size()), Satisfaction); + } return new (SemaRef.Context) concepts::NestedRequirement( SemaRef.Context, TransConstraint.get(), Satisfaction); } @@ -2196,7 +2504,8 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext, - Qualifiers ThisTypeQuals) { + Qualifiers ThisTypeQuals, + bool EvaluateConstraints) { assert(!CodeSynthesisContexts.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); @@ -2205,6 +2514,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, return T; TemplateInstantiator Instantiator(*this, Args, Loc, Entity); + Instantiator.setEvaluateConstraints(EvaluateConstraints); TypeLocBuilder TLB; @@ -2349,9 +2659,19 @@ namespace { bool Sema::SubstTypeConstraint( TemplateTypeParmDecl *Inst, const TypeConstraint *TC, - const MultiLevelTemplateArgumentList &TemplateArgs) { + const MultiLevelTemplateArgumentList &TemplateArgs, + bool EvaluateConstraints) { const ASTTemplateArgumentListInfo *TemplArgInfo = TC->getTemplateArgsAsWritten(); + + if (!EvaluateConstraints) { + Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(), + TC->getConceptNameInfo(), TC->getNamedConcept(), + TC->getNamedConcept(), TemplArgInfo, + TC->getImmediatelyDeclaredConstraint()); + return false; + } + TemplateArgumentListInfo InstArgs; if (TemplArgInfo) { @@ -2370,11 +2690,10 @@ bool Sema::SubstTypeConstraint( : SourceLocation()); } -ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, - const MultiLevelTemplateArgumentList &TemplateArgs, - int indexAdjustment, - Optional<unsigned> NumExpansions, - bool ExpectParameterPack) { +ParmVarDecl *Sema::SubstParmVarDecl( + ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, + int indexAdjustment, std::optional<unsigned> NumExpansions, + bool ExpectParameterPack, bool EvaluateConstraint) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); TypeSourceInfo *NewDI = nullptr; @@ -2432,9 +2751,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, // template's described function, but we might also get here later. // Make sure we do not instantiate the TypeConstraint more than once. if (Inst && !Inst->getTypeConstraint()) { - // TODO: Concepts: do not instantiate the constraint (delayed constraint - // substitution) - if (SubstTypeConstraint(Inst, TC, TemplateArgs)) + if (SubstTypeConstraint(Inst, TC, TemplateArgs, EvaluateConstraint)) return nullptr; } } @@ -2457,29 +2774,17 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, NewParm->setUnparsedDefaultArg(); UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm); } else if (Expr *Arg = OldParm->getDefaultArg()) { - FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext()); - if (OwningFunc->isInLocalScopeForInstantiation()) { - // Instantiate default arguments for methods of local classes (DR1484) - // and non-defining declarations. - Sema::ContextRAII SavedContext(*this, OwningFunc); - LocalInstantiationScope Local(*this, true); - ExprResult NewArg = SubstExpr(Arg, TemplateArgs); - if (NewArg.isUsable()) { - // It would be nice if we still had this. - SourceLocation EqualLoc = NewArg.get()->getBeginLoc(); - ExprResult Result = - ConvertParamDefaultArgument(NewParm, NewArg.get(), EqualLoc); - if (Result.isInvalid()) - return nullptr; - - SetParamDefaultArgument(NewParm, Result.getAs<Expr>(), EqualLoc); - } - } else { - // FIXME: if we non-lazily instantiated non-dependent default args for - // non-dependent parameter types we could remove a bunch of duplicate - // conversion warnings for such arguments. - NewParm->setUninstantiatedDefaultArg(Arg); - } + // Default arguments cannot be substituted until the declaration context + // for the associated function or lambda capture class is available. + // This is necessary for cases like the following where construction of + // the lambda capture class for the outer lambda is dependent on the + // parameter types but where the default argument is dependent on the + // outer lambda's declaration context. + // template <typename T> + // auto f() { + // return [](T = []{ return T{}; }()) { return 0; }; + // } + NewParm->setUninstantiatedDefaultArg(Arg); } NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg()); @@ -2524,6 +2829,88 @@ bool Sema::SubstParmTypes( Loc, Params, nullptr, ExtParamInfos, ParamTypes, OutParams, ParamInfos); } +/// Substitute the given template arguments into the default argument. +bool Sema::SubstDefaultArgument( + SourceLocation Loc, + ParmVarDecl *Param, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool ForCallExpr) { + FunctionDecl *FD = cast<FunctionDecl>(Param->getDeclContext()); + Expr *PatternExpr = Param->getUninstantiatedDefaultArg(); + + EnterExpressionEvaluationContext EvalContext( + *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); + + InstantiatingTemplate Inst(*this, Loc, Param, TemplateArgs.getInnermost()); + if (Inst.isInvalid()) + return true; + if (Inst.isAlreadyInstantiating()) { + Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; + Param->setInvalidDecl(); + return true; + } + + ExprResult Result; + { + // C++ [dcl.fct.default]p5: + // The names in the [default argument] expression are bound, and + // the semantic constraints are checked, at the point where the + // default argument expression appears. + ContextRAII SavedContext(*this, FD); + std::unique_ptr<LocalInstantiationScope> LIS; + + if (ForCallExpr) { + // When instantiating a default argument due to use in a call expression, + // an instantiation scope that includes the parameters of the callee is + // required to satisfy references from the default argument. For example: + // template<typename T> void f(T a, int = decltype(a)()); + // void g() { f(0); } + LIS = std::make_unique<LocalInstantiationScope>(*this); + FunctionDecl *PatternFD = FD->getTemplateInstantiationPattern( + /*ForDefinition*/ false); + if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs)) + return true; + } + + runWithSufficientStackSpace(Loc, [&] { + Result = SubstInitializer(PatternExpr, TemplateArgs, + /*DirectInit*/false); + }); + } + if (Result.isInvalid()) + return true; + + if (ForCallExpr) { + // Check the expression as an initializer for the parameter. + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Context, Param); + InitializationKind Kind = InitializationKind::CreateCopy( + Param->getLocation(), + /*FIXME:EqualLoc*/ PatternExpr->getBeginLoc()); + Expr *ResultE = Result.getAs<Expr>(); + + InitializationSequence InitSeq(*this, Entity, Kind, ResultE); + Result = InitSeq.Perform(*this, Entity, Kind, ResultE); + if (Result.isInvalid()) + return true; + + Result = + ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(), + /*DiscardedValue*/ false); + } else { + // FIXME: Obtain the source location for the '=' token. + SourceLocation EqualLoc = PatternExpr->getBeginLoc(); + Result = ConvertParamDefaultArgument(Param, Result.getAs<Expr>(), EqualLoc); + } + if (Result.isInvalid()) + return true; + + // Remember the instantiated default argument. + Param->setDefaultArg(Result.getAs<Expr>()); + + return false; +} + /// Perform substitution on the base class specifiers of the /// given class template specialization. /// @@ -2556,7 +2943,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, Unexpanded); bool ShouldExpand = false; bool RetainExpansion = false; - Optional<unsigned> NumExpansions; + std::optional<unsigned> NumExpansions; if (CheckParameterPacksForExpansion(Base.getEllipsisLoc(), Base.getSourceRange(), Unexpanded, @@ -2743,6 +3130,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Instantiation->setInvalidDecl(); TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs); + Instantiator.setEvaluateConstraints(false); SmallVector<Decl*, 4> Fields; // Delay instantiation of late parsed attributes. LateInstantiatedAttrVec LateAttrs; @@ -3033,6 +3421,8 @@ bool Sema::InstantiateInClassInitializer( ContextRAII SavedContext(*this, Instantiation->getParent()); EnterExpressionEvaluationContext EvalContext( *this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated); + ExprEvalContexts.back().DelayedDefaultInitializationContext = { + PointOfInstantiation, Instantiation, CurContext}; LocalInstantiationScope Scope(*this, true); @@ -3130,7 +3520,7 @@ getPatternForClassTemplateSpecialization( } else { Matched.push_back(PartialSpecMatchResult()); Matched.back().Partial = Partial; - Matched.back().Args = Info.take(); + Matched.back().Args = Info.takeCanonical(); } } @@ -3521,11 +3911,9 @@ bool Sema::SubstTemplateArguments( ArrayRef<TemplateArgumentLoc> Args, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateArgumentListInfo &Out) { - TemplateInstantiator Instantiator(*this, TemplateArgs, - SourceLocation(), + TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), DeclarationName()); - return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), - Out); + return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), Out); } ExprResult @@ -3539,11 +3927,23 @@ Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) { return Instantiator.TransformExpr(E); } +ExprResult +Sema::SubstConstraintExpr(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs) { + if (!E) + return E; + + // This is where we need to make sure we 'know' constraint checking needs to + // happen. + TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), + DeclarationName()); + return Instantiator.TransformExpr(E); +} + ExprResult Sema::SubstInitializer(Expr *Init, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit) { - TemplateInstantiator Instantiator(*this, TemplateArgs, - SourceLocation(), + TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), DeclarationName()); return Instantiator.TransformInitializer(Init, CXXDirectInit); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 9bf6ca1f8084..7a0da8d08333 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -29,6 +29,7 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateInstCallback.h" #include "llvm/Support/TimeProfiler.h" +#include <optional> using namespace clang; @@ -120,7 +121,7 @@ static void instantiateDependentAlignedAttr( // Determine whether we can expand this attribute pack yet. bool Expand = true, RetainExpansion = false; - Optional<unsigned> NumExpansions; + std::optional<unsigned> NumExpansions; // FIXME: Use the actual location of the ellipsis. SourceLocation EllipsisLoc = Aligned->getLocation(); if (S.CheckParameterPacksForExpansion(EllipsisLoc, Aligned->getRange(), @@ -461,7 +462,7 @@ static void instantiateOMPDeclareVariantAttr( // Check function/variant ref for `omp declare variant` but not for `omp // begin declare variant` (which use implicit attributes). - Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData = + std::optional<std::pair<FunctionDecl *, Expr *>> DeclVarData = S.checkOpenMPDeclareVariantFunction(S.ConvertDeclToDeclGroup(New), E, TI, Attr.appendArgs_size(), Attr.getRange()); @@ -469,8 +470,8 @@ static void instantiateOMPDeclareVariantAttr( if (!DeclVarData) return; - E = DeclVarData.value().second; - FD = DeclVarData.value().first; + E = DeclVarData->second; + FD = DeclVarData->first; if (auto *VariantDRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) { if (auto *VariantFD = dyn_cast<FunctionDecl>(VariantDRE->getDecl())) { @@ -506,7 +507,7 @@ static void instantiateOMPDeclareVariantAttr( SmallVector<Expr *, 8> NothingExprs; SmallVector<Expr *, 8> NeedDevicePtrExprs; - SmallVector<OMPDeclareVariantAttr::InteropType, 8> AppendArgs; + SmallVector<OMPInteropInfo, 4> AppendArgs; for (Expr *E : Attr.adjustArgsNothing()) { ExprResult ER = Subst(E); @@ -520,7 +521,10 @@ static void instantiateOMPDeclareVariantAttr( continue; NeedDevicePtrExprs.push_back(ER.get()); } - llvm::append_range(AppendArgs, Attr.appendArgs()); + for (OMPInteropInfo &II : Attr.appendArgs()) { + // When prefer_type is implemented for append_args handle them here too. + AppendArgs.emplace_back(II.IsTarget, II.IsTargetSync); + } S.ActOnOpenMPDeclareVariantDirective( FD, E, TI, NothingExprs, NeedDevicePtrExprs, AppendArgs, SourceLocation(), @@ -633,7 +637,7 @@ static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) { FD->getReturnType()->isLValueReferenceType()) { return false; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case Builtin::BImove: case Builtin::BImove_if_noexcept: // HACK: Super-old versions of libc++ (3.1 and earlier) provide @@ -873,6 +877,10 @@ TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { llvm_unreachable("Translation units cannot be instantiated"); } +Decl *TemplateDeclInstantiator::VisitHLSLBufferDecl(HLSLBufferDecl *Decl) { + llvm_unreachable("HLSL buffer declarations cannot be instantiated"); +} + Decl * TemplateDeclInstantiator::VisitPragmaCommentDecl(PragmaCommentDecl *D) { llvm_unreachable("pragma comment cannot be instantiated"); @@ -1172,6 +1180,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, if (Var->isStaticLocal()) SemaRef.CheckStaticLocalForDllExport(Var); + if (Var->getTLSKind()) + SemaRef.CheckThreadLocalForLargeAlignment(Var); + return Var; } @@ -1628,12 +1639,16 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { } if (PrevClassTemplate) { - TemplateParameterList *PrevParams - = PrevClassTemplate->getMostRecentDecl()->getTemplateParameters(); + const ClassTemplateDecl *MostRecentPrevCT = + PrevClassTemplate->getMostRecentDecl(); + TemplateParameterList *PrevParams = + MostRecentPrevCT->getTemplateParameters(); // Make sure the parameter lists match. - if (!SemaRef.TemplateParameterListsAreEqual(InstParams, PrevParams, true, - Sema::TPL_TemplateMatch)) + if (!SemaRef.TemplateParameterListsAreEqual( + D->getTemplatedDecl(), InstParams, + MostRecentPrevCT->getTemplatedDecl(), PrevParams, true, + Sema::TPL_TemplateMatch)) return nullptr; // Do some additional validation, then merge default arguments @@ -1823,6 +1838,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // merged with the local instantiation scope for the function template // itself. LocalInstantiationScope Scope(SemaRef); + Sema::ConstraintEvalRAII<TemplateDeclInstantiator> RAII(*this); TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); @@ -1991,7 +2007,7 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context, /// Normal class members are of more specific types and therefore /// don't make it here. This function serves three purposes: /// 1) instantiating function templates -/// 2) substituting friend declarations +/// 2) substituting friend and local function declarations /// 3) substituting deduction guide declarations for nested class templates Decl *TemplateDeclInstantiator::VisitFunctionDecl( FunctionDecl *D, TemplateParameterList *TemplateParams, @@ -2062,19 +2078,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( return nullptr; } - // FIXME: Concepts: Do not substitute into constraint expressions Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); - if (TrailingRequiresClause) { - EnterExpressionEvaluationContext ConstantEvaluated( - SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); - ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, - TemplateArgs); - if (SubstRC.isInvalid()) - return nullptr; - TrailingRequiresClause = SubstRC.get(); - if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause)) - return nullptr; - } // If we're instantiating a local function declaration, put the result // in the enclosing namespace; otherwise we need to find the instantiated @@ -2114,6 +2118,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( D->getCanonicalDecl()->getStorageClass(), D->UsesFPIntrin(), D->isInlineSpecified(), D->hasWrittenPrototype(), D->getConstexprKind(), TrailingRequiresClause); + Function->setFriendConstraintRefersToEnclosingTemplate( + D->FriendConstraintRefersToEnclosingTemplate()); Function->setRangeEnd(D->getSourceRange().getEnd()); } @@ -2131,6 +2137,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( assert(D->getDeclContext()->isFileContext()); LexicalDC = D->getDeclContext(); } + else if (D->isLocalExternDecl()) { + LexicalDC = SemaRef.CurContext; + } Function->setLexicalDeclContext(LexicalDC); @@ -2260,7 +2269,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the - // tag type. Note that this does does not apply if we're declaring a + // tag type. Note that this does not apply if we're declaring a // typedef (C++ [dcl.typedef]p4). if (Previous.isSingleTagDecl()) Previous.clear(); @@ -2268,9 +2277,42 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // Filter out previous declarations that don't match the scope. The only // effect this has is to remove declarations found in inline namespaces // for friend declarations with unqualified names. - SemaRef.FilterLookupForScope(Previous, DC, /*Scope*/ nullptr, - /*ConsiderLinkage*/ true, - QualifierLoc.hasQualifier()); + if (isFriend && !QualifierLoc && !FunctionTemplate) { + SemaRef.FilterLookupForScope(Previous, DC, /*Scope=*/ nullptr, + /*ConsiderLinkage=*/ true, + QualifierLoc.hasQualifier()); + } + } + + // Per [temp.inst], default arguments in function declarations at local scope + // are instantiated along with the enclosing declaration. For example: + // + // template<typename T> + // void ft() { + // void f(int = []{ return T::value; }()); + // } + // template void ft<int>(); // error: type 'int' cannot be used prior + // to '::' because it has no members + // + // The error is issued during instantiation of ft<int>() because substitution + // into the default argument fails; the default argument is instantiated even + // though it is never used. + if (Function->isLocalExternDecl()) { + for (ParmVarDecl *PVD : Function->parameters()) { + if (!PVD->hasDefaultArg()) + continue; + if (SemaRef.SubstDefaultArgument(D->getInnerLocStart(), PVD, TemplateArgs)) { + // If substitution fails, the default argument is set to a + // RecoveryExpr that wraps the uninstantiated default argument so + // that downstream diagnostics are omitted. + Expr *UninstExpr = PVD->getUninstantiatedDefaultArg(); + ExprResult ErrorResult = SemaRef.CreateRecoveryExpr( + UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), + { UninstExpr }, UninstExpr->getType()); + if (ErrorResult.isUsable()) + PVD->setDefaultArg(ErrorResult.get()); + } + } } SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous, @@ -2331,7 +2373,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( CXXMethodDecl *D, TemplateParameterList *TemplateParams, - Optional<const ASTTemplateArgumentListInfo *> ClassScopeSpecializationArgs, + std::optional<const ASTTemplateArgumentListInfo *> + ClassScopeSpecializationArgs, RewriteKind FunctionRewriteKind) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { @@ -2425,23 +2468,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( return nullptr; } - // FIXME: Concepts: Do not substitute into constraint expressions - Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); - if (TrailingRequiresClause) { - EnterExpressionEvaluationContext ConstantEvaluated( - SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); - auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner); - Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, - D->getMethodQualifiers(), ThisContext); - ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, - TemplateArgs); - if (SubstRC.isInvalid()) - return nullptr; - TrailingRequiresClause = SubstRC.get(); - if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause)) - return nullptr; - } - DeclContext *DC = Owner; if (isFriend) { if (QualifierLoc) { @@ -2459,6 +2485,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( if (!DC) return nullptr; } + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); + Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); + DeclarationNameInfo NameInfo = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); @@ -2466,7 +2495,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo); // Build the instantiated method declaration. - CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); CXXMethodDecl *Method = nullptr; SourceLocation StartLoc = D->getInnerLocStart(); @@ -2478,6 +2506,9 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( Constructor->getConstexprKind(), InheritedConstructor(), TrailingRequiresClause); Method->setRangeEnd(Constructor->getEndLoc()); + if (Constructor->isDefaultConstructor() || + Constructor->isCopyOrMoveConstructor()) + Method->setIneligibleOrNotSelected(true); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -2500,6 +2531,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, SC, D->UsesFPIntrin(), D->isInlineSpecified(), D->getConstexprKind(), D->getEndLoc(), TrailingRequiresClause); + if (D->isMoveAssignmentOperator() || D->isCopyAssignmentOperator()) + Method->setIneligibleOrNotSelected(true); } if (D->isInlined()) @@ -2551,7 +2584,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( if (NumTempParamLists) Method->setTemplateParameterListsInfo( SemaRef.Context, - llvm::makeArrayRef(TempParamLists.data(), NumTempParamLists)); + llvm::ArrayRef(TempParamLists.data(), NumTempParamLists)); Method->setLexicalDeclContext(Owner); Method->setObjectOfFriendDecl(); @@ -2630,12 +2663,45 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the - // tag type. Note that this does does not apply if we're declaring a + // tag type. Note that this does not apply if we're declaring a // typedef (C++ [dcl.typedef]p4). if (Previous.isSingleTagDecl()) Previous.clear(); } + // Per [temp.inst], default arguments in member functions of local classes + // are instantiated along with the member function declaration. For example: + // + // template<typename T> + // void ft() { + // struct lc { + // int operator()(int p = []{ return T::value; }()); + // }; + // } + // template void ft<int>(); // error: type 'int' cannot be used prior + // to '::'because it has no members + // + // The error is issued during instantiation of ft<int>()::lc::operator() + // because substitution into the default argument fails; the default argument + // is instantiated even though it is never used. + if (D->isInLocalScopeForInstantiation()) { + for (unsigned P = 0; P < Params.size(); ++P) { + if (!Params[P]->hasDefaultArg()) + continue; + if (SemaRef.SubstDefaultArgument(StartLoc, Params[P], TemplateArgs)) { + // If substitution fails, the default argument is set to a + // RecoveryExpr that wraps the uninstantiated default argument so + // that downstream diagnostics are omitted. + Expr *UninstExpr = Params[P]->getUninstantiatedDefaultArg(); + ExprResult ErrorResult = SemaRef.CreateRecoveryExpr( + UninstExpr->getBeginLoc(), UninstExpr->getEndLoc(), + { UninstExpr }, UninstExpr->getType()); + if (ErrorResult.isUsable()) + Params[P]->setDefaultArg(ErrorResult.get()); + } + } + } + SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, IsExplicitSpecialization, Method->isThisDeclarationADefinition()); @@ -2723,15 +2789,16 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { } Decl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { - return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0, None, - /*ExpectParameterPack=*/ false); + return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0, + std::nullopt, + /*ExpectParameterPack=*/false); } Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( TemplateTypeParmDecl *D) { assert(D->getTypeForDecl()->isTemplateTypeParmType()); - Optional<unsigned> NumExpanded; + std::optional<unsigned> NumExpanded; if (const TypeConstraint *TC = D->getTypeConstraint()) { if (D->isPackExpansion() && !D->isExpandedParameterPack()) { @@ -2771,13 +2838,11 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( Inst->setImplicit(D->isImplicit()); if (auto *TC = D->getTypeConstraint()) { if (!D->isImplicit()) { - // Invented template parameter type constraints will be instantiated with - // the corresponding auto-typed parameter as it might reference other - // parameters. - - // TODO: Concepts: do not instantiate the constraint (delayed constraint - // substitution) - if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs)) + // Invented template parameter type constraints will be instantiated + // with the corresponding auto-typed parameter as it might reference + // other parameters. + if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs, + EvaluateConstraints)) return nullptr; } } @@ -2844,9 +2909,9 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( // be expanded. bool Expand = true; bool RetainExpansion = false; - Optional<unsigned> OrigNumExpansions - = Expansion.getTypePtr()->getNumExpansions(); - Optional<unsigned> NumExpansions = OrigNumExpansions; + std::optional<unsigned> OrigNumExpansions = + Expansion.getTypePtr()->getNumExpansions(); + std::optional<unsigned> NumExpansions = OrigNumExpansions; if (SemaRef.CheckParameterPacksForExpansion(Expansion.getEllipsisLoc(), Pattern.getSourceRange(), Unexpanded, @@ -3009,7 +3074,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( // be expanded. bool Expand = true; bool RetainExpansion = false; - Optional<unsigned> NumExpansions; + std::optional<unsigned> NumExpansions; if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(), TempParams->getSourceRange(), Unexpanded, @@ -3235,9 +3300,11 @@ Decl *TemplateDeclInstantiator::VisitUsingEnumDecl(UsingEnumDecl *D) { if (SemaRef.RequireCompleteEnumDecl(EnumD, EnumD->getLocation())) return nullptr; + TypeSourceInfo *TSI = SemaRef.SubstType(D->getEnumType(), TemplateArgs, + D->getLocation(), D->getDeclName()); UsingEnumDecl *NewUD = UsingEnumDecl::Create(SemaRef.Context, Owner, D->getUsingLoc(), - D->getEnumLoc(), D->getLocation(), EnumD); + D->getEnumLoc(), D->getLocation(), TSI); SemaRef.Context.setInstantiatedFromUsingEnumDecl(NewUD, D); NewUD->setAccess(D->getAccess()); @@ -3278,7 +3345,7 @@ Decl *TemplateDeclInstantiator::instantiateUnresolvedUsingDecl( // be expanded. bool Expand = true; bool RetainExpansion = false; - Optional<unsigned> NumExpansions; + std::optional<unsigned> NumExpansions; if (SemaRef.CheckParameterPacksForExpansion( D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs, Expand, RetainExpansion, NumExpansions)) @@ -3617,9 +3684,10 @@ TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) { OMPVarListLocTy Locs(OldC->getBeginLoc(), OldC->getLParenLoc(), OldC->getEndLoc()); OMPClause *NewC = SemaRef.ActOnOpenMPMapClause( - OldC->getMapTypeModifiers(), OldC->getMapTypeModifiersLoc(), SS, - NewNameInfo, OldC->getMapType(), OldC->isImplicitMapType(), - OldC->getMapLoc(), OldC->getColonLoc(), NewVars, Locs); + OldC->getIteratorModifier(), OldC->getMapTypeModifiers(), + OldC->getMapTypeModifiersLoc(), SS, NewNameInfo, OldC->getMapType(), + OldC->isImplicitMapType(), OldC->getMapLoc(), OldC->getColonLoc(), + NewVars, Locs); Clauses.push_back(NewC); } SemaRef.EndOpenMPDSABlock(nullptr); @@ -3691,12 +3759,10 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // Check that the template argument list is well-formed for this // class template. - SmallVector<TemplateArgument, 4> Converted; - if (SemaRef.CheckTemplateArgumentList(InstClassTemplate, - D->getLocation(), - InstTemplateArgs, - false, - Converted, + SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; + if (SemaRef.CheckTemplateArgumentList(InstClassTemplate, D->getLocation(), + InstTemplateArgs, false, + SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return nullptr; @@ -3704,7 +3770,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // in the member template's set of class template explicit specializations. void *InsertPos = nullptr; ClassTemplateSpecializationDecl *PrevDecl = - InstClassTemplate->findSpecialization(Converted, InsertPos); + InstClassTemplate->findSpecialization(CanonicalConverted, InsertPos); // Check whether we've already seen a conflicting instantiation of this // declaration (for instance, if there was a prior implicit instantiation). @@ -3742,7 +3808,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *InstD = ClassTemplateSpecializationDecl::Create( SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(), - D->getLocation(), InstClassTemplate, Converted, PrevDecl); + D->getLocation(), InstClassTemplate, CanonicalConverted, PrevDecl); // Add this partial specialization to the set of class template partial // specializations. @@ -3756,7 +3822,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // Build the canonical type that describes the converted template // arguments of the class template explicit specialization. QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(InstClassTemplate), Converted, + TemplateName(InstClassTemplate), CanonicalConverted, SemaRef.Context.getRecordType(InstD)); // Build the fully-sugared type for this class template @@ -3818,16 +3884,17 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( } // Check that the template argument list is well-formed for this template. - SmallVector<TemplateArgument, 4> Converted; + SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(), - VarTemplateArgsInfo, false, Converted, + VarTemplateArgsInfo, false, + SugaredConverted, CanonicalConverted, /*UpdateArgsWithConversions=*/true)) return nullptr; // Check whether we've already seen a declaration of this specialization. void *InsertPos = nullptr; VarTemplateSpecializationDecl *PrevDecl = - InstVarTemplate->findSpecialization(Converted, InsertPos); + InstVarTemplate->findSpecialization(CanonicalConverted, InsertPos); // Check whether we've already seen a conflicting instantiation of this // declaration (for instance, if there was a prior implicit instantiation). @@ -3839,7 +3906,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( return nullptr; return VisitVarTemplateSpecializationDecl( - InstVarTemplate, D, VarTemplateArgsInfo, Converted, PrevDecl); + InstVarTemplate, D, VarTemplateArgsInfo, CanonicalConverted, PrevDecl); } Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( @@ -3904,6 +3971,11 @@ Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) { llvm_unreachable("Concept definitions cannot reside inside a template"); } +Decl *TemplateDeclInstantiator::VisitImplicitConceptSpecializationDecl( + ImplicitConceptSpecializationDecl *D) { + llvm_unreachable("Concept specializations cannot reside inside a template"); +} + Decl * TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(), @@ -3975,7 +4047,7 @@ FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD, Decl *R; if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) { R = Instantiator.VisitCXXMethodDecl( - MD, nullptr, None, + MD, nullptr, std::nullopt, TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual); } else { assert(Spaceship->getFriendObjectKind() && @@ -4021,18 +4093,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { if (Invalid) return nullptr; - // FIXME: Concepts: Substitution into requires clause should only happen when - // checking satisfaction. - Expr *InstRequiresClause = nullptr; - if (Expr *E = L->getRequiresClause()) { - EnterExpressionEvaluationContext ConstantEvaluated( - SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); - ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs); - if (Res.isInvalid() || !Res.isUsable()) { - return nullptr; - } - InstRequiresClause = Res.get(); - } + Expr *InstRequiresClause = L->getRequiresClause(); TemplateParameterList *InstL = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(), @@ -4043,8 +4104,10 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { TemplateParameterList * Sema::SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner, - const MultiLevelTemplateArgumentList &TemplateArgs) { + const MultiLevelTemplateArgumentList &TemplateArgs, + bool EvaluateConstraints) { TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); + Instantiator.setEvaluateConstraints(EvaluateConstraints); return Instantiator.SubstTemplateParams(Params); } @@ -4087,32 +4150,29 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // Check that the template argument list is well-formed for this // class template. - SmallVector<TemplateArgument, 4> Converted; - if (SemaRef.CheckTemplateArgumentList(ClassTemplate, - PartialSpec->getLocation(), - InstTemplateArgs, - false, - Converted)) + SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; + if (SemaRef.CheckTemplateArgumentList( + ClassTemplate, PartialSpec->getLocation(), InstTemplateArgs, + /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) return nullptr; // Check these arguments are valid for a template partial specialization. if (SemaRef.CheckTemplatePartialSpecializationArgs( PartialSpec->getLocation(), ClassTemplate, InstTemplateArgs.size(), - Converted)) + CanonicalConverted)) return nullptr; // Figure out where to insert this class template partial specialization // in the member template's set of class template partial specializations. void *InsertPos = nullptr; - ClassTemplateSpecializationDecl *PrevDecl - = ClassTemplate->findPartialSpecialization(Converted, InstParams, + ClassTemplateSpecializationDecl *PrevDecl = + ClassTemplate->findPartialSpecialization(CanonicalConverted, InstParams, InsertPos); // Build the canonical type that describes the converted template // arguments of the class template partial specialization. - QualType CanonType - = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), - Converted); + QualType CanonType = SemaRef.Context.getTemplateSpecializationType( + TemplateName(ClassTemplate), CanonicalConverted); // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization @@ -4157,7 +4217,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( ClassTemplatePartialSpecializationDecl::Create( SemaRef.Context, PartialSpec->getTagKind(), Owner, PartialSpec->getBeginLoc(), PartialSpec->getLocation(), InstParams, - ClassTemplate, Converted, InstTemplateArgs, CanonType, nullptr); + ClassTemplate, CanonicalConverted, InstTemplateArgs, CanonType, + nullptr); // Substitute the nested name specifier, if any. if (SubstQualifier(PartialSpec, InstPartialSpec)) return nullptr; @@ -4214,27 +4275,29 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( // Check that the template argument list is well-formed for this // class template. - SmallVector<TemplateArgument, 4> Converted; - if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(), - InstTemplateArgs, false, Converted)) + SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; + if (SemaRef.CheckTemplateArgumentList( + VarTemplate, PartialSpec->getLocation(), InstTemplateArgs, + /*PartialTemplateArgs=*/false, SugaredConverted, CanonicalConverted)) return nullptr; // Check these arguments are valid for a template partial specialization. if (SemaRef.CheckTemplatePartialSpecializationArgs( PartialSpec->getLocation(), VarTemplate, InstTemplateArgs.size(), - Converted)) + CanonicalConverted)) return nullptr; // Figure out where to insert this variable template partial specialization // in the member template's set of variable template partial specializations. void *InsertPos = nullptr; VarTemplateSpecializationDecl *PrevDecl = - VarTemplate->findPartialSpecialization(Converted, InstParams, InsertPos); + VarTemplate->findPartialSpecialization(CanonicalConverted, InstParams, + InsertPos); // Build the canonical type that describes the converted template // arguments of the variable template partial specialization. QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(VarTemplate), Converted); + TemplateName(VarTemplate), CanonicalConverted); // Build the fully-sugared type for this variable template // specialization as the user wrote in the specialization @@ -4290,7 +4353,8 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( VarTemplatePartialSpecializationDecl::Create( SemaRef.Context, Owner, PartialSpec->getInnerLocStart(), PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(), - DI, PartialSpec->getStorageClass(), Converted, InstTemplateArgs); + DI, PartialSpec->getStorageClass(), CanonicalConverted, + InstTemplateArgs); // Substitute the nested name specifier, if any. if (SubstQualifier(PartialSpec, InstPartialSpec)) @@ -4326,11 +4390,9 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, ThisTypeQuals = Method->getMethodQualifiers(); } - TypeSourceInfo *NewTInfo - = SemaRef.SubstFunctionDeclType(OldTInfo, TemplateArgs, - D->getTypeSpecStartLoc(), - D->getDeclName(), - ThisContext, ThisTypeQuals); + TypeSourceInfo *NewTInfo = SemaRef.SubstFunctionDeclType( + OldTInfo, TemplateArgs, D->getTypeSpecStartLoc(), D->getDeclName(), + ThisContext, ThisTypeQuals, EvaluateConstraints); if (!NewTInfo) return nullptr; @@ -4349,7 +4411,7 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, LocalInstantiationScope *Scope = SemaRef.CurrentInstantiationScope; - Optional<unsigned> NumArgumentsInExpansion; + std::optional<unsigned> NumArgumentsInExpansion; if (OldParam->isParameterPack()) NumArgumentsInExpansion = SemaRef.getNumArgumentsInExpansion(OldParam->getType(), @@ -4451,7 +4513,7 @@ bool Sema::addInstantiatedParametersToScope( // Expand the parameter pack. Scope.MakeInstantiatedLocalArgPack(PatternParam); - Optional<unsigned> NumArgumentsInExpansion = + std::optional<unsigned> NumArgumentsInExpansion = getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs); if (NumArgumentsInExpansion) { QualType PatternType = @@ -4481,10 +4543,6 @@ bool Sema::addInstantiatedParametersToScope( bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param) { assert(Param->hasUninstantiatedDefaultArg()); - Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); - - EnterExpressionEvaluationContext EvalContext( - *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); // Instantiate the expression. // @@ -4503,62 +4561,12 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, // // template<typename T> // A<T> Foo(int a = A<T>::FooImpl()); - MultiLevelTemplateArgumentList TemplateArgs - = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true); + MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs( + FD, /*Final=*/false, nullptr, /*RelativeToPrimary=*/true); - InstantiatingTemplate Inst(*this, CallLoc, Param, - TemplateArgs.getInnermost()); - if (Inst.isInvalid()) + if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true)) return true; - if (Inst.isAlreadyInstantiating()) { - Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; - Param->setInvalidDecl(); - return true; - } - ExprResult Result; - { - // C++ [dcl.fct.default]p5: - // The names in the [default argument] expression are bound, and - // the semantic constraints are checked, at the point where the - // default argument expression appears. - ContextRAII SavedContext(*this, FD); - LocalInstantiationScope Local(*this); - - FunctionDecl *Pattern = FD->getTemplateInstantiationPattern( - /*ForDefinition*/ false); - if (addInstantiatedParametersToScope(FD, Pattern, Local, TemplateArgs)) - return true; - - runWithSufficientStackSpace(CallLoc, [&] { - Result = SubstInitializer(UninstExpr, TemplateArgs, - /*DirectInit*/false); - }); - } - if (Result.isInvalid()) - return true; - - // Check the expression as an initializer for the parameter. - InitializedEntity Entity - = InitializedEntity::InitializeParameter(Context, Param); - InitializationKind Kind = InitializationKind::CreateCopy( - Param->getLocation(), - /*FIXME:EqualLoc*/ UninstExpr->getBeginLoc()); - Expr *ResultE = Result.getAs<Expr>(); - - InitializationSequence InitSeq(*this, Entity, Kind, ResultE); - Result = InitSeq.Perform(*this, Entity, Kind, ResultE); - if (Result.isInvalid()) - return true; - - Result = - ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(), - /*DiscardedValue*/ false); - if (Result.isInvalid()) - return true; - - // Remember the instantiated default argument. - Param->setDefaultArg(Result.getAs<Expr>()); if (ASTMutationListener *L = getASTMutationListener()) L->DefaultArgumentInstantiated(Param); @@ -4592,8 +4600,8 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, Sema::ContextRAII savedContext(*this, Decl); LocalInstantiationScope Scope(*this); - MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); + MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs( + Decl, /*Final=*/false, nullptr, /*RelativeToPrimary*/ true); // FIXME: We can't use getTemplateInstantiationPattern(false) in general // here, because for a non-defining friend declaration in a class template, @@ -4767,7 +4775,8 @@ Sema::InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD, return nullptr; ContextRAII SavedContext(*this, FD); - MultiLevelTemplateArgumentList MArgs(*Args); + MultiLevelTemplateArgumentList MArgs(FTD, Args->asArray(), + /*Final=*/false); return cast_or_null<FunctionDecl>(SubstDecl(FD, FD->getParent(), MArgs)); } @@ -5033,8 +5042,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, RebuildTypeSourceInfoForDefaultSpecialMembers(); SetDeclDefaulted(Function, PatternDecl->getLocation()); } else { - MultiLevelTemplateArgumentList TemplateArgs = - getTemplateInstantiationArgs(Function, nullptr, false, PatternDecl); + MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs( + Function, /*Final=*/false, nullptr, false, PatternDecl); // Substitute into the qualifier; we can get a substitution failure here // through evil use of alias templates. @@ -5103,8 +5112,7 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( const TemplateArgumentList &TemplateArgList, const TemplateArgumentListInfo &TemplateArgsInfo, SmallVectorImpl<TemplateArgument> &Converted, - SourceLocation PointOfInstantiation, - LateInstantiatedAttrVec *LateAttrs, + SourceLocation PointOfInstantiation, LateInstantiatedAttrVec *LateAttrs, LocalInstantiationScope *StartingScope) { if (FromVar->isInvalidDecl()) return nullptr; @@ -5113,9 +5121,6 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( if (Inst.isInvalid()) return nullptr; - MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgList); - // Instantiate the first declaration of the variable template: for a partial // specialization of a static data member template, the first declaration may // or may not be the declaration in the class; if it's in the class, we want @@ -5126,15 +5131,21 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( // partial specialization, don't do this. The member specialization completely // replaces the original declaration in this case. bool IsMemberSpec = false; - if (VarTemplatePartialSpecializationDecl *PartialSpec = - dyn_cast<VarTemplatePartialSpecializationDecl>(FromVar)) + MultiLevelTemplateArgumentList MultiLevelList; + if (auto *PartialSpec = + dyn_cast<VarTemplatePartialSpecializationDecl>(FromVar)) { IsMemberSpec = PartialSpec->isMemberSpecialization(); - else if (VarTemplateDecl *FromTemplate = FromVar->getDescribedVarTemplate()) - IsMemberSpec = FromTemplate->isMemberSpecialization(); + MultiLevelList.addOuterTemplateArguments( + PartialSpec, TemplateArgList.asArray(), /*Final=*/false); + } else { + assert(VarTemplate == FromVar->getDescribedVarTemplate()); + IsMemberSpec = VarTemplate->isMemberSpecialization(); + MultiLevelList.addOuterTemplateArguments( + VarTemplate, TemplateArgList.asArray(), /*Final=*/false); + } if (!IsMemberSpec) FromVar = FromVar->getFirstDecl(); - MultiLevelTemplateArgumentList MultiLevelList(TemplateArgList); TemplateDeclInstantiator Instantiator(*this, FromVar->getDeclContext(), MultiLevelList); @@ -5633,7 +5644,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, collectUnexpandedParameterPacks(Init->getInit(), Unexpanded); bool ShouldExpand = false; bool RetainExpansion = false; - Optional<unsigned> NumExpansions; + std::optional<unsigned> NumExpansions; if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(), BaseTL.getSourceRange(), Unexpanded, @@ -6147,7 +6158,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // Move to the outer template scope. if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) { - if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){ + if (FD->getFriendObjectKind() && + FD->getNonTransparentDeclContext()->isFileContext()) { DC = FD->getLexicalDeclContext(); continue; } @@ -6388,7 +6400,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs) { - for (auto DD : Pattern->ddiags()) { + for (auto *DD : Pattern->ddiags()) { switch (DD->getKind()) { case DependentDiagnostic::Access: HandleDependentAccessCheck(*DD, TemplateArgs); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 790792f77b24..01a435668d88 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -18,6 +18,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" +#include <optional> using namespace clang; @@ -88,6 +89,23 @@ namespace { return true; } + bool + VisitSubstTemplateTypeParmPackTypeLoc(SubstTemplateTypeParmPackTypeLoc TL) { + Unexpanded.push_back({TL.getTypePtr(), TL.getNameLoc()}); + return true; + } + + bool VisitSubstTemplateTypeParmPackType(SubstTemplateTypeParmPackType *T) { + Unexpanded.push_back({T, SourceLocation()}); + return true; + } + + bool + VisitSubstNonTypeTemplateParmPackExpr(SubstNonTypeTemplateParmPackExpr *E) { + Unexpanded.push_back({E, E->getParameterPackLocation()}); + return true; + } + /// Record occurrences of function and non-type template /// parameter packs in an expression. bool VisitDeclRefExpr(DeclRefExpr *E) { @@ -306,7 +324,8 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack); return TTPD && TTPD->getTypeForDecl() == TTPT; } - return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack); + return declaresSameEntity(Pack.first.get<const NamedDecl *>(), + LocalPack); }; if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack)) LambdaParamPackReferences.push_back(Pack); @@ -358,7 +377,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) Name = TTP->getIdentifier(); else - Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier(); + Name = Unexpanded[I].first.get<const NamedDecl *>()->getIdentifier(); if (Name && NamesKnown.insert(Name).second) Names.push_back(Name); @@ -421,7 +440,7 @@ bool Sema::DiagnoseUnexpandedParameterPackInRequiresExpr(RequiresExpr *RE) { llvm::SmallPtrSet<NamedDecl*, 8> ParmSet(Parms.begin(), Parms.end()); SmallVector<UnexpandedParameterPack, 2> UnexpandedParms; for (auto Parm : Unexpanded) - if (ParmSet.contains(Parm.first.dyn_cast<NamedDecl*>())) + if (ParmSet.contains(Parm.first.dyn_cast<const NamedDecl *>())) UnexpandedParms.push_back(Parm); if (UnexpandedParms.empty()) return false; @@ -594,7 +613,8 @@ TypeResult Sema::ActOnPackExpansion(ParsedType Type, if (!TSInfo) return true; - TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc, None); + TypeSourceInfo *TSResult = + CheckPackExpansion(TSInfo, EllipsisLoc, std::nullopt); if (!TSResult) return true; @@ -603,7 +623,7 @@ TypeResult Sema::ActOnPackExpansion(ParsedType Type, TypeSourceInfo * Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc, - Optional<unsigned> NumExpansions) { + std::optional<unsigned> NumExpansions) { // Create the pack expansion type and source-location information. QualType Result = CheckPackExpansion(Pattern->getType(), Pattern->getTypeLoc().getSourceRange(), @@ -621,7 +641,7 @@ Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc, QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, - Optional<unsigned> NumExpansions) { + std::optional<unsigned> NumExpansions) { // C++11 [temp.variadic]p5: // The pattern of a pack expansion shall name one or more // parameter packs that are not expanded by a nested pack @@ -641,11 +661,11 @@ QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange, } ExprResult Sema::ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc) { - return CheckPackExpansion(Pattern, EllipsisLoc, None); + return CheckPackExpansion(Pattern, EllipsisLoc, std::nullopt); } ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, - Optional<unsigned> NumExpansions) { + std::optional<unsigned> NumExpansions) { if (!Pattern) return ExprError(); @@ -669,112 +689,98 @@ bool Sema::CheckParameterPacksForExpansion( SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand, - bool &RetainExpansion, Optional<unsigned> &NumExpansions) { + bool &RetainExpansion, std::optional<unsigned> &NumExpansions) { ShouldExpand = true; RetainExpansion = false; - std::pair<IdentifierInfo *, SourceLocation> FirstPack; - bool HaveFirstPack = false; - Optional<unsigned> NumPartialExpansions; - SourceLocation PartiallySubstitutedPackLoc; + std::pair<const IdentifierInfo *, SourceLocation> FirstPack; + std::optional<std::pair<unsigned, SourceLocation>> PartialExpansion; + std::optional<unsigned> CurNumExpansions; - for (UnexpandedParameterPack ParmPack : Unexpanded) { + for (auto [P, Loc] : Unexpanded) { // Compute the depth and index for this parameter pack. - unsigned Depth = 0, Index = 0; - IdentifierInfo *Name; - bool IsVarDeclPack = false; - - if (const TemplateTypeParmType *TTP = - ParmPack.first.dyn_cast<const TemplateTypeParmType *>()) { - Depth = TTP->getDepth(); - Index = TTP->getIndex(); - Name = TTP->getIdentifier(); - } else { - NamedDecl *ND = ParmPack.first.get<NamedDecl *>(); - if (isa<VarDecl>(ND)) - IsVarDeclPack = true; - else - std::tie(Depth, Index) = getDepthAndIndex(ND); - - Name = ND->getIdentifier(); - } - - // Determine the size of this argument pack. + std::optional<std::pair<unsigned, unsigned>> Pos; unsigned NewPackSize; - if (IsVarDeclPack) { - // Figure out whether we're instantiating to an argument pack or not. - typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; - - llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation = - CurrentInstantiationScope->findInstantiationOf( - ParmPack.first.get<NamedDecl *>()); - if (Instantiation->is<DeclArgumentPack *>()) { - // We could expand this function parameter pack. - NewPackSize = Instantiation->get<DeclArgumentPack *>()->size(); - } else { + const auto *ND = P.dyn_cast<const NamedDecl *>(); + if (ND && isa<VarDecl>(ND)) { + const auto *DAP = + CurrentInstantiationScope->findInstantiationOf(ND) + ->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>(); + if (!DAP) { // We can't expand this function parameter pack, so we can't expand // the pack expansion. ShouldExpand = false; continue; } + NewPackSize = DAP->size(); + } else if (ND) { + Pos = getDepthAndIndex(ND); + } else if (const auto *TTP = P.dyn_cast<const TemplateTypeParmType *>()) { + Pos = {TTP->getDepth(), TTP->getIndex()}; + ND = TTP->getDecl(); + // FIXME: We either should have some fallback for canonical TTP, or + // never have canonical TTP here. + } else if (const auto *STP = + P.dyn_cast<const SubstTemplateTypeParmPackType *>()) { + NewPackSize = STP->getNumArgs(); + ND = STP->getReplacedParameter(); } else { + const auto *SEP = P.get<const SubstNonTypeTemplateParmPackExpr *>(); + NewPackSize = SEP->getArgumentPack().pack_size(); + ND = SEP->getParameterPack(); + } + + if (Pos) { // If we don't have a template argument at this depth/index, then we // cannot expand the pack expansion. Make a note of this, but we still // want to check any parameter packs we *do* have arguments for. - if (Depth >= TemplateArgs.getNumLevels() || - !TemplateArgs.hasTemplateArgument(Depth, Index)) { + if (Pos->first >= TemplateArgs.getNumLevels() || + !TemplateArgs.hasTemplateArgument(Pos->first, Pos->second)) { ShouldExpand = false; continue; } - // Determine the size of the argument pack. - NewPackSize = TemplateArgs(Depth, Index).pack_size(); - } - - // C++0x [temp.arg.explicit]p9: - // Template argument deduction can extend the sequence of template - // arguments corresponding to a template parameter pack, even when the - // sequence contains explicitly specified template arguments. - if (!IsVarDeclPack && CurrentInstantiationScope) { - if (NamedDecl *PartialPack - = CurrentInstantiationScope->getPartiallySubstitutedPack()){ - unsigned PartialDepth, PartialIndex; - std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack); - if (PartialDepth == Depth && PartialIndex == Index) { + NewPackSize = TemplateArgs(Pos->first, Pos->second).pack_size(); + // C++0x [temp.arg.explicit]p9: + // Template argument deduction can extend the sequence of template + // arguments corresponding to a template parameter pack, even when the + // sequence contains explicitly specified template arguments. + if (CurrentInstantiationScope) + if (const NamedDecl *PartialPack = + CurrentInstantiationScope->getPartiallySubstitutedPack(); + PartialPack && getDepthAndIndex(PartialPack) == *Pos) { RetainExpansion = true; // We don't actually know the new pack size yet. - NumPartialExpansions = NewPackSize; - PartiallySubstitutedPackLoc = ParmPack.second; + PartialExpansion = {NewPackSize, Loc}; continue; } - } } - if (!NumExpansions) { + // FIXME: Workaround for Canonical TTP. + const IdentifierInfo *Name = ND ? ND->getIdentifier() : nullptr; + if (!CurNumExpansions) { // The is the first pack we've seen for which we have an argument. // Record it. - NumExpansions = NewPackSize; - FirstPack.first = Name; - FirstPack.second = ParmPack.second; - HaveFirstPack = true; - continue; - } - - if (NewPackSize != *NumExpansions) { + CurNumExpansions = NewPackSize; + FirstPack = {Name, Loc}; + } else if (NewPackSize != *CurNumExpansions) { // C++0x [temp.variadic]p5: // All of the parameter packs expanded by a pack expansion shall have // the same number of arguments specified. - if (HaveFirstPack) - Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) - << FirstPack.first << Name << *NumExpansions << NewPackSize - << SourceRange(FirstPack.second) << SourceRange(ParmPack.second); - else - Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) - << Name << *NumExpansions << NewPackSize - << SourceRange(ParmPack.second); + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) + << FirstPack.first << Name << *CurNumExpansions << NewPackSize + << SourceRange(FirstPack.second) << SourceRange(Loc); return true; } } + if (NumExpansions && CurNumExpansions && + *NumExpansions != *CurNumExpansions) { + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_multilevel) + << FirstPack.first << *CurNumExpansions << *NumExpansions + << SourceRange(FirstPack.second); + return true; + } + // If we're performing a partial expansion but we also have a full expansion, // expand to the number of common arguments. For example, given: // @@ -784,70 +790,72 @@ bool Sema::CheckParameterPacksForExpansion( // // ... a call to 'A<int, int>().f<int>' should expand the pack once and // retain an expansion. - if (NumPartialExpansions) { - if (NumExpansions && *NumExpansions < *NumPartialExpansions) { + if (PartialExpansion) { + if (CurNumExpansions && *CurNumExpansions < PartialExpansion->first) { NamedDecl *PartialPack = CurrentInstantiationScope->getPartiallySubstitutedPack(); Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial) - << PartialPack << *NumPartialExpansions << *NumExpansions - << SourceRange(PartiallySubstitutedPackLoc); + << PartialPack << PartialExpansion->first << *CurNumExpansions + << SourceRange(PartialExpansion->second); return true; } - - NumExpansions = NumPartialExpansions; + NumExpansions = PartialExpansion->first; + } else { + NumExpansions = CurNumExpansions; } return false; } -Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T, - const MultiLevelTemplateArgumentList &TemplateArgs) { +std::optional<unsigned> Sema::getNumArgumentsInExpansion( + QualType T, const MultiLevelTemplateArgumentList &TemplateArgs) { QualType Pattern = cast<PackExpansionType>(T)->getPattern(); SmallVector<UnexpandedParameterPack, 2> Unexpanded; CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(Pattern); - Optional<unsigned> Result; - for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { - // Compute the depth and index for this parameter pack. - unsigned Depth; - unsigned Index; + std::optional<unsigned> Result; + auto setResultSz = [&Result](unsigned Size) { + assert((!Result || *Result == Size) && "inconsistent pack sizes"); + Result = Size; + }; + auto setResultPos = [&](const std::pair<unsigned, unsigned> &Pos) -> bool { + unsigned Depth = Pos.first, Index = Pos.second; + if (Depth >= TemplateArgs.getNumLevels() || + !TemplateArgs.hasTemplateArgument(Depth, Index)) + // The pattern refers to an unknown template argument. We're not ready to + // expand this pack yet. + return true; + // Determine the size of the argument pack. + setResultSz(TemplateArgs(Depth, Index).pack_size()); + return false; + }; - if (const TemplateTypeParmType *TTP - = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { - Depth = TTP->getDepth(); - Index = TTP->getIndex(); + for (auto [I, _] : Unexpanded) { + if (const auto *TTP = I.dyn_cast<const TemplateTypeParmType *>()) { + if (setResultPos({TTP->getDepth(), TTP->getIndex()})) + return std::nullopt; + } else if (const auto *STP = + I.dyn_cast<const SubstTemplateTypeParmPackType *>()) { + setResultSz(STP->getNumArgs()); + } else if (const auto *SEP = + I.dyn_cast<const SubstNonTypeTemplateParmPackExpr *>()) { + setResultSz(SEP->getArgumentPack().pack_size()); } else { - NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); + const auto *ND = I.get<const NamedDecl *>(); + // Function parameter pack or init-capture pack. if (isa<VarDecl>(ND)) { - // Function parameter pack or init-capture pack. - typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; - - llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation - = CurrentInstantiationScope->findInstantiationOf( - Unexpanded[I].first.get<NamedDecl *>()); - if (Instantiation->is<Decl*>()) + const auto *DAP = + CurrentInstantiationScope->findInstantiationOf(ND) + ->dyn_cast<LocalInstantiationScope::DeclArgumentPack *>(); + if (!DAP) // The pattern refers to an unexpanded pack. We're not ready to expand // this pack yet. - return None; - - unsigned Size = Instantiation->get<DeclArgumentPack *>()->size(); - assert((!Result || *Result == Size) && "inconsistent pack sizes"); - Result = Size; - continue; + return std::nullopt; + setResultSz(DAP->size()); + } else if (setResultPos(getDepthAndIndex(ND))) { + return std::nullopt; } - - std::tie(Depth, Index) = getDepthAndIndex(ND); } - if (Depth >= TemplateArgs.getNumLevels() || - !TemplateArgs.hasTemplateArgument(Depth, Index)) - // The pattern refers to an unknown template argument. We're not ready to - // expand this pack yet. - return None; - - // Determine the size of the argument pack. - unsigned Size = TemplateArgs(Depth, Index).pack_size(); - assert((!Result || *Result == Size) && "inconsistent pack sizes"); - Result = Size; } return Result; @@ -857,8 +865,10 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { const DeclSpec &DS = D.getDeclSpec(); switch (DS.getTypeSpecType()) { case TST_typename: + case TST_typeof_unqualType: case TST_typeofType: - case TST_underlyingType: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case TST_##Trait: +#include "clang/Basic/TransformTypeTraits.def" case TST_atomic: { QualType T = DS.getRepAsType().get(); if (!T.isNull() && T->containsUnexpandedParameterPack()) @@ -866,6 +876,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { break; } + case TST_typeof_unqualExpr: case TST_typeofExpr: case TST_decltype: case TST_bitint: @@ -1049,10 +1060,9 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S, RParenLoc); } -TemplateArgumentLoc -Sema::getTemplateArgumentPackExpansionPattern( - TemplateArgumentLoc OrigLoc, - SourceLocation &Ellipsis, Optional<unsigned> &NumExpansions) const { +TemplateArgumentLoc Sema::getTemplateArgumentPackExpansionPattern( + TemplateArgumentLoc OrigLoc, SourceLocation &Ellipsis, + std::optional<unsigned> &NumExpansions) const { const TemplateArgument &Argument = OrigLoc.getArgument(); assert(Argument.isPackExpansion()); switch (Argument.getKind()) { @@ -1109,7 +1119,7 @@ Sema::getTemplateArgumentPackExpansionPattern( llvm_unreachable("Invalid TemplateArgument Kind!"); } -Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) { +std::optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) { assert(Arg.containsUnexpandedParameterPack()); // If this is a substituted pack, grab that pack. If not, we don't know @@ -1123,7 +1133,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) { if (auto *Subst = Arg.getAsType()->getAs<SubstTemplateTypeParmPackType>()) Pack = Subst->getArgumentPack(); else - return None; + return std::nullopt; break; case TemplateArgument::Expression: @@ -1133,10 +1143,10 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) { else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) { for (VarDecl *PD : *Subst) if (PD->isParameterPack()) - return None; + return std::nullopt; return Subst->getNumExpansions(); } else - return None; + return std::nullopt; break; case TemplateArgument::Template: @@ -1144,7 +1154,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) { Arg.getAsTemplate().getAsSubstTemplateTemplateParmPack()) Pack = Subst->getArgumentPack(); else - return None; + return std::nullopt; break; case TemplateArgument::Declaration: @@ -1153,7 +1163,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) { case TemplateArgument::Integral: case TemplateArgument::Pack: case TemplateArgument::Null: - return None; + return std::nullopt; } // Check that no argument in the pack is itself a pack expansion. @@ -1161,7 +1171,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) { // There's no point recursing in this case; we would have already // expanded this pack expansion into the enclosing pack if we could. if (Elem.isPackExpansion()) - return None; + return std::nullopt; } return Pack.pack_size(); } @@ -1242,7 +1252,7 @@ ExprResult Sema::ActOnCXXFoldExpr(Scope *S, SourceLocation LParenLoc, Expr *LHS, } return BuildCXXFoldExpr(ULE, LParenLoc, LHS, Opc, EllipsisLoc, RHS, RParenLoc, - None); + std::nullopt); } ExprResult Sema::BuildCXXFoldExpr(UnresolvedLookupExpr *Callee, @@ -1250,7 +1260,7 @@ ExprResult Sema::BuildCXXFoldExpr(UnresolvedLookupExpr *Callee, BinaryOperatorKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc, - Optional<unsigned> NumExpansions) { + std::optional<unsigned> NumExpansions) { return new (Context) CXXFoldExpr(Context.DependentTy, Callee, LParenLoc, LHS, Operator, EllipsisLoc, RHS, RParenLoc, NumExpansions); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 3ab5d26a9a75..89d819a77dcb 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -19,9 +19,11 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -33,12 +35,13 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/Support/ErrorHandling.h" #include <bitset> +#include <optional> using namespace clang; @@ -430,7 +433,7 @@ static DeclaratorChunk *maybeMovePastReturnType(Declarator &declarator, if (onlyBlockPointers) continue; - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorChunk::BlockPointer: result = &ptrChunk; @@ -759,7 +762,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, - /*DeclsInPrototype=*/None, loc, loc, declarator)); + /*DeclsInPrototype=*/std::nullopt, loc, loc, declarator)); // For consistency, make sure the state still has us as processing // the decl spec. @@ -827,8 +830,8 @@ static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator, /// Apply Objective-C type arguments to the given type. static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, ArrayRef<TypeSourceInfo *> typeArgs, - SourceRange typeArgsRange, - bool failOnError = false) { + SourceRange typeArgsRange, bool failOnError, + bool rebuilding) { // We can only apply type arguments to an Objective-C class type. const auto *objcObjectType = type->getAs<ObjCObjectType>(); if (!objcObjectType || !objcObjectType->getInterface()) { @@ -892,7 +895,9 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, } } - if (!diagnosed) { + // When rebuilding, qualifiers might have gotten here through a + // final substitution. + if (!rebuilding && !diagnosed) { S.Diag(qual.getBeginLoc(), diag::err_objc_type_arg_qualified) << typeArg << typeArg.getQualifiers().getAsString() << FixItHint::CreateRemoval(rangeToRemove); @@ -1054,22 +1059,18 @@ QualType Sema::BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl, return Result; } -QualType Sema::BuildObjCObjectType(QualType BaseType, - SourceLocation Loc, - SourceLocation TypeArgsLAngleLoc, - ArrayRef<TypeSourceInfo *> TypeArgs, - SourceLocation TypeArgsRAngleLoc, - SourceLocation ProtocolLAngleLoc, - ArrayRef<ObjCProtocolDecl *> Protocols, - ArrayRef<SourceLocation> ProtocolLocs, - SourceLocation ProtocolRAngleLoc, - bool FailOnError) { +QualType Sema::BuildObjCObjectType( + QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, + ArrayRef<TypeSourceInfo *> TypeArgs, SourceLocation TypeArgsRAngleLoc, + SourceLocation ProtocolLAngleLoc, ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, SourceLocation ProtocolRAngleLoc, + bool FailOnError, bool Rebuilding) { QualType Result = BaseType; if (!TypeArgs.empty()) { - Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs, - SourceRange(TypeArgsLAngleLoc, - TypeArgsRAngleLoc), - FailOnError); + Result = + applyObjCTypeArgs(*this, Loc, Result, TypeArgs, + SourceRange(TypeArgsLAngleLoc, TypeArgsRAngleLoc), + FailOnError, Rebuilding); if (FailOnError && Result.isNull()) return QualType(); } @@ -1097,11 +1098,10 @@ TypeResult Sema::actOnObjCProtocolQualifierType( SourceLocation rAngleLoc) { // Form id<protocol-list>. QualType Result = Context.getObjCObjectType( - Context.ObjCBuiltinIdTy, { }, - llvm::makeArrayRef( - (ObjCProtocolDecl * const *)protocols.data(), - protocols.size()), - false); + Context.ObjCBuiltinIdTy, {}, + llvm::ArrayRef((ObjCProtocolDecl *const *)protocols.data(), + protocols.size()), + false); Result = Context.getObjCObjectPointerType(Result); TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result); @@ -1168,10 +1168,11 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( T, BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(), TypeArgsLAngleLoc, ActualTypeArgInfos, TypeArgsRAngleLoc, ProtocolLAngleLoc, - llvm::makeArrayRef((ObjCProtocolDecl * const *)Protocols.data(), - Protocols.size()), + llvm::ArrayRef((ObjCProtocolDecl *const *)Protocols.data(), + Protocols.size()), ProtocolLocs, ProtocolRAngleLoc, - /*FailOnError=*/false); + /*FailOnError=*/false, + /*Rebuilding=*/false); if (Result == T) return BaseType; @@ -1247,6 +1248,18 @@ getImageAccess(const ParsedAttributesView &Attrs) { return OpenCLAccessAttr::Keyword_read_only; } +static UnaryTransformType::UTTKind +TSTToUnaryTransformType(DeclSpec::TST SwitchTST) { + switch (SwitchTST) { +#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \ + case TST_##Trait: \ + return UnaryTransformType::Enum; +#include "clang/Basic/TransformTypeTraits.def" + default: + llvm_unreachable("attempted to parse a non-unary transform builtin"); + } +} + /// Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -1369,7 +1382,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } } - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclSpec::TST_int: { if (DS.getTypeSpecSign() != TypeSpecifierSign::Unsigned) { switch (DS.getTypeSpecWidth()) { @@ -1575,6 +1588,9 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // TypeQuals handled by caller. Result = Context.getTypeDeclType(D); + if (const auto *Using = + dyn_cast_or_null<UsingShadowDecl>(DS.getRepAsFoundDecl())) + Result = Context.getUsingType(Using, Result); // In both C and C++, make an ElaboratedType. ElaboratedTypeKeyword Keyword @@ -1596,6 +1612,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // TypeQuals handled by caller. break; } + case DeclSpec::TST_typeof_unqualType: case DeclSpec::TST_typeofType: // FIXME: Preserve type source info. Result = S.GetTypeFromParser(DS.getRepAsType()); @@ -1604,13 +1621,20 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { if (const TagType *TT = Result->getAs<TagType>()) S.DiagnoseUseOfDecl(TT->getDecl(), DS.getTypeSpecTypeLoc()); // TypeQuals handled by caller. - Result = Context.getTypeOfType(Result); + Result = Context.getTypeOfType( + Result, DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualType + ? TypeOfKind::Unqualified + : TypeOfKind::Qualified); break; + case DeclSpec::TST_typeof_unqualExpr: case DeclSpec::TST_typeofExpr: { Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. - Result = S.BuildTypeofExprType(E); + Result = S.BuildTypeofExprType(E, DS.getTypeSpecType() == + DeclSpec::TST_typeof_unqualExpr + ? TypeOfKind::Unqualified + : TypeOfKind::Qualified); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -1628,12 +1652,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; } - case DeclSpec::TST_underlyingType: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case DeclSpec::TST_##Trait: +#include "clang/Basic/TransformTypeTraits.def" Result = S.GetTypeFromParser(DS.getRepAsType()); - assert(!Result.isNull() && "Didn't get a type for __underlying_type?"); - Result = S.BuildUnaryTransformType(Result, - UnaryTransformType::EnumUnderlyingType, - DS.getTypeSpecTypeLoc()); + assert(!Result.isNull() && "Didn't get a type for the transformation?"); + Result = S.BuildUnaryTransformType( + Result, TSTToUnaryTransformType(DS.getTypeSpecType()), + DS.getTypeSpecTypeLoc()); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -2158,7 +2183,7 @@ QualType Sema::BuildPointerType(QualType T, return QualType(); } - if (getLangOpts().HLSL) { + if (getLangOpts().HLSL && Loc.isValid()) { Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0; return QualType(); } @@ -2228,7 +2253,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return QualType(); } - if (getLangOpts().HLSL) { + if (getLangOpts().HLSL && Loc.isValid()) { Diag(Loc, diag::err_hlsl_pointers_unsupported) << 1; return QualType(); } @@ -2379,6 +2404,23 @@ static ExprResult checkArraySize(Sema &S, Expr *&ArraySize, return R; } +bool Sema::checkArrayElementAlignment(QualType EltTy, SourceLocation Loc) { + EltTy = Context.getBaseElementType(EltTy); + if (EltTy->isIncompleteType() || EltTy->isDependentType() || + EltTy->isUndeducedType()) + return true; + + CharUnits Size = Context.getTypeSizeInChars(EltTy); + CharUnits Alignment = Context.getTypeAlignInChars(EltTy); + + if (Size.isMultipleOf(Alignment)) + return true; + + Diag(Loc, diag::err_array_element_alignment) + << EltTy << Size.getQuantity() << Alignment.getQuantity(); + return false; +} + /// Build an array type. /// /// \param T The type of each element in the array. @@ -2462,6 +2504,9 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, return QualType(); } + if (!checkArrayElementAlignment(T, Loc)) + return QualType(); + // Do placeholder conversions on the array size expression. if (ArraySize && ArraySize->hasPlaceholderType()) { ExprResult Result = CheckPlaceholderExpr(ArraySize); @@ -2584,12 +2629,10 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, if (T->isVariableArrayType() && !Context.getTargetInfo().isVLASupported()) { // CUDA device code and some other targets don't support VLAs. - targetDiag(Loc, (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) - ? diag::err_cuda_vla - : diag::err_vla_unsupported) - << ((getLangOpts().CUDA && getLangOpts().CUDAIsDevice) - ? CurrentCUDATarget() - : CFT_InvalidTarget); + bool IsCUDADevice = (getLangOpts().CUDA && getLangOpts().CUDAIsDevice); + targetDiag(Loc, + IsCUDADevice ? diag::err_cuda_vla : diag::err_vla_unsupported) + << (IsCUDADevice ? CurrentCUDATarget() : 0); } // If this is not C99, diagnose array size modifiers on non-VLAs. @@ -2621,17 +2664,28 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, // can't already be a vector. if ((!CurType->isDependentType() && (!CurType->isBuiltinType() || CurType->isBooleanType() || - (!CurType->isIntegerType() && !CurType->isRealFloatingType()))) || + (!CurType->isIntegerType() && !CurType->isRealFloatingType())) && + !CurType->isBitIntType()) || CurType->isArrayType()) { Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << CurType; return QualType(); } + // Only support _BitInt elements with byte-sized power of 2 NumBits. + if (CurType->isBitIntType()) { + unsigned NumBits = CurType->getAs<BitIntType>()->getNumBits(); + if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) { + Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type) + << (NumBits < 8); + return QualType(); + } + } if (SizeExpr->isTypeDependent() || SizeExpr->isValueDependent()) return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc, VectorType::GenericVector); - Optional<llvm::APSInt> VecSize = SizeExpr->getIntegerConstantExpr(Context); + std::optional<llvm::APSInt> VecSize = + SizeExpr->getIntegerConstantExpr(Context); if (!VecSize) { Diag(AttrLoc, diag::err_attribute_argument_type) << "vector_size" << AANT_ArgumentIntegerConstant @@ -2697,8 +2751,19 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return QualType(); } + // Only support _BitInt elements with byte-sized power of 2 NumBits. + if (T->isBitIntType()) { + unsigned NumBits = T->getAs<BitIntType>()->getNumBits(); + if (!llvm::isPowerOf2_32(NumBits) || NumBits < 8) { + Diag(AttrLoc, diag::err_attribute_invalid_bitint_vector_type) + << (NumBits < 8); + return QualType(); + } + } + if (!ArraySize->isTypeDependent() && !ArraySize->isValueDependent()) { - Optional<llvm::APSInt> vecSize = ArraySize->getIntegerConstantExpr(Context); + std::optional<llvm::APSInt> vecSize = + ArraySize->getIntegerConstantExpr(Context); if (!vecSize) { Diag(AttrLoc, diag::err_attribute_argument_type) << "ext_vector_type" << AANT_ArgumentIntegerConstant @@ -2744,8 +2809,9 @@ QualType Sema::BuildMatrixType(QualType ElementTy, Expr *NumRows, Expr *NumCols, return Context.getDependentSizedMatrixType(ElementTy, NumRows, NumCols, AttrLoc); - Optional<llvm::APSInt> ValueRows = NumRows->getIntegerConstantExpr(Context); - Optional<llvm::APSInt> ValueColumns = + std::optional<llvm::APSInt> ValueRows = + NumRows->getIntegerConstantExpr(Context); + std::optional<llvm::APSInt> ValueColumns = NumCols->getIntegerConstantExpr(Context); auto const RowRange = NumRows->getSourceRange(); @@ -2810,7 +2876,8 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { } // Functions cannot return half FP. - if (T->isHalfType() && !getLangOpts().HalfArgsAndReturns) { + if (T->isHalfType() && !getLangOpts().NativeHalfArgsAndReturns && + !Context.getTargetInfo().allowHalfArgsAndReturns()) { Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 1 << FixItHint::CreateInsertion(Loc, "*"); return true; @@ -2834,6 +2901,8 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { if (T.isVolatileQualified() && getLangOpts().CPlusPlus20) Diag(Loc, diag::warn_deprecated_volatile_return) << T; + if (T.getAddressSpace() != LangAS::Default && getLangOpts().HLSL) + return true; return false; } @@ -2916,7 +2985,8 @@ QualType Sema::BuildFunctionType(QualType T, if (ParamType->isVoidType()) { Diag(Loc, diag::err_param_with_void_type); Invalid = true; - } else if (ParamType->isHalfType() && !getLangOpts().HalfArgsAndReturns) { + } else if (ParamType->isHalfType() && !getLangOpts().NativeHalfArgsAndReturns && + !Context.getTargetInfo().allowHalfArgsAndReturns()) { // Disallow half FP arguments. Diag(Loc, diag::err_parameters_retval_cannot_have_fp16_type) << 0 << FixItHint::CreateInsertion(Loc, "*"); @@ -2992,7 +3062,7 @@ QualType Sema::BuildMemberPointerType(QualType T, QualType Class, return QualType(); } - if (getLangOpts().HLSL) { + if (getLangOpts().HLSL && Loc.isValid()) { Diag(Loc, diag::err_hlsl_pointers_unsupported) << 0; return QualType(); } @@ -3540,7 +3610,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, !D.getNumTypeObjects() && D.getDeclSpec().getParsedSpecifiers() == DeclSpec::PQ_TypeSpecifier) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorContext::TemplateTypeArg: Error = 10; // Template type argument break; @@ -3565,7 +3635,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, if (SemaRef.getLangOpts().CPlusPlus2b && IsCXXAutoType && !Auto->isDecltypeAuto()) break; // auto(x) - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorContext::TypeName: case DeclaratorContext::Association: Error = 15; // Generic @@ -3834,7 +3904,7 @@ static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) { case DeclaratorChunk::Paren: if (&C == &Paren) continue; - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorChunk::Pointer: StartsWithDeclaratorId = false; continue; @@ -4604,7 +4674,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } // Determine whether we should infer _Nonnull on pointer types. - Optional<NullabilityKind> inferNullability; + std::optional<NullabilityKind> inferNullability; bool inferNullabilityCS = false; bool inferNullabilityInnerOnly = false; bool inferNullabilityInnerOnlyComplete = false; @@ -4637,8 +4707,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // inner pointers. complainAboutMissingNullability = CAMN_InnerPointers; - if (T->canHaveNullability(/*ResultIfUnknown*/false) && - !T->getNullability(S.Context)) { + if (T->canHaveNullability(/*ResultIfUnknown*/ false) && + !T->getNullability()) { // Note that we allow but don't require nullability on dependent types. ++NumPointersRemaining; } @@ -4674,7 +4744,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::TrailingReturn: case DeclaratorContext::TrailingReturnVar: isFunctionOrMethod = true; - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorContext::Member: if (state.getDeclarator().isObjCIvar() && !isFunctionOrMethod) { @@ -4683,12 +4753,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } // Weak properties are inferred to be nullable. - if (state.getDeclarator().isObjCWeakProperty() && inAssumeNonNullRegion) { - inferNullability = NullabilityKind::Nullable; + if (state.getDeclarator().isObjCWeakProperty()) { + // Weak properties cannot be nonnull, and should not complain about + // missing nullable attributes during completeness checks. + complainAboutMissingNullability = CAMN_No; + if (inAssumeNonNullRegion) { + inferNullability = NullabilityKind::Nullable; + } break; } - LLVM_FALLTHROUGH; + [[fallthrough]]; case DeclaratorContext::File: case DeclaratorContext::KNRTypeList: { @@ -4843,7 +4918,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case CAMN_InnerPointers: if (NumPointersRemaining == 0) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; case CAMN_Yes: checkNullabilityConsistency(S, pointerKind, pointerLoc, pointerEndLoc); @@ -4854,8 +4929,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // If the type itself could have nullability but does not, infer pointer // nullability and perform consistency checking. if (S.CodeSynthesisContexts.empty()) { - if (T->canHaveNullability(/*ResultIfUnknown*/false) && - !T->getNullability(S.Context)) { + if (T->canHaveNullability(/*ResultIfUnknown*/ false) && + !T->getNullability()) { if (isVaList(T)) { // Record that we've seen a pointer, but do nothing else. if (NumPointersRemaining > 0) @@ -4878,9 +4953,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } - if (complainAboutMissingNullability == CAMN_Yes && - T->isArrayType() && !T->getNullability(S.Context) && !isVaList(T) && - D.isPrototypeContext() && + if (complainAboutMissingNullability == CAMN_Yes && T->isArrayType() && + !T->getNullability() && !isVaList(T) && D.isPrototypeContext() && !hasOuterPointerLikeChunk(D, D.getNumTypeObjects())) { checkNullabilityConsistency(S, SimplePointerKind::Array, D.getDeclSpec().getTypeSpecTypeLoc()); @@ -5152,7 +5226,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, << T << 0 /*pointer hint*/; D.setInvalidType(true); } - } else if (!S.getLangOpts().HalfArgsAndReturns) { + } else if (!S.getLangOpts().NativeHalfArgsAndReturns && + !S.Context.getTargetInfo().allowHalfArgsAndReturns()) { S.Diag(D.getIdentifierLoc(), diag::err_parameters_retval_cannot_have_fp16_type) << 1; D.setInvalidType(true); @@ -5301,14 +5376,19 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } else { // We allow a zero-parameter variadic function in C if the // function is marked with the "overloadable" attribute. Scan - // for this attribute now. - if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) - if (!D.getDeclarationAttributes().hasAttribute( - ParsedAttr::AT_Overloadable) && - !D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) && - !D.getDeclSpec().getAttributes().hasAttribute( - ParsedAttr::AT_Overloadable)) + // for this attribute now. We also allow it in C2x per WG14 N2975. + if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) { + if (LangOpts.C2x) + S.Diag(FTI.getEllipsisLoc(), + diag::warn_c17_compat_ellipsis_only_parameter); + else if (!D.getDeclarationAttributes().hasAttribute( + ParsedAttr::AT_Overloadable) && + !D.getAttributes().hasAttribute( + ParsedAttr::AT_Overloadable) && + !D.getDeclSpec().getAttributes().hasAttribute( + ParsedAttr::AT_Overloadable)) S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_param); + } if (FTI.NumParams && FTI.Params[0].Param == nullptr) { // C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function @@ -5384,16 +5464,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, D.setInvalidType(); Param->setInvalidDecl(); } - } else if (!S.getLangOpts().HalfArgsAndReturns) { + } else if (!S.getLangOpts().NativeHalfArgsAndReturns && + !S.Context.getTargetInfo().allowHalfArgsAndReturns()) { S.Diag(Param->getLocation(), diag::err_parameters_retval_cannot_have_fp16_type) << 0; D.setInvalidType(); } } else if (!FTI.hasPrototype) { - if (ParamTy->isPromotableIntegerType()) { + if (Context.isPromotableIntegerType(ParamTy)) { ParamTy = Context.getPromotedIntegerType(ParamTy); Param->setKNRPromoted(true); - } else if (const BuiltinType* BTy = ParamTy->getAs<BuiltinType>()) { + } else if (const BuiltinType *BTy = ParamTy->getAs<BuiltinType>()) { if (BTy->getKind() == BuiltinType::Float) { ParamTy = Context.DoubleTy; Param->setKNRPromoted(true); @@ -5538,7 +5619,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // in ClsType; hence we wrap ClsType into an ElaboratedType. // NOTE: in particular, no wrap occurs if ClsType already is an // Elaborated, DependentName, or DependentTemplateSpecialization. - if (NNSPrefix && isa<TemplateSpecializationType>(NNS->getAsType())) + if (isa<TemplateSpecializationType>(NNS->getAsType())) ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType); break; } @@ -5775,7 +5856,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, << T << D.getSourceRange(); D.setEllipsisLoc(SourceLocation()); } else { - T = Context.getPackExpansionType(T, None, /*ExpectPackInType=*/false); + T = Context.getPackExpansionType(T, std::nullopt, + /*ExpectPackInType=*/false); } break; case DeclaratorContext::TemplateParam: @@ -5788,7 +5870,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // parameter packs in the type of the non-type template parameter, then // it expands those parameter packs. if (T->containsUnexpandedParameterPack()) - T = Context.getPackExpansionType(T, None); + T = Context.getPackExpansionType(T, std::nullopt); else S.Diag(D.getEllipsisLoc(), LangOpts.CPlusPlus11 @@ -5974,6 +6056,21 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL, TL.setAttr(State.takeAttrForAttributedType(TL.getTypePtr())); } +static void fillMatrixTypeLoc(MatrixTypeLoc MTL, + const ParsedAttributesView &Attrs) { + for (const ParsedAttr &AL : Attrs) { + if (AL.getKind() == ParsedAttr::AT_MatrixType) { + MTL.setAttrNameLoc(AL.getLoc()); + MTL.setAttrRowOperand(AL.getArgAsExpr(0)); + MTL.setAttrColumnOperand(AL.getArgAsExpr(1)); + MTL.setAttrOperandParensRange(SourceRange()); + return; + } + } + + llvm_unreachable("no matrix_type attribute found at the expected location!"); +} + namespace { class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> { Sema &SemaRef; @@ -6048,18 +6145,20 @@ namespace { } void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { - assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr); + assert(DS.getTypeSpecType() == DeclSpec::TST_typeofExpr || + DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualExpr); TL.setTypeofLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); } void VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { - assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType); + assert(DS.getTypeSpecType() == DeclSpec::TST_typeofType || + DS.getTypeSpecType() == DeclSpec::TST_typeof_unqualType); TL.setTypeofLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); assert(DS.getRepAsType()); TypeSourceInfo *TInfo = nullptr; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); - TL.setUnderlyingTInfo(TInfo); + TL.setUnmodifiedTInfo(TInfo); } void VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { assert(DS.getTypeSpecType() == DeclSpec::TST_decltype); @@ -6067,8 +6166,7 @@ namespace { TL.setRParenLoc(DS.getTypeofParensRange().getEnd()); } void VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { - // FIXME: This holds only because we only have one unary transform. - assert(DS.getTypeSpecType() == DeclSpec::TST_underlyingType); + assert(DS.isTransformTypeTrait(DS.getTypeSpecType())); TL.setKWLoc(DS.getTypeSpecTypeLoc()); TL.setParensRange(DS.getTypeofParensRange()); assert(DS.getRepAsType()); @@ -6090,19 +6188,19 @@ namespace { } } void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { - ElaboratedTypeKeyword Keyword - = TypeWithKeyword::getKeywordForTypeSpec(DS.getTypeSpecType()); if (DS.getTypeSpecType() == TST_typename) { TypeSourceInfo *TInfo = nullptr; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); - if (TInfo) { - TL.copy(TInfo->getTypeLoc().castAs<ElaboratedTypeLoc>()); - return; - } + if (TInfo) + if (auto ETL = TInfo->getTypeLoc().getAs<ElaboratedTypeLoc>()) { + TL.copy(ETL); + return; + } } - TL.setElaboratedKeywordLoc(Keyword != ETK_None - ? DS.getTypeSpecTypeLoc() - : SourceLocation()); + const ElaboratedType *T = TL.getTypePtr(); + TL.setElaboratedKeywordLoc(T->getKeyword() != ETK_None + ? DS.getTypeSpecTypeLoc() + : SourceLocation()); const CXXScopeSpec& SS = DS.getTypeSpecScope(); TL.setQualifierLoc(SS.getWithLocInContext(Context)); Visit(TL.getNextTypeLoc().getUnqualifiedLoc()); @@ -6158,6 +6256,9 @@ namespace { void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } + void VisitUsingTypeLoc(UsingTypeLoc TL) { + TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); + } void VisitAtomicTypeLoc(AtomicTypeLoc TL) { // An AtomicTypeLoc can come from either an _Atomic(...) type specifier // or an _Atomic qualifier. @@ -6339,6 +6440,9 @@ namespace { VisitDependentSizedExtVectorTypeLoc(DependentSizedExtVectorTypeLoc TL) { TL.setNameLoc(Chunk.Loc); } + void VisitMatrixTypeLoc(MatrixTypeLoc TL) { + fillMatrixTypeLoc(TL, Chunk.getAttrs()); + } void VisitTypeLoc(TypeLoc TL) { llvm_unreachable("unsupported TypeLoc kind in declarator!"); @@ -6386,21 +6490,6 @@ fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL, "no address_space attribute found at the expected location!"); } -static void fillMatrixTypeLoc(MatrixTypeLoc MTL, - const ParsedAttributesView &Attrs) { - for (const ParsedAttr &AL : Attrs) { - if (AL.getKind() == ParsedAttr::AT_MatrixType) { - MTL.setAttrNameLoc(AL.getLoc()); - MTL.setAttrRowOperand(AL.getArgAsExpr(0)); - MTL.setAttrColumnOperand(AL.getArgAsExpr(1)); - MTL.setAttrOperandParensRange(SourceRange()); - return; - } - } - - llvm_unreachable("no matrix_type attribute found at the expected location!"); -} - /// Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. @@ -6432,29 +6521,42 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, CurrTL = ATL.getValueLoc().getUnqualifiedLoc(); } - while (MacroQualifiedTypeLoc TL = CurrTL.getAs<MacroQualifiedTypeLoc>()) { - TL.setExpansionLoc( - State.getExpansionLocForMacroQualifiedType(TL.getTypePtr())); - CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); - } + bool HasDesugaredTypeLoc = true; + while (HasDesugaredTypeLoc) { + switch (CurrTL.getTypeLocClass()) { + case TypeLoc::MacroQualified: { + auto TL = CurrTL.castAs<MacroQualifiedTypeLoc>(); + TL.setExpansionLoc( + State.getExpansionLocForMacroQualifiedType(TL.getTypePtr())); + CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); + break; + } - while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) { - fillAttributedTypeLoc(TL, State); - CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); - } + case TypeLoc::Attributed: { + auto TL = CurrTL.castAs<AttributedTypeLoc>(); + fillAttributedTypeLoc(TL, State); + CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); + break; + } - while (DependentAddressSpaceTypeLoc TL = - CurrTL.getAs<DependentAddressSpaceTypeLoc>()) { - fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs()); - CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc(); - } + case TypeLoc::Adjusted: + case TypeLoc::BTFTagAttributed: { + CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); + break; + } - if (MatrixTypeLoc TL = CurrTL.getAs<MatrixTypeLoc>()) - fillMatrixTypeLoc(TL, D.getTypeObject(i).getAttrs()); + case TypeLoc::DependentAddressSpace: { + auto TL = CurrTL.castAs<DependentAddressSpaceTypeLoc>(); + fillDependentAddressSpaceTypeLoc(TL, D.getTypeObject(i).getAttrs()); + CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc(); + break; + } - // FIXME: Ordering here? - while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>()) - CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); + default: + HasDesugaredTypeLoc = false; + break; + } + } DeclaratorLocFiller(S.Context, State, D.getTypeObject(i)).Visit(CurrTL); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); @@ -6539,7 +6641,7 @@ static bool BuildAddressSpaceIndex(Sema &S, LangAS &ASIdx, const Expr *AddrSpace, SourceLocation AttrLoc) { if (!AddrSpace->isValueDependent()) { - Optional<llvm::APSInt> OptAddrSpace = + std::optional<llvm::APSInt> OptAddrSpace = AddrSpace->getIntegerConstantExpr(S.Context); if (!OptAddrSpace) { S.Diag(AttrLoc, diag::err_attribute_argument_type) @@ -6707,6 +6809,8 @@ static void HandleAddressSpaceTypeAttribute(QualType &Type, // The keyword-based type attributes imply which address space to use. ASIdx = S.getLangOpts().SYCLIsDevice ? Attr.asSYCLLangAS() : Attr.asOpenCLLangAS(); + if (S.getLangOpts().HLSL) + ASIdx = Attr.asHLSLLangAS(); if (ASIdx == LangAS::Default) llvm_unreachable("Invalid address space"); @@ -7158,17 +7262,25 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, } std::bitset<attr::LastAttr> Attrs; - attr::Kind NewAttrKind = A->getKind(); QualType Desugared = Type; - const AttributedType *AT = dyn_cast<AttributedType>(Type); - while (AT) { + for (;;) { + if (const TypedefType *TT = dyn_cast<TypedefType>(Desugared)) { + Desugared = TT->desugar(); + continue; + } else if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Desugared)) { + Desugared = ET->desugar(); + continue; + } + const AttributedType *AT = dyn_cast<AttributedType>(Desugared); + if (!AT) + break; Attrs[AT->getAttrKind()] = true; Desugared = AT->getModifiedType(); - AT = dyn_cast<AttributedType>(Desugared); } // You cannot specify duplicate type attributes, so if the attribute has // already been applied, flag it. + attr::Kind NewAttrKind = A->getKind(); if (Attrs[NewAttrKind]) { S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr; return true; @@ -7189,14 +7301,11 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, return true; } - // Pointer type qualifiers can only operate on pointer types, but not - // pointer-to-member types. - // - // FIXME: Should we really be disallowing this attribute if there is any - // type sugar between it and the pointer (other than attributes)? Eg, this - // disallows the attribute on a parenthesized pointer. - // And if so, should we really allow *any* type attribute? + // Check the raw (i.e., desugared) Canonical type to see if it + // is a pointer type. if (!isa<PointerType>(Desugared)) { + // Pointer type qualifiers can only operate on pointer types, but not + // pointer-to-member types. if (Type->isMemberPointerType()) S.Diag(PAttr.getLoc(), diag::err_attribute_no_member_pointers) << PAttr; else @@ -7206,7 +7315,8 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, // Add address space to type based on its attributes. LangAS ASIdx = LangAS::Default; - uint64_t PtrWidth = S.Context.getTargetInfo().getPointerWidth(0); + uint64_t PtrWidth = + S.Context.getTargetInfo().getPointerWidth(LangAS::Default); if (PtrWidth == 32) { if (Attrs[attr::Ptr64]) ASIdx = LangAS::ptr64; @@ -7300,7 +7410,7 @@ static bool checkNullabilityTypeSpecifier(TypeProcessingState &state, // This (unlike the code above) looks through typedefs that might // have nullability specifiers on them, which means we cannot // provide a useful Fix-It. - if (auto existingNullability = desugared->getNullability(S.Context)) { + if (auto existingNullability = desugared->getNullability()) { if (nullability != *existingNullability) { S.Diag(nullabilityLoc, diag::err_nullability_conflicting) << DiagNullabilityKind(nullability, isContextSensitive) @@ -7399,7 +7509,7 @@ static bool checkObjCKindOfType(TypeProcessingState &state, QualType &type, // If we started with an object pointer type, rebuild it. if (ptrType) { equivType = S.Context.getObjCObjectPointerType(equivType); - if (auto nullability = type->getNullability(S.Context)) { + if (auto nullability = type->getNullability()) { // We create a nullability attribute from the __kindof attribute. // Make sure that will make sense. assert(attr.getAttributeSpellingListIndex() == 0 && @@ -7714,7 +7824,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, case EST_NoexceptTrue: case EST_NoThrow: // Exception spec doesn't conflict with nothrow, so don't warn. - LLVM_FALLTHROUGH; + [[fallthrough]]; case EST_Unparsed: case EST_Uninstantiated: case EST_DependentNoexcept: @@ -7853,7 +7963,7 @@ void Sema::adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, CallingConv DefaultCC = Context.getDefaultCallingConvention(IsVariadic, IsStatic); - if (CurCC != DefaultCC || DefaultCC == ToCC) + if (CurCC != DefaultCC) return; if (hasExplicitCallingConv(T)) @@ -7960,7 +8070,7 @@ static bool verifyValidIntegerConstantExpr(Sema &S, const ParsedAttr &Attr, llvm::APSInt &Result) { const auto *AttrExpr = Attr.getArgAsExpr(0); if (!AttrExpr->isTypeDependent()) { - if (Optional<llvm::APSInt> Res = + if (std::optional<llvm::APSInt> Res = AttrExpr->getIntegerConstantExpr(S.Context)) { Result = *Res; return true; @@ -8315,6 +8425,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case ParsedAttr::AT_OpenCLLocalAddressSpace: case ParsedAttr::AT_OpenCLConstantAddressSpace: case ParsedAttr::AT_OpenCLGenericAddressSpace: + case ParsedAttr::AT_HLSLGroupSharedAddressSpace: case ParsedAttr::AT_AddressSpace: HandleAddressSpaceTypeAttribute(type, attr, state); attr.setUsedAsTypeAttr(); @@ -8443,7 +8554,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // clang, so revert to attribute-based handling for C. if (!state.getSema().getLangOpts().CPlusPlus) break; - LLVM_FALLTHROUGH; + [[fallthrough]]; FUNCTION_TYPE_ATTRS_CASELIST: attr.setUsedAsTypeAttr(); @@ -9100,29 +9211,23 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, TagDecl *OwnedTagDecl) { if (T.isNull()) return T; - NestedNameSpecifier *NNS; - if (SS.isValid()) - NNS = SS.getScopeRep(); - else { - if (Keyword == ETK_None) - return T; - NNS = nullptr; - } - return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl); + return Context.getElaboratedType( + Keyword, SS.isValid() ? SS.getScopeRep() : nullptr, T, OwnedTagDecl); } -QualType Sema::BuildTypeofExprType(Expr *E) { +QualType Sema::BuildTypeofExprType(Expr *E, TypeOfKind Kind) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (!getLangOpts().CPlusPlus && E->refersToBitField()) - Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) << 2; + Diag(E->getExprLoc(), diag::err_sizeof_alignof_typeof_bitfield) + << (Kind == TypeOfKind::Unqualified ? 3 : 2); if (!E->isTypeDependent()) { QualType T = E->getType(); if (const TagType *TT = T->getAs<TagType>()) DiagnoseUseOfDecl(TT->getDecl(), E->getExprLoc()); } - return Context.getTypeOfExprType(E); + return Context.getTypeOfExprType(E, Kind); } /// getDecltypeForExpr - Given an expr, will return the decltype for @@ -9207,39 +9312,257 @@ QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) { return Context.getDecltypeType(E, getDecltypeForExpr(E)); } -QualType Sema::BuildUnaryTransformType(QualType BaseType, - UnaryTransformType::UTTKind UKind, - SourceLocation Loc) { - switch (UKind) { - case UnaryTransformType::EnumUnderlyingType: - if (!BaseType->isDependentType() && !BaseType->isEnumeralType()) { - Diag(Loc, diag::err_only_enums_have_underlying_types); - return QualType(); - } else { - QualType Underlying = BaseType; - if (!BaseType->isDependentType()) { - // The enum could be incomplete if we're parsing its definition or - // recovering from an error. - NamedDecl *FwdDecl = nullptr; - if (BaseType->isIncompleteType(&FwdDecl)) { - Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType; - Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl; - return QualType(); - } +static QualType GetEnumUnderlyingType(Sema &S, QualType BaseType, + SourceLocation Loc) { + assert(BaseType->isEnumeralType()); + EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl(); + assert(ED && "EnumType has no EnumDecl"); - EnumDecl *ED = BaseType->castAs<EnumType>()->getDecl(); - assert(ED && "EnumType has no EnumDecl"); + S.DiagnoseUseOfDecl(ED, Loc); - DiagnoseUseOfDecl(ED, Loc); + QualType Underlying = ED->getIntegerType(); + assert(!Underlying.isNull()); - Underlying = ED->getIntegerType(); - assert(!Underlying.isNull()); - } - return Context.getUnaryTransformType(BaseType, Underlying, - UnaryTransformType::EnumUnderlyingType); + return Underlying; +} + +QualType Sema::BuiltinEnumUnderlyingType(QualType BaseType, + SourceLocation Loc) { + if (!BaseType->isEnumeralType()) { + Diag(Loc, diag::err_only_enums_have_underlying_types); + return QualType(); + } + + // The enum could be incomplete if we're parsing its definition or + // recovering from an error. + NamedDecl *FwdDecl = nullptr; + if (BaseType->isIncompleteType(&FwdDecl)) { + Diag(Loc, diag::err_underlying_type_of_incomplete_enum) << BaseType; + Diag(FwdDecl->getLocation(), diag::note_forward_declaration) << FwdDecl; + return QualType(); + } + + return GetEnumUnderlyingType(*this, BaseType, Loc); +} + +QualType Sema::BuiltinAddPointer(QualType BaseType, SourceLocation Loc) { + QualType Pointer = BaseType.isReferenceable() || BaseType->isVoidType() + ? BuildPointerType(BaseType.getNonReferenceType(), Loc, + DeclarationName()) + : BaseType; + + return Pointer.isNull() ? QualType() : Pointer; +} + +QualType Sema::BuiltinRemovePointer(QualType BaseType, SourceLocation Loc) { + // We don't want block pointers or ObjectiveC's id type. + if (!BaseType->isAnyPointerType() || BaseType->isObjCIdType()) + return BaseType; + + return BaseType->getPointeeType(); +} + +QualType Sema::BuiltinDecay(QualType BaseType, SourceLocation Loc) { + QualType Underlying = BaseType.getNonReferenceType(); + if (Underlying->isArrayType()) + return Context.getDecayedType(Underlying); + + if (Underlying->isFunctionType()) + return BuiltinAddPointer(BaseType, Loc); + + SplitQualType Split = Underlying.getSplitUnqualifiedType(); + // std::decay is supposed to produce 'std::remove_cv', but since 'restrict' is + // in the same group of qualifiers as 'const' and 'volatile', we're extending + // '__decay(T)' so that it removes all qualifiers. + Split.Quals.removeCVRQualifiers(); + return Context.getQualifiedType(Split); +} + +QualType Sema::BuiltinAddReference(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + assert(LangOpts.CPlusPlus); + QualType Reference = + BaseType.isReferenceable() + ? BuildReferenceType(BaseType, + UKind == UnaryTransformType::AddLvalueReference, + Loc, DeclarationName()) + : BaseType; + return Reference.isNull() ? QualType() : Reference; +} + +QualType Sema::BuiltinRemoveExtent(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + if (UKind == UnaryTransformType::RemoveAllExtents) + return Context.getBaseElementType(BaseType); + + if (const auto *AT = Context.getAsArrayType(BaseType)) + return AT->getElementType(); + + return BaseType; +} + +QualType Sema::BuiltinRemoveReference(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + assert(LangOpts.CPlusPlus); + QualType T = BaseType.getNonReferenceType(); + if (UKind == UTTKind::RemoveCVRef && + (T.isConstQualified() || T.isVolatileQualified())) { + Qualifiers Quals; + QualType Unqual = Context.getUnqualifiedArrayType(T, Quals); + Quals.removeConst(); + Quals.removeVolatile(); + T = Context.getQualifiedType(Unqual, Quals); + } + return T; +} + +QualType Sema::BuiltinChangeCVRQualifiers(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + if ((BaseType->isReferenceType() && UKind != UTTKind::RemoveRestrict) || + BaseType->isFunctionType()) + return BaseType; + + Qualifiers Quals; + QualType Unqual = Context.getUnqualifiedArrayType(BaseType, Quals); + + if (UKind == UTTKind::RemoveConst || UKind == UTTKind::RemoveCV) + Quals.removeConst(); + if (UKind == UTTKind::RemoveVolatile || UKind == UTTKind::RemoveCV) + Quals.removeVolatile(); + if (UKind == UTTKind::RemoveRestrict) + Quals.removeRestrict(); + + return Context.getQualifiedType(Unqual, Quals); +} + +static QualType ChangeIntegralSignedness(Sema &S, QualType BaseType, + bool IsMakeSigned, + SourceLocation Loc) { + if (BaseType->isEnumeralType()) { + QualType Underlying = GetEnumUnderlyingType(S, BaseType, Loc); + if (auto *BitInt = dyn_cast<BitIntType>(Underlying)) { + unsigned int Bits = BitInt->getNumBits(); + if (Bits > 1) + return S.Context.getBitIntType(!IsMakeSigned, Bits); + + S.Diag(Loc, diag::err_make_signed_integral_only) + << IsMakeSigned << /*_BitInt(1)*/ true << BaseType << 1 << Underlying; + return QualType(); + } + if (Underlying->isBooleanType()) { + S.Diag(Loc, diag::err_make_signed_integral_only) + << IsMakeSigned << /*_BitInt(1)*/ false << BaseType << 1 + << Underlying; + return QualType(); } } - llvm_unreachable("unknown unary transform type"); + + bool Int128Unsupported = !S.Context.getTargetInfo().hasInt128Type(); + std::array<CanQualType *, 6> AllSignedIntegers = { + &S.Context.SignedCharTy, &S.Context.ShortTy, &S.Context.IntTy, + &S.Context.LongTy, &S.Context.LongLongTy, &S.Context.Int128Ty}; + ArrayRef<CanQualType *> AvailableSignedIntegers( + AllSignedIntegers.data(), AllSignedIntegers.size() - Int128Unsupported); + std::array<CanQualType *, 6> AllUnsignedIntegers = { + &S.Context.UnsignedCharTy, &S.Context.UnsignedShortTy, + &S.Context.UnsignedIntTy, &S.Context.UnsignedLongTy, + &S.Context.UnsignedLongLongTy, &S.Context.UnsignedInt128Ty}; + ArrayRef<CanQualType *> AvailableUnsignedIntegers(AllUnsignedIntegers.data(), + AllUnsignedIntegers.size() - + Int128Unsupported); + ArrayRef<CanQualType *> *Consider = + IsMakeSigned ? &AvailableSignedIntegers : &AvailableUnsignedIntegers; + + uint64_t BaseSize = S.Context.getTypeSize(BaseType); + auto *Result = + llvm::find_if(*Consider, [&S, BaseSize](const CanQual<Type> *T) { + return BaseSize == S.Context.getTypeSize(T->getTypePtr()); + }); + + assert(Result != Consider->end()); + return QualType((*Result)->getTypePtr(), 0); +} + +QualType Sema::BuiltinChangeSignedness(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + bool IsMakeSigned = UKind == UnaryTransformType::MakeSigned; + if ((!BaseType->isIntegerType() && !BaseType->isEnumeralType()) || + BaseType->isBooleanType() || + (BaseType->isBitIntType() && + BaseType->getAs<BitIntType>()->getNumBits() < 2)) { + Diag(Loc, diag::err_make_signed_integral_only) + << IsMakeSigned << BaseType->isBitIntType() << BaseType << 0; + return QualType(); + } + + bool IsNonIntIntegral = + BaseType->isChar16Type() || BaseType->isChar32Type() || + BaseType->isWideCharType() || BaseType->isEnumeralType(); + + QualType Underlying = + IsNonIntIntegral + ? ChangeIntegralSignedness(*this, BaseType, IsMakeSigned, Loc) + : IsMakeSigned ? Context.getCorrespondingSignedType(BaseType) + : Context.getCorrespondingUnsignedType(BaseType); + if (Underlying.isNull()) + return Underlying; + return Context.getQualifiedType(Underlying, BaseType.getQualifiers()); +} + +QualType Sema::BuildUnaryTransformType(QualType BaseType, UTTKind UKind, + SourceLocation Loc) { + if (BaseType->isDependentType()) + return Context.getUnaryTransformType(BaseType, BaseType, UKind); + QualType Result; + switch (UKind) { + case UnaryTransformType::EnumUnderlyingType: { + Result = BuiltinEnumUnderlyingType(BaseType, Loc); + break; + } + case UnaryTransformType::AddPointer: { + Result = BuiltinAddPointer(BaseType, Loc); + break; + } + case UnaryTransformType::RemovePointer: { + Result = BuiltinRemovePointer(BaseType, Loc); + break; + } + case UnaryTransformType::Decay: { + Result = BuiltinDecay(BaseType, Loc); + break; + } + case UnaryTransformType::AddLvalueReference: + case UnaryTransformType::AddRvalueReference: { + Result = BuiltinAddReference(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::RemoveAllExtents: + case UnaryTransformType::RemoveExtent: { + Result = BuiltinRemoveExtent(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::RemoveCVRef: + case UnaryTransformType::RemoveReference: { + Result = BuiltinRemoveReference(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::RemoveConst: + case UnaryTransformType::RemoveCV: + case UnaryTransformType::RemoveRestrict: + case UnaryTransformType::RemoveVolatile: { + Result = BuiltinChangeCVRQualifiers(BaseType, UKind, Loc); + break; + } + case UnaryTransformType::MakeSigned: + case UnaryTransformType::MakeUnsigned: { + Result = BuiltinChangeSignedness(BaseType, UKind, Loc); + break; + } + } + + return !Result.isNull() + ? Context.getUnaryTransformType(BaseType, Result, UKind) + : Result; } QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index a8589191fc91..6a05ecc5370f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -40,6 +40,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> +#include <optional> using namespace llvm::omp; @@ -279,9 +280,8 @@ public: bool TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, - bool &ShouldExpand, - bool &RetainExpansion, - Optional<unsigned> &NumExpansions) { + bool &ShouldExpand, bool &RetainExpansion, + std::optional<unsigned> &NumExpansions) { ShouldExpand = false; return false; } @@ -636,6 +636,14 @@ public: QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" + QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, + TemplateTypeParmTypeLoc TL, + bool SuppressObjCLifetime); + QualType + TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL, + bool SuppressObjCLifetime); + template<typename Fn> QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, @@ -671,13 +679,49 @@ public: /// The result vectors should be kept in sync; null entries in the /// variables vector are acceptable. /// + /// LastParamTransformed, if non-null, will be set to the index of the last + /// parameter on which transfromation was started. In the event of an error, + /// this will contain the parameter which failed to instantiate. + /// /// Return true on error. bool TransformFunctionTypeParams( SourceLocation Loc, ArrayRef<ParmVarDecl *> Params, const QualType *ParamTypes, const FunctionProtoType::ExtParameterInfo *ParamInfos, SmallVectorImpl<QualType> &PTypes, SmallVectorImpl<ParmVarDecl *> *PVars, - Sema::ExtParameterInfoBuilder &PInfos); + Sema::ExtParameterInfoBuilder &PInfos, unsigned *LastParamTransformed); + + bool TransformFunctionTypeParams( + SourceLocation Loc, ArrayRef<ParmVarDecl *> Params, + const QualType *ParamTypes, + const FunctionProtoType::ExtParameterInfo *ParamInfos, + SmallVectorImpl<QualType> &PTypes, SmallVectorImpl<ParmVarDecl *> *PVars, + Sema::ExtParameterInfoBuilder &PInfos) { + return getDerived().TransformFunctionTypeParams( + Loc, Params, ParamTypes, ParamInfos, PTypes, PVars, PInfos, nullptr); + } + + /// Transforms the parameters of a requires expresison into the given vectors. + /// + /// The result vectors should be kept in sync; null entries in the + /// variables vector are acceptable. + /// + /// Returns an unset ExprResult on success. Returns an ExprResult the 'not + /// satisfied' RequiresExpr if subsitution failed, OR an ExprError, both of + /// which are cases where transformation shouldn't continue. + ExprResult TransformRequiresTypeParams( + SourceLocation KWLoc, SourceLocation RBraceLoc, const RequiresExpr *RE, + RequiresExprBodyDecl *Body, ArrayRef<ParmVarDecl *> Params, + SmallVectorImpl<QualType> &PTypes, + SmallVectorImpl<ParmVarDecl *> &TransParams, + Sema::ExtParameterInfoBuilder &PInfos) { + if (getDerived().TransformFunctionTypeParams( + KWLoc, Params, /*ParamTypes=*/nullptr, + /*ParamInfos=*/nullptr, PTypes, &TransParams, PInfos)) + return ExprError(); + + return ExprResult{}; + } /// Transforms a single function-type parameter. Return null /// on error. @@ -686,7 +730,7 @@ public: /// scope index; can be negative ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, - Optional<unsigned> NumExpansions, + std::optional<unsigned> NumExpansions, bool ExpectParameterPack); /// Transform the body of a lambda-expression. @@ -963,12 +1007,13 @@ public: /// /// By default, performs semantic analysis when building the typeof type. /// Subclasses may override this routine to provide different behavior. - QualType RebuildTypeOfExprType(Expr *Underlying, SourceLocation Loc); + QualType RebuildTypeOfExprType(Expr *Underlying, SourceLocation Loc, + TypeOfKind Kind); /// Build a new typeof(type) type. /// /// By default, builds a new TypeOfType with the given underlying type. - QualType RebuildTypeOfType(QualType Underlying); + QualType RebuildTypeOfType(QualType Underlying, TypeOfKind Kind); /// Build a new unary transform type. QualType RebuildUnaryTransformType(QualType BaseType, @@ -1061,23 +1106,18 @@ public: // If it's still dependent, make a dependent specialization. if (InstName.getAsDependentTemplateName()) - return SemaRef.Context.getDependentTemplateSpecializationType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - Name, - Args); + return SemaRef.Context.getDependentTemplateSpecializationType( + Keyword, QualifierLoc.getNestedNameSpecifier(), Name, + Args.arguments()); // Otherwise, make an elaborated type wrapping a non-dependent // specialization. QualType T = - getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args); - if (T.isNull()) return QualType(); - - if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == nullptr) - return T; - - return SemaRef.Context.getElaboratedType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - T); + getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args); + if (T.isNull()) + return QualType(); + return SemaRef.Context.getElaboratedType( + Keyword, QualifierLoc.getNestedNameSpecifier(), T); } /// Build a new typename type that refers to an identifier. @@ -1182,10 +1222,9 @@ public: /// /// By default, builds a new PackExpansionType type from the given pattern. /// Subclasses may override this routine to provide different behavior. - QualType RebuildPackExpansionType(QualType Pattern, - SourceRange PatternRange, + QualType RebuildPackExpansionType(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, - Optional<unsigned> NumExpansions) { + std::optional<unsigned> NumExpansions) { return getSema().CheckPackExpansion(Pattern, PatternRange, EllipsisLoc, NumExpansions); } @@ -1252,9 +1291,11 @@ public: /// be resolved to a specific template, then builds the appropriate kind of /// template name. Subclasses may override this routine to provide different /// behavior. - TemplateName RebuildTemplateName(TemplateTemplateParmDecl *Param, - const TemplateArgument &ArgPack) { - return getSema().Context.getSubstTemplateTemplateParmPack(Param, ArgPack); + TemplateName RebuildTemplateName(const TemplateArgument &ArgPack, + Decl *AssociatedDecl, unsigned Index, + bool Final) { + return getSema().Context.getSubstTemplateTemplateParmPack( + ArgPack, AssociatedDecl, Index, Final); } /// Build a new compound statement. @@ -1946,15 +1987,16 @@ public: /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPMapClause( - ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, + Expr *IteratorModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, ArrayRef<SourceLocation> MapTypeModifiersLoc, CXXScopeSpec MapperIdScopeSpec, DeclarationNameInfo MapperId, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) { return getSema().ActOnOpenMPMapClause( - MapTypeModifiers, MapTypeModifiersLoc, MapperIdScopeSpec, MapperId, - MapType, IsMapTypeImplicit, MapLoc, ColonLoc, VarList, Locs, + IteratorModifier, MapTypeModifiers, MapTypeModifiersLoc, + MapperIdScopeSpec, MapperId, MapType, IsMapTypeImplicit, MapLoc, + ColonLoc, VarList, Locs, /*NoDiagnose=*/false, UnresolvedMappers); } @@ -2009,22 +2051,26 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPGrainsizeClause(Expr *Grainsize, SourceLocation StartLoc, + OMPClause *RebuildOMPGrainsizeClause(OpenMPGrainsizeClauseModifier Modifier, + Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation EndLoc) { - return getSema().ActOnOpenMPGrainsizeClause(Grainsize, StartLoc, LParenLoc, - EndLoc); + return getSema().ActOnOpenMPGrainsizeClause(Modifier, Device, StartLoc, + LParenLoc, ModifierLoc, EndLoc); } /// Build a new OpenMP 'num_tasks' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc, + OMPClause *RebuildOMPNumTasksClause(OpenMPNumTasksClauseModifier Modifier, + Expr *NumTasks, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation EndLoc) { - return getSema().ActOnOpenMPNumTasksClause(NumTasks, StartLoc, LParenLoc, - EndLoc); + return getSema().ActOnOpenMPNumTasksClause(Modifier, NumTasks, StartLoc, + LParenLoc, ModifierLoc, EndLoc); } /// Build a new OpenMP 'hint' clause. @@ -2207,28 +2253,25 @@ public: /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPOrderClause(OpenMPOrderClauseKind Kind, - SourceLocation KindKwLoc, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { - return getSema().ActOnOpenMPOrderClause(Kind, KindKwLoc, StartLoc, - LParenLoc, EndLoc); + OMPClause *RebuildOMPOrderClause( + OpenMPOrderClauseKind Kind, SourceLocation KindKwLoc, + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, + OpenMPOrderClauseModifier Modifier, SourceLocation ModifierKwLoc) { + return getSema().ActOnOpenMPOrderClause(Modifier, Kind, StartLoc, LParenLoc, + ModifierKwLoc, KindKwLoc, EndLoc); } /// Build a new OpenMP 'init' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPInitClause(Expr *InteropVar, ArrayRef<Expr *> PrefExprs, - bool IsTarget, bool IsTargetSync, + OMPClause *RebuildOMPInitClause(Expr *InteropVar, OMPInteropInfo &InteropInfo, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation VarLoc, SourceLocation EndLoc) { - return getSema().ActOnOpenMPInitClause(InteropVar, PrefExprs, IsTarget, - IsTargetSync, StartLoc, LParenLoc, - VarLoc, EndLoc); + return getSema().ActOnOpenMPInitClause(InteropVar, InteropInfo, StartLoc, + LParenLoc, VarLoc, EndLoc); } /// Build a new OpenMP 'use' clause. @@ -2301,6 +2344,17 @@ public: EndLoc); } + /// Build a new OpenMP 'ompx_dyn_cgroup_mem' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPXDynCGroupMemClause(Expr *Size, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPXDynCGroupMemClause(Size, StartLoc, LParenLoc, + EndLoc); + } + /// Build a new OpenMP 'align' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -2311,6 +2365,41 @@ public: return getSema().ActOnOpenMPAlignClause(A, StartLoc, LParenLoc, EndLoc); } + /// Build a new OpenMP 'at' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPAtClause(OpenMPAtClauseKind Kind, SourceLocation KwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPAtClause(Kind, KwLoc, StartLoc, LParenLoc, + EndLoc); + } + + /// Build a new OpenMP 'severity' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPSeverityClause(OpenMPSeverityClauseKind Kind, + SourceLocation KwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPSeverityClause(Kind, KwLoc, StartLoc, LParenLoc, + EndLoc); + } + + /// Build a new OpenMP 'message' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPMessageClause(Expr *MS, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPMessageClause(MS, StartLoc, LParenLoc, EndLoc); + } + /// Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -2783,20 +2872,18 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildExtVectorElementExpr(Expr *Base, - SourceLocation OpLoc, - SourceLocation AccessorLoc, - IdentifierInfo &Accessor) { + ExprResult RebuildExtVectorElementExpr(Expr *Base, SourceLocation OpLoc, + bool IsArrow, + SourceLocation AccessorLoc, + IdentifierInfo &Accessor) { CXXScopeSpec SS; DeclarationNameInfo NameInfo(&Accessor, AccessorLoc); - return getSema().BuildMemberReferenceExpr(Base, Base->getType(), - OpLoc, /*IsArrow*/ false, - SS, SourceLocation(), - /*FirstQualifierInScope*/ nullptr, - NameInfo, - /* TemplateArgs */ nullptr, - /*S*/ nullptr); + return getSema().BuildMemberReferenceExpr( + Base, Base->getType(), OpLoc, IsArrow, SS, SourceLocation(), + /*FirstQualifierInScope*/ nullptr, NameInfo, + /* TemplateArgs */ nullptr, + /*S*/ nullptr); } /// Build a new initializer list expression. @@ -3134,9 +3221,10 @@ public: /// By default, builds a new default-argument expression, which does not /// require any semantic analysis. Subclasses may override this routine to /// provide different behavior. - ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param) { + ExprResult RebuildCXXDefaultArgExpr(SourceLocation Loc, ParmVarDecl *Param, + Expr *RewrittenExpr) { return CXXDefaultArgExpr::Create(getSema().Context, Loc, Param, - getSema().CurContext); + RewrittenExpr, getSema().CurContext); } /// Build a new C++11 default-initialization expression. @@ -3146,8 +3234,7 @@ public: /// routine to provide different behavior. ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { - return CXXDefaultInitExpr::Create(getSema().Context, Loc, Field, - getSema().CurContext); + return getSema().BuildCXXDefaultInitExpr(Loc, Field); } /// Build a new C++ zero-initialization expression. @@ -3157,25 +3244,23 @@ public: ExprResult RebuildCXXScalarValueInitExpr(TypeSourceInfo *TSInfo, SourceLocation LParenLoc, SourceLocation RParenLoc) { - return getSema().BuildCXXTypeConstructExpr( - TSInfo, LParenLoc, None, RParenLoc, /*ListInitialization=*/false); + return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, std::nullopt, + RParenLoc, + /*ListInitialization=*/false); } /// Build a new C++ "new" expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildCXXNewExpr(SourceLocation StartLoc, - bool UseGlobal, + ExprResult RebuildCXXNewExpr(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, - SourceRange TypeIdParens, - QualType AllocatedType, + SourceRange TypeIdParens, QualType AllocatedType, TypeSourceInfo *AllocatedTypeInfo, - Optional<Expr *> ArraySize, - SourceRange DirectInitRange, - Expr *Initializer) { + std::optional<Expr *> ArraySize, + SourceRange DirectInitRange, Expr *Initializer) { return getSema().BuildCXXNew(StartLoc, UseGlobal, PlacementLParen, PlacementArgs, @@ -3397,11 +3482,10 @@ public: } /// Build a new expression to compute the length of a parameter pack. - ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, - NamedDecl *Pack, + ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack, SourceLocation PackLoc, SourceLocation RParenLoc, - Optional<unsigned> Length, + std::optional<unsigned> Length, ArrayRef<TemplateArgument> PartialArgs) { return SizeOfPackExpr::Create(SemaRef.Context, OperatorLoc, Pack, PackLoc, RParenLoc, Length, PartialArgs); @@ -3479,9 +3563,10 @@ public: } concepts::NestedRequirement * - RebuildNestedRequirement( - concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { - return SemaRef.BuildNestedRequirement(SubstDiag); + RebuildNestedRequirement(StringRef InvalidConstraintEntity, + const ASTConstraintSatisfaction &Satisfaction) { + return SemaRef.BuildNestedRequirement(InvalidConstraintEntity, + Satisfaction); } concepts::NestedRequirement *RebuildNestedRequirement(Expr *Constraint) { @@ -3704,9 +3789,9 @@ public: /// By default, performs semantic analysis to build a new pack expansion /// for a template argument. Subclasses may override this routine to provide /// different behavior. - TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern, - SourceLocation EllipsisLoc, - Optional<unsigned> NumExpansions) { + TemplateArgumentLoc + RebuildPackExpansion(TemplateArgumentLoc Pattern, SourceLocation EllipsisLoc, + std::optional<unsigned> NumExpansions) { switch (Pattern.getArgument().getKind()) { case TemplateArgument::Expression: { ExprResult Result @@ -3753,7 +3838,7 @@ public: /// for an expression. Subclasses may override this routine to provide /// different behavior. ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, - Optional<unsigned> NumExpansions) { + std::optional<unsigned> NumExpansions) { return getSema().CheckPackExpansion(Pattern, EllipsisLoc, NumExpansions); } @@ -3766,7 +3851,7 @@ public: BinaryOperatorKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc, - Optional<unsigned> NumExpansions) { + std::optional<unsigned> NumExpansions) { return getSema().BuildCXXFoldExpr(ULE, LParenLoc, LHS, Operator, EllipsisLoc, RHS, RParenLoc, NumExpansions); @@ -3781,6 +3866,16 @@ public: return getSema().BuildEmptyCXXFoldExpr(EllipsisLoc, Operator); } + ExprResult RebuildCXXParenListInitExpr(ArrayRef<Expr *> Args, QualType T, + unsigned NumUserSpecifiedExprs, + SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return CXXParenListInitExpr::Create(getSema().Context, Args, T, + NumUserSpecifiedExprs, InitLoc, + LParenLoc, RParenLoc); + } + /// Build a new atomic operation expression. /// /// By default, performs semantic analysis to build the new expression. @@ -3931,13 +4026,13 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init, // Revert value-initialization back to empty parens. if (CXXScalarValueInitExpr *VIE = dyn_cast<CXXScalarValueInitExpr>(Init)) { SourceRange Parens = VIE->getSourceRange(); - return getDerived().RebuildParenListExpr(Parens.getBegin(), None, + return getDerived().RebuildParenListExpr(Parens.getBegin(), std::nullopt, Parens.getEnd()); } // FIXME: We shouldn't build ImplicitValueInitExprs for direct-initialization. if (isa<ImplicitValueInitExpr>(Init)) - return getDerived().RebuildParenListExpr(SourceLocation(), None, + return getDerived().RebuildParenListExpr(SourceLocation(), std::nullopt, SourceLocation()); // Revert initialization by constructor back to a parenthesized or braced list @@ -4005,8 +4100,8 @@ bool TreeTransform<Derived>::TransformExprs(Expr *const *Inputs, // be expanded. bool Expand = true; bool RetainExpansion = false; - Optional<unsigned> OrigNumExpansions = Expansion->getNumExpansions(); - Optional<unsigned> NumExpansions = OrigNumExpansions; + std::optional<unsigned> OrigNumExpansions = Expansion->getNumExpansions(); + std::optional<unsigned> NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded, @@ -4123,9 +4218,13 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc( NestedNameSpecifierLoc NNS, QualType ObjectType, NamedDecl *FirstQualifierInScope) { SmallVector<NestedNameSpecifierLoc, 4> Qualifiers; - for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier; - Qualifier = Qualifier.getPrefix()) - Qualifiers.push_back(Qualifier); + + auto insertNNS = [&Qualifiers](NestedNameSpecifierLoc NNS) { + for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier; + Qualifier = Qualifier.getPrefix()) + Qualifiers.push_back(Qualifier); + }; + insertNNS(NNS); CXXScopeSpec SS; while (!Qualifiers.empty()) { @@ -4182,24 +4281,27 @@ NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc( if (!TL) return NestedNameSpecifierLoc(); - if (TL.getType()->isDependentType() || TL.getType()->isRecordType() || - (SemaRef.getLangOpts().CPlusPlus11 && - TL.getType()->isEnumeralType())) { - assert(!TL.getType().hasLocalQualifiers() && - "Can't get cv-qualifiers here"); - if (TL.getType()->isEnumeralType()) + QualType T = TL.getType(); + if (T->isDependentType() || T->isRecordType() || + (SemaRef.getLangOpts().CPlusPlus11 && T->isEnumeralType())) { + if (T->isEnumeralType()) SemaRef.Diag(TL.getBeginLoc(), diag::warn_cxx98_compat_enum_nested_name_spec); + + if (const auto ETL = TL.getAs<ElaboratedTypeLoc>()) { + SS.Adopt(ETL.getQualifierLoc()); + TL = ETL.getNamedTypeLoc(); + } SS.Extend(SemaRef.Context, /*FIXME:*/ SourceLocation(), TL, Q.getLocalEndLoc()); break; } // If the nested-name-specifier is an invalid type def, don't emit an // error because a previous error should have already been emitted. - TypedefTypeLoc TTL = TL.getAs<TypedefTypeLoc>(); + TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>(); if (!TTL || !TTL.getTypedefNameDecl()->isInvalidDecl()) { SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag) - << TL.getType() << SS.getRange(); + << T << SS.getRange(); } return NestedNameSpecifierLoc(); } @@ -4362,18 +4464,9 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS, if (SubstTemplateTemplateParmPackStorage *SubstPack = Name.getAsSubstTemplateTemplateParmPack()) { - TemplateTemplateParmDecl *TransParam - = cast_or_null<TemplateTemplateParmDecl>( - getDerived().TransformDecl(NameLoc, SubstPack->getParameterPack())); - if (!TransParam) - return TemplateName(); - - if (!getDerived().AlwaysRebuild() && - TransParam == SubstPack->getParameterPack()) - return Name; - - return getDerived().RebuildTemplateName(TransParam, - SubstPack->getArgumentPack()); + return getDerived().RebuildTemplateName( + SubstPack->getArgumentPack(), SubstPack->getAssociatedDecl(), + SubstPack->getIndex(), SubstPack->getFinal()); } // These should be getting filtered out before they reach the AST. @@ -4587,7 +4680,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments( // We have a pack expansion, for which we will be substituting into // the pattern. SourceLocation Ellipsis; - Optional<unsigned> OrigNumExpansions; + std::optional<unsigned> OrigNumExpansions; TemplateArgumentLoc Pattern = getSema().getTemplateArgumentPackExpansionPattern( In, Ellipsis, OrigNumExpansions); @@ -4600,7 +4693,7 @@ bool TreeTransform<Derived>::TransformTemplateArguments( // be expanded. bool Expand = true; bool RetainExpansion = false; - Optional<unsigned> NumExpansions = OrigNumExpansions; + std::optional<unsigned> NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(Ellipsis, Pattern.getSourceRange(), Unexpanded, @@ -4787,7 +4880,20 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, QualifiedTypeLoc T) { - QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc()); + QualType Result; + TypeLoc UnqualTL = T.getUnqualifiedLoc(); + auto SuppressObjCLifetime = + T.getType().getLocalQualifiers().hasObjCLifetime(); + if (auto TTP = UnqualTL.getAs<TemplateTypeParmTypeLoc>()) { + Result = getDerived().TransformTemplateTypeParmType(TLB, TTP, + SuppressObjCLifetime); + } else if (auto STTP = UnqualTL.getAs<SubstTemplateTypeParmPackTypeLoc>()) { + Result = getDerived().TransformSubstTemplateTypeParmPackType( + TLB, STTP, SuppressObjCLifetime); + } else { + Result = getDerived().TransformType(TLB, UnqualTL); + } + if (Result.isNull()) return QualType(); @@ -4850,16 +4956,7 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T, // A lifetime qualifier applied to a substituted template parameter // overrides the lifetime qualifier from the template argument. const AutoType *AutoTy; - if (const SubstTemplateTypeParmType *SubstTypeParam - = dyn_cast<SubstTemplateTypeParmType>(T)) { - QualType Replacement = SubstTypeParam->getReplacementType(); - Qualifiers Qs = Replacement.getQualifiers(); - Qs.removeObjCLifetime(); - Replacement = SemaRef.Context.getQualifiedType( - Replacement.getUnqualifiedType(), Qs); - T = SemaRef.Context.getSubstTemplateTypeParmType( - SubstTypeParam->getReplacedParameter(), Replacement); - } else if ((AutoTy = dyn_cast<AutoType>(T)) && AutoTy->isDeduced()) { + if ((AutoTy = dyn_cast<AutoType>(T)) && AutoTy->isDeduced()) { // 'auto' types behave the same way as template parameters. QualType Deduced = AutoTy->getDeducedType(); Qualifiers Qs = Deduced.getQualifiers(); @@ -5604,8 +5701,8 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB, template <typename Derived> ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam( - ParmVarDecl *OldParm, int indexAdjustment, Optional<unsigned> NumExpansions, - bool ExpectParameterPack) { + ParmVarDecl *OldParm, int indexAdjustment, + std::optional<unsigned> NumExpansions, bool ExpectParameterPack) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); TypeSourceInfo *NewDI = nullptr; @@ -5665,15 +5762,18 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams( const FunctionProtoType::ExtParameterInfo *ParamInfos, SmallVectorImpl<QualType> &OutParamTypes, SmallVectorImpl<ParmVarDecl *> *PVars, - Sema::ExtParameterInfoBuilder &PInfos) { + Sema::ExtParameterInfoBuilder &PInfos, + unsigned *LastParamTransformed) { int indexAdjustment = 0; unsigned NumParams = Params.size(); for (unsigned i = 0; i != NumParams; ++i) { + if (LastParamTransformed) + *LastParamTransformed = i; if (ParmVarDecl *OldParm = Params[i]) { assert(OldParm->getFunctionScopeIndex() == i); - Optional<unsigned> NumExpansions; + std::optional<unsigned> NumExpansions; ParmVarDecl *NewParm = nullptr; if (OldParm->isParameterPack()) { // We have a function parameter pack that may need to be expanded. @@ -5688,7 +5788,7 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams( // Determine whether we should expand the parameter packs. bool ShouldExpand = false; bool RetainExpansion = false; - Optional<unsigned> OrigNumExpansions; + std::optional<unsigned> OrigNumExpansions; if (Unexpanded.size() > 0) { OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions(); NumExpansions = OrigNumExpansions; @@ -5771,7 +5871,8 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams( "transformation."); } else { NewParm = getDerived().TransformFunctionTypeParam( - OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false); + OldParm, indexAdjustment, std::nullopt, + /*ExpectParameterPack=*/false); } if (!NewParm) @@ -5787,14 +5888,16 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams( // Deal with the possibility that we don't have a parameter // declaration for this parameter. + assert(ParamTypes); QualType OldType = ParamTypes[i]; bool IsPackExpansion = false; - Optional<unsigned> NumExpansions; + std::optional<unsigned> NumExpansions; QualType NewType; if (const PackExpansionType *Expansion = dyn_cast<PackExpansionType>(OldType)) { // We have a function parameter pack that may need to be expanded. QualType Pattern = Expansion->getPattern(); + NumExpansions = Expansion->getNumExpansions(); SmallVector<UnexpandedParameterPack, 2> Unexpanded; getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); @@ -5819,8 +5922,8 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams( return true; if (NewType->containsUnexpandedParameterPack()) { - NewType = - getSema().getASTContext().getPackExpansionType(NewType, None); + NewType = getSema().getASTContext().getPackExpansionType( + NewType, std::nullopt); if (NewType.isNull()) return true; @@ -5965,8 +6068,8 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType( if (auto NewExtParamInfos = ExtParamInfos.getPointerOrNull(ParamTypes.size())) { if (!EPI.ExtParameterInfos || - llvm::makeArrayRef(EPI.ExtParameterInfos, TL.getNumParams()) - != llvm::makeArrayRef(NewExtParamInfos, ParamTypes.size())) { + llvm::ArrayRef(EPI.ExtParameterInfos, TL.getNumParams()) != + llvm::ArrayRef(NewExtParamInfos, ParamTypes.size())) { EPIChanged = true; } EPI.ExtParameterInfos = NewExtParamInfos; @@ -5977,7 +6080,7 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType( QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() || - T->getParamTypes() != llvm::makeArrayRef(ParamTypes) || EPIChanged) { + T->getParamTypes() != llvm::ArrayRef(ParamTypes) || EPIChanged) { Result = getDerived().RebuildFunctionProtoType(ResultType, ParamTypes, EPI); if (Result.isNull()) return QualType(); @@ -6041,7 +6144,7 @@ bool TreeTransform<Derived>::TransformExceptionSpec( // be expanded. bool Expand = false; bool RetainExpansion = false; - Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); + std::optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); // FIXME: Track the location of the ellipsis (and track source location // information for the types in the exception specification in general). if (getDerived().TryExpandParameterPacks( @@ -6203,13 +6306,13 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, return QualType(); QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || - E.get() != TL.getUnderlyingExpr()) { - Result = getDerived().RebuildTypeOfExprType(E.get(), TL.getTypeofLoc()); + TypeOfKind Kind = Result->getAs<TypeOfExprType>()->getKind(); + if (getDerived().AlwaysRebuild() || E.get() != TL.getUnderlyingExpr()) { + Result = + getDerived().RebuildTypeOfExprType(E.get(), TL.getTypeofLoc(), Kind); if (Result.isNull()) return QualType(); } - else E.get(); TypeOfExprTypeLoc NewTL = TLB.push<TypeOfExprTypeLoc>(Result); NewTL.setTypeofLoc(TL.getTypeofLoc()); @@ -6222,14 +6325,15 @@ QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, template<typename Derived> QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB, TypeOfTypeLoc TL) { - TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo(); + TypeSourceInfo* Old_Under_TI = TL.getUnmodifiedTInfo(); TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI); if (!New_Under_TI) return QualType(); QualType Result = TL.getType(); + TypeOfKind Kind = Result->getAs<TypeOfType>()->getKind(); if (getDerived().AlwaysRebuild() || New_Under_TI != Old_Under_TI) { - Result = getDerived().RebuildTypeOfType(New_Under_TI->getType()); + Result = getDerived().RebuildTypeOfType(New_Under_TI->getType(), Kind); if (Result.isNull()) return QualType(); } @@ -6238,7 +6342,7 @@ QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB, NewTL.setTypeofLoc(TL.getTypeofLoc()); NewTL.setLParenLoc(TL.getLParenLoc()); NewTL.setRParenLoc(TL.getRParenLoc()); - NewTL.setUnderlyingTInfo(New_Under_TI); + NewTL.setUnmodifiedTInfo(New_Under_TI); return Result; } @@ -6395,6 +6499,14 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateTypeParmType( TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL) { + return getDerived().TransformTemplateTypeParmType( + TLB, TL, + /*SuppressObjCLifetime=*/false); +} + +template <typename Derived> +QualType TreeTransform<Derived>::TransformTemplateTypeParmType( + TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL, bool) { return TransformTypeSpecType(TLB, TL); } @@ -6404,6 +6516,9 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType( SubstTemplateTypeParmTypeLoc TL) { const SubstTemplateTypeParmType *T = TL.getTypePtr(); + Decl *NewReplaced = + getDerived().TransformDecl(TL.getNameLoc(), T->getAssociatedDecl()); + // Substitute into the replacement type, which itself might involve something // that needs to be transformed. This only tends to occur with default // template arguments of template template parameters. @@ -6412,11 +6527,8 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType( if (Replacement.isNull()) return QualType(); - // Always canonicalize the replacement type. - Replacement = SemaRef.Context.getCanonicalType(Replacement); - QualType Result - = SemaRef.Context.getSubstTemplateTypeParmType(T->getReplacedParameter(), - Replacement); + QualType Result = SemaRef.Context.getSubstTemplateTypeParmType( + Replacement, NewReplaced, T->getIndex(), T->getPackIndex()); // Propagate type-source information. SubstTemplateTypeParmTypeLoc NewTL @@ -6430,6 +6542,13 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType( TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL) { + return getDerived().TransformSubstTemplateTypeParmPackType( + TLB, TL, /*SuppressObjCLifetime=*/false); +} + +template <typename Derived> +QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType( + TypeLocBuilder &TLB, SubstTemplateTypeParmPackTypeLoc TL, bool) { return TransformTypeSpecType(TLB, TL); } @@ -6750,12 +6869,9 @@ QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType( // FIXME: maybe don't rebuild if all the template arguments are the same. if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { - QualType Result - = getSema().Context.getDependentTemplateSpecializationType( - TL.getTypePtr()->getKeyword(), - DTN->getQualifier(), - DTN->getIdentifier(), - NewTemplateArgs); + QualType Result = getSema().Context.getDependentTemplateSpecializationType( + TL.getTypePtr()->getKeyword(), DTN->getQualifier(), + DTN->getIdentifier(), NewTemplateArgs.arguments()); DependentTemplateSpecializationTypeLoc NewTL = TLB.push<DependentTemplateSpecializationTypeLoc>(Result); @@ -7113,12 +7229,10 @@ TreeTransform<Derived>::TransformObjCTypeParamType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || OTP != T->getDecl()) { - Result = getDerived().RebuildObjCTypeParamType(OTP, - TL.getProtocolLAngleLoc(), - llvm::makeArrayRef(TL.getTypePtr()->qual_begin(), - TL.getNumProtocols()), - TL.getProtocolLocs(), - TL.getProtocolRAngleLoc()); + Result = getDerived().RebuildObjCTypeParamType( + OTP, TL.getProtocolLAngleLoc(), + llvm::ArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()), + TL.getProtocolLocs(), TL.getProtocolRAngleLoc()); if (Result.isNull()) return QualType(); } @@ -7166,7 +7280,7 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc(); bool Expand = false; bool RetainExpansion = false; - Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); + std::optional<unsigned> NumExpansions = PackExpansion->getNumExpansions(); if (getDerived().TryExpandParameterPacks( PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(), Unexpanded, Expand, RetainExpansion, NumExpansions)) @@ -7216,7 +7330,8 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, TypeLocBuilder TypeArgBuilder; TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize()); - QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc); + QualType NewTypeArg = + getDerived().TransformType(TypeArgBuilder, TypeArgLoc); if (NewTypeArg.isNull()) return QualType(); @@ -7237,7 +7352,7 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, Result = getDerived().RebuildObjCObjectType( BaseType, TL.getBeginLoc(), TL.getTypeArgsLAngleLoc(), NewTypeArgInfos, TL.getTypeArgsRAngleLoc(), TL.getProtocolLAngleLoc(), - llvm::makeArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()), + llvm::ArrayRef(TL.getTypePtr()->qual_begin(), TL.getNumProtocols()), TL.getProtocolLocs(), TL.getProtocolRAngleLoc()); if (Result.isNull()) @@ -7483,7 +7598,7 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { } // If this is a constexpr if, determine which arm we should instantiate. - llvm::Optional<bool> ConstexprConditionValue; + std::optional<bool> ConstexprConditionValue; if (S->isConstexpr()) ConstexprConditionValue = Cond.getKnownValue(); @@ -7800,8 +7915,7 @@ TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) { template<typename Derived> StmtResult TreeTransform<Derived>::TransformMSAsmStmt(MSAsmStmt *S) { - ArrayRef<Token> AsmToks = - llvm::makeArrayRef(S->getAsmToks(), S->getNumAsmToks()); + ArrayRef<Token> AsmToks = llvm::ArrayRef(S->getAsmToks(), S->getNumAsmToks()); bool HadError = false, HadChange = false; @@ -8839,6 +8953,17 @@ TreeTransform<Derived>::TransformOMPTaskwaitDirective(OMPTaskwaitDirective *D) { } template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPErrorDirective(OMPErrorDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_error, DirName, nullptr, + D->getBeginLoc()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> StmtResult TreeTransform<Derived>::TransformOMPTaskgroupDirective( OMPTaskgroupDirective *D) { DeclarationNameInfo DirName; @@ -9676,17 +9801,17 @@ OMPClause *TreeTransform<Derived>::TransformOMPInitClause(OMPInitClause *C) { if (IVR.isInvalid()) return nullptr; - llvm::SmallVector<Expr *, 8> PrefExprs; - PrefExprs.reserve(C->varlist_size() - 1); + OMPInteropInfo InteropInfo(C->getIsTarget(), C->getIsTargetSync()); + InteropInfo.PreferTypes.reserve(C->varlist_size() - 1); for (Expr *E : llvm::drop_begin(C->varlists())) { ExprResult ER = getDerived().TransformExpr(cast<Expr>(E)); if (ER.isInvalid()) return nullptr; - PrefExprs.push_back(ER.get()); + InteropInfo.PreferTypes.push_back(ER.get()); } - return getDerived().RebuildOMPInitClause( - IVR.get(), PrefExprs, C->getIsTarget(), C->getIsTargetSync(), - C->getBeginLoc(), C->getLParenLoc(), C->getVarLoc(), C->getEndLoc()); + return getDerived().RebuildOMPInitClause(IVR.get(), InteropInfo, + C->getBeginLoc(), C->getLParenLoc(), + C->getVarLoc(), C->getEndLoc()); } template <typename Derived> @@ -9786,6 +9911,32 @@ OMPClause *TreeTransform<Derived>::TransformOMPAtomicDefaultMemOrderClause( } template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPAtClause(OMPAtClause *C) { + return getDerived().RebuildOMPAtClause(C->getAtKind(), C->getAtKindKwLoc(), + C->getBeginLoc(), C->getLParenLoc(), + C->getEndLoc()); +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPSeverityClause(OMPSeverityClause *C) { + return getDerived().RebuildOMPSeverityClause( + C->getSeverityKind(), C->getSeverityKindKwLoc(), C->getBeginLoc(), + C->getLParenLoc(), C->getEndLoc()); +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPMessageClause(OMPMessageClause *C) { + ExprResult E = getDerived().TransformExpr(C->getMessageString()); + if (E.isInvalid()) + return nullptr; + return getDerived().RebuildOMPMessageClause( + C->getMessageString(), C->getBeginLoc(), C->getLParenLoc(), + C->getEndLoc()); +} + +template <typename Derived> OMPClause * TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) { llvm::SmallVector<Expr *, 16> Vars; @@ -10168,6 +10319,13 @@ template <typename Derived> OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) { OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); llvm::SmallVector<Expr *, 16> Vars; + Expr *IteratorModifier = C->getIteratorModifier(); + if (IteratorModifier) { + ExprResult MapModRes = getDerived().TransformExpr(IteratorModifier); + if (MapModRes.isInvalid()) + return nullptr; + IteratorModifier = MapModRes.get(); + } CXXScopeSpec MapperIdScopeSpec; DeclarationNameInfo MapperIdInfo; llvm::SmallVector<Expr *, 16> UnresolvedMappers; @@ -10175,9 +10333,9 @@ OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) { *this, C, Vars, MapperIdScopeSpec, MapperIdInfo, UnresolvedMappers)) return nullptr; return getDerived().RebuildOMPMapClause( - C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), MapperIdScopeSpec, - MapperIdInfo, C->getMapType(), C->isImplicitMapType(), C->getMapLoc(), - C->getColonLoc(), Vars, Locs, UnresolvedMappers); + IteratorModifier, C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(), + MapperIdScopeSpec, MapperIdInfo, C->getMapType(), C->isImplicitMapType(), + C->getMapLoc(), C->getColonLoc(), Vars, Locs, UnresolvedMappers); } template <typename Derived> @@ -10240,7 +10398,8 @@ TreeTransform<Derived>::TransformOMPGrainsizeClause(OMPGrainsizeClause *C) { if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPGrainsizeClause( - E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + C->getModifier(), E.get(), C->getBeginLoc(), C->getLParenLoc(), + C->getModifierLoc(), C->getEndLoc()); } template <typename Derived> @@ -10250,7 +10409,8 @@ TreeTransform<Derived>::TransformOMPNumTasksClause(OMPNumTasksClause *C) { if (E.isInvalid()) return nullptr; return getDerived().RebuildOMPNumTasksClause( - E.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + C->getModifier(), E.get(), C->getBeginLoc(), C->getLParenLoc(), + C->getModifierLoc(), C->getEndLoc()); } template <typename Derived> @@ -10472,9 +10632,9 @@ TreeTransform<Derived>::TransformOMPAffinityClause(OMPAffinityClause *C) { template <typename Derived> OMPClause *TreeTransform<Derived>::TransformOMPOrderClause(OMPOrderClause *C) { - return getDerived().RebuildOMPOrderClause(C->getKind(), C->getKindKwLoc(), - C->getBeginLoc(), C->getLParenLoc(), - C->getEndLoc()); + return getDerived().RebuildOMPOrderClause( + C->getKind(), C->getKindKwLoc(), C->getBeginLoc(), C->getLParenLoc(), + C->getEndLoc(), C->getModifier(), C->getModifierKwLoc()); } template <typename Derived> @@ -10484,6 +10644,16 @@ OMPClause *TreeTransform<Derived>::TransformOMPBindClause(OMPBindClause *C) { C->getLParenLoc(), C->getEndLoc()); } +template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPXDynCGroupMemClause( + OMPXDynCGroupMemClause *C) { + ExprResult Size = getDerived().TransformExpr(C->getSize()); + if (Size.isInvalid()) + return nullptr; + return getDerived().RebuildOMPXDynCGroupMemClause( + Size.get(), C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// @@ -11190,7 +11360,7 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { return getDerived().RebuildBinaryOperator( E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get()); Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); - FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts())); + FPOptionsOverride NewOverrides(E->getFPFeatures()); getSema().CurFPFeatures = NewOverrides.applyOverrides(getSema().getLangOpts()); getSema().FpPragmaStack.CurrentValue = NewOverrides; @@ -11257,7 +11427,7 @@ ExprResult TreeTransform<Derived>::TransformCompoundAssignOperator( CompoundAssignOperator *E) { Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); - FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts())); + FPOptionsOverride NewOverrides(E->getFPFeatures()); getSema().CurFPFeatures = NewOverrides.applyOverrides(getSema().getLangOpts()); getSema().FpPragmaStack.CurrentValue = NewOverrides; @@ -11389,9 +11559,9 @@ TreeTransform<Derived>::TransformExtVectorElementExpr(ExtVectorElementExpr *E) { // FIXME: Bad source location SourceLocation FakeOperatorLoc = SemaRef.getLocForEndOfToken(E->getBase()->getEndLoc()); - return getDerived().RebuildExtVectorElementExpr(Base.get(), FakeOperatorLoc, - E->getAccessorLoc(), - E->getAccessor()); + return getDerived().RebuildExtVectorElementExpr( + Base.get(), FakeOperatorLoc, E->isArrow(), E->getAccessorLoc(), + E->getAccessor()); } template<typename Derived> @@ -12024,11 +12194,20 @@ TreeTransform<Derived>::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) { if (!Param) return ExprError(); + ExprResult InitRes; + if (E->hasRewrittenInit()) { + InitRes = getDerived().TransformExpr(E->getRewrittenExpr()); + if (InitRes.isInvalid()) + return ExprError(); + } + if (!getDerived().AlwaysRebuild() && Param == E->getParam() && - E->getUsedContext() == SemaRef.CurContext) + E->getUsedContext() == SemaRef.CurContext && + InitRes.get() == E->getRewrittenExpr()) return E; - return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param); + return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param, + InitRes.get()); } template<typename Derived> @@ -12073,10 +12252,10 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { return ExprError(); // Transform the size of the array we're allocating (if any). - Optional<Expr *> ArraySize; + std::optional<Expr *> ArraySize; if (E->isArray()) { ExprResult NewArraySize; - if (Optional<Expr *> OldArraySize = E->getArraySize()) { + if (std::optional<Expr *> OldArraySize = E->getArraySize()) { NewArraySize = getDerived().TransformExpr(*OldArraySize); if (NewArraySize.isInvalid()) return ExprError(); @@ -12455,9 +12634,9 @@ TreeTransform<Derived>::TransformTypeTraitExpr(TypeTraitExpr *E) { // be expanded. bool Expand = true; bool RetainExpansion = false; - Optional<unsigned> OrigNumExpansions = + std::optional<unsigned> OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions(); - Optional<unsigned> NumExpansions = OrigNumExpansions; + std::optional<unsigned> NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), PatternTL.getSourceRange(), Unexpanded, @@ -12578,7 +12757,8 @@ TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) { // C++2a [expr.prim.req]p2 // Expressions appearing within a requirement-body are unevaluated operands. EnterExpressionEvaluationContext Ctx( - SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated, + Sema::ReuseLambdaContextDecl); RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create( getSema().Context, getSema().CurContext, @@ -12586,16 +12766,20 @@ TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) { Sema::ContextRAII SavedContext(getSema(), Body, /*NewThisContext*/false); - if (getDerived().TransformFunctionTypeParams(E->getRequiresKWLoc(), - E->getLocalParameters(), - /*ParamTypes=*/nullptr, - /*ParamInfos=*/nullptr, - TransParamTypes, &TransParams, - ExtParamInfos)) - return ExprError(); + ExprResult TypeParamResult = getDerived().TransformRequiresTypeParams( + E->getRequiresKWLoc(), E->getRBraceLoc(), E, Body, + E->getLocalParameters(), TransParamTypes, TransParams, ExtParamInfos); for (ParmVarDecl *Param : TransParams) - Param->setDeclContext(Body); + if (Param) + Param->setDeclContext(Body); + + // On failure to transform, TransformRequiresTypeParams returns an expression + // in the event that the transformation of the type params failed in some way. + // It is expected that this will result in a 'not satisfied' Requires clause + // when instantiating. + if (!TypeParamResult.isUnset()) + return TypeParamResult; SmallVector<concepts::Requirement *, 4> TransReqs; if (getDerived().TransformRequiresExprRequirements(E->getRequirements(), @@ -12668,7 +12852,7 @@ TreeTransform<Derived>::TransformExprRequirement(concepts::ExprRequirement *Req) TransExpr = TransExprRes.get(); } - llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq; + std::optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq; const auto &RetReq = Req->getReturnTypeRequirement(); if (RetReq.isEmpty()) TransRetReq.emplace(); @@ -12697,10 +12881,10 @@ template<typename Derived> concepts::NestedRequirement * TreeTransform<Derived>::TransformNestedRequirement( concepts::NestedRequirement *Req) { - if (Req->isSubstitutionFailure()) { + if (Req->hasInvalidConstraint()) { if (getDerived().AlwaysRebuild()) return getDerived().RebuildNestedRequirement( - Req->getSubstitutionDiagnostic()); + Req->getInvalidConstraintEntity(), Req->getConstraintSatisfaction()); return Req; } ExprResult TransConstraint = @@ -12990,10 +13174,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { continue; TransformedInitCapture &Result = InitCaptures[C - E->capture_begin()]; - VarDecl *OldVD = C->getCapturedVar(); + auto *OldVD = cast<VarDecl>(C->getCapturedVar()); auto SubstInitCapture = [&](SourceLocation EllipsisLoc, - Optional<unsigned> NumExpansions) { + std::optional<unsigned> NumExpansions) { ExprResult NewExprInitResult = getDerived().TransformInitializer( OldVD->getInit(), OldVD->getInitStyle() == VarDecl::CallInit); @@ -13005,9 +13189,10 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { QualType NewInitCaptureType = getSema().buildLambdaInitCaptureInitialization( - C->getLocation(), OldVD->getType()->isReferenceType(), + C->getLocation(), C->getCaptureKind() == LCK_ByRef, EllipsisLoc, NumExpansions, OldVD->getIdentifier(), - C->getCapturedVar()->getInitStyle() != VarDecl::CInit, + cast<VarDecl>(C->getCapturedVar())->getInitStyle() != + VarDecl::CInit, NewExprInit); Result.Expansions.push_back( InitCaptureInfoTy(NewExprInit, NewInitCaptureType)); @@ -13025,9 +13210,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { // be expanded. bool Expand = true; bool RetainExpansion = false; - Optional<unsigned> OrigNumExpansions = + std::optional<unsigned> OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions(); - Optional<unsigned> NumExpansions = OrigNumExpansions; + std::optional<unsigned> NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks( ExpansionTL.getEllipsisLoc(), OldVD->getInit()->getSourceRange(), Unexpanded, Expand, @@ -13036,7 +13221,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { if (Expand) { for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); - SubstInitCapture(SourceLocation(), None); + SubstInitCapture(SourceLocation(), std::nullopt); } } if (!Expand || RetainExpansion) { @@ -13045,7 +13230,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { Result.EllipsisLoc = ExpansionTL.getEllipsisLoc(); } } else { - SubstInitCapture(SourceLocation(), None); + SubstInitCapture(SourceLocation(), std::nullopt); } } @@ -13083,23 +13268,17 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { NewCallOpType); } - // Transform the trailing requires clause - ExprResult NewTrailingRequiresClause; - if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause()) - // FIXME: Concepts: Substitution into requires clause should only happen - // when checking satisfaction. - NewTrailingRequiresClause = getDerived().TransformExpr(TRC); - // Create the local class that will describe the lambda. // FIXME: DependencyKind below is wrong when substituting inside a templated // context that isn't a DeclContext (such as a variable template), or when // substituting an unevaluated lambda inside of a function's parameter's type // - as parameter types are not instantiated from within a function's DC. We - // use isUnevaluatedContext() to distinguish the function parameter case. + // use evaluation contexts to distinguish the function parameter case. CXXRecordDecl::LambdaDependencyKind DependencyKind = CXXRecordDecl::LDK_Unknown; - if (getSema().isUnevaluatedContext() && + if ((getSema().isUnevaluatedContext() || + getSema().isConstantEvaluatedContext()) && (getSema().CurContext->isFileContext() || !getSema().CurContext->getParent()->isDependentContext())) DependencyKind = CXXRecordDecl::LDK_NeverDependent; @@ -13111,7 +13290,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { getDerived().transformedLocalDecl(OldClass, {Class}); - Optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling; + std::optional<std::tuple<bool, unsigned, unsigned, Decl *>> Mangling; if (getDerived().ReplacingOriginal()) Mangling = std::make_tuple(OldClass->hasKnownLambdaInternalLinkage(), OldClass->getLambdaManglingNumber(), @@ -13124,7 +13303,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { E->getCallOperator()->getEndLoc(), NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(), E->getCallOperator()->getConstexprKind(), - NewTrailingRequiresClause.get()); + E->getCallOperator()->getStorageClass(), + E->getCallOperator()->getTrailingRequiresClause()); LSI->CallOperator = NewCallOperator; @@ -13174,7 +13354,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { if (E->isInitCapture(C)) { TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()]; - VarDecl *OldVD = C->getCapturedVar(); + auto *OldVD = cast<VarDecl>(C->getCapturedVar()); llvm::SmallVector<Decl*, 4> NewVDs; for (InitCaptureInfoTy &Info : NewC.Expansions) { @@ -13192,7 +13372,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { break; } NewVDs.push_back(NewVD); - getSema().addInitCapture(LSI, NewVD); + getSema().addInitCapture(LSI, NewVD, C->getCaptureKind() == LCK_ByRef); } if (Invalid) @@ -13215,7 +13395,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { UnexpandedParameterPack Unexpanded(C->getCapturedVar(), C->getLocation()); bool ShouldExpand = false; bool RetainExpansion = false; - Optional<unsigned> NumExpansions; + std::optional<unsigned> NumExpansions; if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(), C->getLocation(), Unexpanded, @@ -13229,7 +13409,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { // The transform has determined that we should perform an expansion; // transform and capture each of the arguments. // expansion of the pattern. Do so. - VarDecl *Pack = C->getCapturedVar(); + auto *Pack = cast<VarDecl>(C->getCapturedVar()); for (unsigned I = 0; I != *NumExpansions; ++I) { Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); VarDecl *CapturedVar @@ -13253,9 +13433,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { } // Transform the captured variable. - VarDecl *CapturedVar - = cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(), - C->getCapturedVar())); + auto *CapturedVar = cast_or_null<ValueDecl>( + getDerived().TransformDecl(C->getLocation(), C->getCapturedVar())); if (!CapturedVar || CapturedVar->isInvalidDecl()) { Invalid = true; continue; @@ -13592,7 +13771,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc()); bool ShouldExpand = false; bool RetainExpansion = false; - Optional<unsigned> NumExpansions; + std::optional<unsigned> NumExpansions; if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(), Unexpanded, ShouldExpand, RetainExpansion, @@ -13605,9 +13784,9 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { auto *Pack = E->getPack(); if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Pack)) { ArgStorage = getSema().Context.getPackExpansionType( - getSema().Context.getTypeDeclType(TTPD), None); + getSema().Context.getTypeDeclType(TTPD), std::nullopt); } else if (auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Pack)) { - ArgStorage = TemplateArgument(TemplateName(TTPD), None); + ArgStorage = TemplateArgument(TemplateName(TTPD), std::nullopt); } else { auto *VD = cast<ValueDecl>(Pack); ExprResult DRE = getSema().BuildDeclRefExpr( @@ -13616,8 +13795,9 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { E->getPackLoc()); if (DRE.isInvalid()) return ExprError(); - ArgStorage = new (getSema().Context) PackExpansionExpr( - getSema().Context.DependentTy, DRE.get(), E->getPackLoc(), None); + ArgStorage = new (getSema().Context) + PackExpansionExpr(getSema().Context.DependentTy, DRE.get(), + E->getPackLoc(), std::nullopt); } PackArgs = ArgStorage; } @@ -13629,13 +13809,13 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { getDerived().TransformDecl(E->getPackLoc(), E->getPack())); if (!Pack) return ExprError(); - return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), Pack, - E->getPackLoc(), - E->getRParenLoc(), None, None); + return getDerived().RebuildSizeOfPackExpr( + E->getOperatorLoc(), Pack, E->getPackLoc(), E->getRParenLoc(), + std::nullopt, std::nullopt); } // Try to compute the result without performing a partial substitution. - Optional<unsigned> Result = 0; + std::optional<unsigned> Result = 0; for (const TemplateArgument &Arg : PackArgs) { if (!Arg.isPackExpansion()) { Result = *Result + 1; @@ -13647,7 +13827,7 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { // Find the pattern of the pack expansion. SourceLocation Ellipsis; - Optional<unsigned> OrigNumExpansions; + std::optional<unsigned> OrigNumExpansions; TemplateArgumentLoc Pattern = getSema().getTemplateArgumentPackExpansionPattern(ArgLoc, Ellipsis, OrigNumExpansions); @@ -13660,12 +13840,12 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { return true; // See if we can determine the number of arguments from the result. - Optional<unsigned> NumExpansions = + std::optional<unsigned> NumExpansions = getSema().getFullyPackExpandedSize(OutPattern.getArgument()); if (!NumExpansions) { // No: we must be in an alias template expansion, and we're going to need // to actually expand the packs. - Result = None; + Result = std::nullopt; break; } @@ -13675,9 +13855,9 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { // Common case: we could determine the number of expansions without // substituting. if (Result) - return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), - E->getPackLoc(), - E->getRParenLoc(), *Result, None); + return getDerived().RebuildSizeOfPackExpr( + E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(), + *Result, std::nullopt); TemplateArgumentListInfo TransformedPackArgs(E->getPackLoc(), E->getPackLoc()); @@ -13702,13 +13882,13 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { } if (PartialSubstitution) - return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), - E->getPackLoc(), - E->getRParenLoc(), None, Args); + return getDerived().RebuildSizeOfPackExpr( + E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(), + std::nullopt, Args); return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), E->getPackLoc(), E->getRParenLoc(), - Args.size(), None); + Args.size(), std::nullopt); } template<typename Derived> @@ -13762,8 +13942,8 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { // be expanded. bool Expand = true; bool RetainExpansion = false; - Optional<unsigned> OrigNumExpansions = E->getNumExpansions(), - NumExpansions = OrigNumExpansions; + std::optional<unsigned> OrigNumExpansions = E->getNumExpansions(), + NumExpansions = OrigNumExpansions; if (getDerived().TryExpandParameterPacks(E->getEllipsisLoc(), Pattern->getSourceRange(), Unexpanded, @@ -13887,6 +14067,20 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { return Result; } +template <typename Derived> +ExprResult +TreeTransform<Derived>::TransformCXXParenListInitExpr(CXXParenListInitExpr *E) { + SmallVector<Expr *, 4> TransformedInits; + ArrayRef<Expr *> InitExprs = E->getInitExprs(); + if (TransformExprs(InitExprs.data(), InitExprs.size(), true, + TransformedInits)) + return ExprError(); + + return getDerived().RebuildCXXParenListInitExpr( + TransformedInits, E->getType(), E->getUserSpecifiedInitExprs().size(), + E->getInitLoc(), E->getBeginLoc(), E->getEndLoc()); +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformCXXStdInitializerListExpr( @@ -13959,8 +14153,8 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral( // and should be expanded. bool Expand = true; bool RetainExpansion = false; - Optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions; - Optional<unsigned> NumExpansions = OrigNumExpansions; + std::optional<unsigned> OrigNumExpansions = OrigElement.NumExpansions; + std::optional<unsigned> NumExpansions = OrigNumExpansions; SourceRange PatternRange(OrigElement.Key->getBeginLoc(), OrigElement.Value->getEndLoc()); if (getDerived().TryExpandParameterPacks(OrigElement.EllipsisLoc, @@ -14047,9 +14241,8 @@ TreeTransform<Derived>::TransformObjCDictionaryLiteral( if (Value.get() != OrigElement.Value) ArgChanged = true; - ObjCDictionaryElement Element = { - Key.get(), Value.get(), SourceLocation(), None - }; + ObjCDictionaryElement Element = {Key.get(), Value.get(), SourceLocation(), + std::nullopt}; Elements.push_back(Element); } @@ -14506,11 +14699,11 @@ QualType TreeTransform<Derived>::RebuildObjCObjectType( ArrayRef<ObjCProtocolDecl *> Protocols, ArrayRef<SourceLocation> ProtocolLocs, SourceLocation ProtocolRAngleLoc) { - return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc, - TypeArgs, TypeArgsRAngleLoc, - ProtocolLAngleLoc, Protocols, ProtocolLocs, - ProtocolRAngleLoc, - /*FailOnError=*/true); + return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc, TypeArgs, + TypeArgsRAngleLoc, ProtocolLAngleLoc, + Protocols, ProtocolLocs, ProtocolRAngleLoc, + /*FailOnError=*/true, + /*Rebuilding=*/true); } template<typename Derived> @@ -14538,11 +14731,10 @@ TreeTransform<Derived>::RebuildArrayType(QualType ElementType, SemaRef.Context.UnsignedIntTy, SemaRef.Context.UnsignedLongTy, SemaRef.Context.UnsignedLongLongTy, SemaRef.Context.UnsignedInt128Ty }; - const unsigned NumTypes = llvm::array_lengthof(Types); QualType SizeType; - for (unsigned I = 0; I != NumTypes; ++I) - if (Size->getBitWidth() == SemaRef.Context.getIntWidth(Types[I])) { - SizeType = Types[I]; + for (const auto &T : Types) + if (Size->getBitWidth() == SemaRef.Context.getIntWidth(T)) { + SizeType = T; break; } @@ -14733,14 +14925,15 @@ QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(SourceLocation Loc, } template <typename Derived> -QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E, - SourceLocation) { - return SemaRef.BuildTypeofExprType(E); +QualType TreeTransform<Derived>::RebuildTypeOfExprType(Expr *E, SourceLocation, + TypeOfKind Kind) { + return SemaRef.BuildTypeofExprType(E, Kind); } template<typename Derived> -QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying) { - return SemaRef.Context.getTypeOfType(Underlying); +QualType TreeTransform<Derived>::RebuildTypeOfType(QualType Underlying, + TypeOfKind Kind) { + return SemaRef.Context.getTypeOfType(Underlying, Kind); } template <typename Derived> diff --git a/clang/lib/Sema/TypeLocBuilder.cpp b/clang/lib/Sema/TypeLocBuilder.cpp index 2dcbbd83c691..fcd090ff2020 100644 --- a/clang/lib/Sema/TypeLocBuilder.cpp +++ b/clang/lib/Sema/TypeLocBuilder.cpp @@ -41,6 +41,29 @@ void TypeLocBuilder::pushFullCopy(TypeLoc L) { } } +void TypeLocBuilder::pushTrivial(ASTContext &Context, QualType T, + SourceLocation Loc) { + auto L = TypeLoc(T, nullptr); + reserve(L.getFullDataSize()); + + SmallVector<TypeLoc, 4> TypeLocs; + for (auto CurTL = L; CurTL; CurTL = CurTL.getNextTypeLoc()) + TypeLocs.push_back(CurTL); + + for (const auto &CurTL : llvm::reverse(TypeLocs)) { + switch (CurTL.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: { \ + auto NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \ + NewTL.initializeLocal(Context, Loc); \ + break; \ + } +#include "clang/AST/TypeLocNodes.def" + } + } +} + void TypeLocBuilder::grow(size_t NewCapacity) { assert(NewCapacity > Capacity); @@ -85,7 +108,7 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli // FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to // hardcode them. if (LocalAlignment == 4) { - if (NumBytesAtAlign8 == 0) { + if (!AtAlign8) { NumBytesAtAlign4 += LocalSize; } else { unsigned Padding = NumBytesAtAlign4 % 8; @@ -114,7 +137,7 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli NumBytesAtAlign4 += LocalSize; } } else if (LocalAlignment == 8) { - if (NumBytesAtAlign8 == 0) { + if (!AtAlign8) { // We have not seen any 8-byte aligned element yet. We insert a padding // only if the new Index is not 8-byte-aligned. if ((Index - LocalSize) % 8 != 0) { @@ -149,7 +172,7 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli // Forget about any padding. NumBytesAtAlign4 = 0; - NumBytesAtAlign8 += LocalSize; + AtAlign8 = true; } else { assert(LocalSize == 0); } diff --git a/clang/lib/Sema/TypeLocBuilder.h b/clang/lib/Sema/TypeLocBuilder.h index 738f731c9fe2..d413d74b74ff 100644 --- a/clang/lib/Sema/TypeLocBuilder.h +++ b/clang/lib/Sema/TypeLocBuilder.h @@ -40,12 +40,13 @@ class TypeLocBuilder { /// The inline buffer. enum { BufferMaxAlignment = alignof(void *) }; alignas(BufferMaxAlignment) char InlineBuffer[InlineCapacity]; - unsigned NumBytesAtAlign4, NumBytesAtAlign8; + unsigned NumBytesAtAlign4; + bool AtAlign8; public: TypeLocBuilder() : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity), - NumBytesAtAlign4(0), NumBytesAtAlign8(0) {} + NumBytesAtAlign4(0), AtAlign8(false) {} ~TypeLocBuilder() { if (Buffer != InlineBuffer) @@ -63,6 +64,10 @@ public: /// must be empty for this to work. void pushFullCopy(TypeLoc L); + /// Pushes 'T' with all locations pointing to 'Loc'. + /// The builder must be empty for this to work. + void pushTrivial(ASTContext &Context, QualType T, SourceLocation Loc); + /// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs /// previously retrieved from this builder. TypeSpecTypeLoc pushTypeSpec(QualType T) { @@ -77,7 +82,8 @@ public: LastTy = QualType(); #endif Index = Capacity; - NumBytesAtAlign4 = NumBytesAtAlign8 = 0; + NumBytesAtAlign4 = 0; + AtAlign8 = false; } /// Tell the TypeLocBuilder that the type it is storing has been diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h index 24b7342b3fb4..580d702f96fe 100644 --- a/clang/lib/Sema/UsedDeclVisitor.h +++ b/clang/lib/Sema/UsedDeclVisitor.h @@ -82,11 +82,28 @@ public: void VisitCXXConstructExpr(CXXConstructExpr *E) { asImpl().visitUsedDecl(E->getBeginLoc(), E->getConstructor()); + CXXConstructorDecl *D = E->getConstructor(); + for (const CXXCtorInitializer *Init : D->inits()) { + if (Init->isInClassMemberInitializer()) + asImpl().Visit(Init->getInit()); + } Inherited::VisitCXXConstructExpr(E); } void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { asImpl().Visit(E->getExpr()); + Inherited::VisitCXXDefaultArgExpr(E); + } + + void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { + asImpl().Visit(E->getExpr()); + Inherited::VisitCXXDefaultInitExpr(E); + } + + void VisitInitListExpr(InitListExpr *ILE) { + if (ILE->hasArrayFiller()) + asImpl().Visit(ILE->getArrayFiller()); + Inherited::VisitInitListExpr(ILE); } void visitUsedDecl(SourceLocation Loc, Decl *D) { |