diff options
Diffstat (limited to 'clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 225 |
1 files changed, 147 insertions, 78 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 22bf35dbd0cb..8bfaa46162bc 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -655,7 +655,8 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // contain the constexpr specifier. if (New->getConstexprKind() != Old->getConstexprKind()) { Diag(New->getLocation(), diag::err_constexpr_redecl_mismatch) - << New << New->getConstexprKind() << Old->getConstexprKind(); + << New << static_cast<int>(New->getConstexprKind()) + << static_cast<int>(Old->getConstexprKind()); Diag(Old->getLocation(), diag::note_previous_declaration); Invalid = true; } else if (!Old->getMostRecentDecl()->isInlined() && New->isInlined() && @@ -694,6 +695,17 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Invalid = true; } + // C++11 [temp.friend]p4 (DR329): + // When a function is defined in a friend function declaration in a class + // template, the function is instantiated when the function is odr-used. + // The same restrictions on multiple declarations and definitions that + // apply to non-template function declarations and definitions also apply + // to these implicit definitions. + const FunctionDecl *OldDefinition = nullptr; + if (New->isThisDeclarationInstantiatedFromAFriendDefinition() && + Old->isDefined(OldDefinition, true)) + CheckForFunctionRedefinition(New, OldDefinition); + return Invalid; } @@ -723,7 +735,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, Diag(Decomp.getLSquareLoc(), !getLangOpts().CPlusPlus17 ? diag::ext_decomp_decl - : D.getContext() == DeclaratorContext::ConditionContext + : D.getContext() == DeclaratorContext::Condition ? diag::ext_decomp_decl_cond : diag::warn_cxx14_compat_decomp_decl) << Decomp.getSourceRange(); @@ -890,7 +902,8 @@ static bool checkSimpleDecomposition( llvm::function_ref<ExprResult(SourceLocation, Expr *, unsigned)> GetInit) { if ((int64_t)Bindings.size() != NumElems) { S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) - << DecompType << (unsigned)Bindings.size() << NumElems.toString(10) + << DecompType << (unsigned)Bindings.size() + << (unsigned)NumElems.getLimitedValue(UINT_MAX) << NumElems.toString(10) << (NumElems < Bindings.size()); return true; } @@ -1066,8 +1079,9 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, TemplateArgumentListInfo &Args; ICEDiagnoser(LookupResult &R, TemplateArgumentListInfo &Args) : R(R), Args(Args) {} - void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) override { - S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant) + Sema::SemaDiagnosticBuilder diagnoseNotICE(Sema &S, + SourceLocation Loc) override { + return S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant) << printTemplateArgs(S.Context.getPrintingPolicy(), Args); } } Diagnoser(R, Args); @@ -1077,7 +1091,7 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, if (E.isInvalid()) return IsTupleLike::Error; - E = S.VerifyIntegerConstantExpression(E.get(), &Size, Diagnoser, false); + E = S.VerifyIntegerConstantExpression(E.get(), &Size, Diagnoser); if (E.isInvalid()) return IsTupleLike::Error; @@ -1135,8 +1149,9 @@ static bool checkTupleLikeDecomposition(Sema &S, const llvm::APSInt &TupleSize) { if ((int64_t)Bindings.size() != TupleSize) { S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) - << DecompType << (unsigned)Bindings.size() << TupleSize.toString(10) - << (TupleSize < Bindings.size()); + << DecompType << (unsigned)Bindings.size() + << (unsigned)TupleSize.getLimitedValue(UINT_MAX) + << TupleSize.toString(10) << (TupleSize < Bindings.size()); return true; } @@ -1184,7 +1199,8 @@ static bool checkTupleLikeDecomposition(Sema &S, // an xvalue otherwise if (!Src->getType()->isLValueReferenceType()) E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), CK_NoOp, - E.get(), nullptr, VK_XValue); + E.get(), nullptr, VK_XValue, + FPOptionsOverride()); TemplateArgumentListInfo Args(Loc, Loc); Args.addArgument( @@ -1248,8 +1264,7 @@ static bool checkTupleLikeDecomposition(Sema &S, if (E.isInvalid()) return true; RefVD->setInit(E.get()); - if (!E.get()->isValueDependent()) - RefVD->checkInitIsICE(); + S.CheckCompleteVariableDeclaration(RefVD); E = S.BuildDeclarationNameExpr(CXXScopeSpec(), DeclarationNameInfo(B->getDeclName(), Loc), @@ -1360,7 +1375,7 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, [](FieldDecl *FD) { return !FD->isUnnamedBitfield(); }); assert(Bindings.size() != NumFields); S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) - << DecompType << (unsigned)Bindings.size() << NumFields + << DecompType << (unsigned)Bindings.size() << NumFields << NumFields << (NumFields < Bindings.size()); return true; }; @@ -1373,11 +1388,23 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, if (FD->isUnnamedBitfield()) continue; - if (FD->isAnonymousStructOrUnion()) { - S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member) - << DecompType << FD->getType()->isUnionType(); - S.Diag(FD->getLocation(), diag::note_declared_at); - return true; + // All the non-static data members are required to be nameable, so they + // must all have names. + if (!FD->getDeclName()) { + if (RD->isLambda()) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_lambda); + S.Diag(RD->getLocation(), diag::note_lambda_decl); + return true; + } + + if (FD->isAnonymousStructOrUnion()) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member) + << DecompType << FD->getType()->isUnionType(); + S.Diag(FD->getLocation(), diag::note_declared_at); + return true; + } + + // FIXME: Are there any other ways we could have an anonymous member? } // We have a real field to bind. @@ -1618,7 +1645,7 @@ static bool CheckConstexprDestructorSubobjects(Sema &SemaRef, if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.Diag(DD->getLocation(), diag::err_constexpr_dtor_subobject) - << DD->getConstexprKind() << !FD + << static_cast<int>(DD->getConstexprKind()) << !FD << (FD ? FD->getDeclName() : DeclarationName()) << T; SemaRef.Diag(Loc, diag::note_constexpr_dtor_subobject) << !FD << (FD ? FD->getDeclName() : DeclarationName()) << T; @@ -2588,7 +2615,7 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute ? (unsigned)diag::warn_unknown_attribute_ignored : (unsigned)diag::err_base_specifier_attribute) - << AL; + << AL << AL.getRange(); } TypeSourceInfo *TInfo = nullptr; @@ -3577,8 +3604,10 @@ namespace { Base = SubME->getBase(); } - if (!isa<CXXThisExpr>(Base->IgnoreParenImpCasts())) + if (!isa<CXXThisExpr>(Base->IgnoreParenImpCasts())) { + Visit(Base); return; + } if (AddressOf && AllPODFields) return; @@ -3905,9 +3934,22 @@ void Sema::ActOnStartTrailingRequiresClause(Scope *S, Declarator &D) { } ExprResult Sema::ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr) { + return ActOnRequiresClause(ConstraintExpr); +} + +ExprResult Sema::ActOnRequiresClause(ExprResult ConstraintExpr) { + if (ConstraintExpr.isInvalid()) + return ExprError(); + + ConstraintExpr = CorrectDelayedTyposInExpr(ConstraintExpr); if (ConstraintExpr.isInvalid()) return ExprError(); - return CorrectDelayedTyposInExpr(ConstraintExpr); + + if (DiagnoseUnexpandedParameterPack(ConstraintExpr.get(), + UPPC_RequiresClause)) + return ExprError(); + + return ConstraintExpr; } /// This is invoked after parsing an in-class initializer for a @@ -5478,8 +5520,9 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, // Bases. for (const auto &Base : ClassDecl->bases()) { - // Bases are always records in a well-formed non-dependent class. const RecordType *RT = Base.getType()->getAs<RecordType>(); + if (!RT) + continue; // Remember direct virtual bases. if (Base.isVirtual()) { @@ -5869,13 +5912,22 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { // The function will be passed to the consumer when its definition is // encountered. - } else if (!MD->isTrivial() || MD->isExplicitlyDefaulted() || + } else if (MD->isExplicitlyDefaulted()) { + // Synthesize and instantiate explicitly defaulted methods. + S.MarkFunctionReferenced(Class->getLocation(), MD); + + if (TSK != TSK_ExplicitInstantiationDefinition) { + // Except for explicit instantiation defs, we will not see the + // definition again later, so pass it to the consumer now. + S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); + } + } else if (!MD->isTrivial() || MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) { - // Synthesize and instantiate non-trivial implicit methods, explicitly - // defaulted methods, and the copy and move assignment operators. The - // latter are exported even if they are trivial, because the address of - // an operator can be taken and should compare equal across libraries. + // Synthesize and instantiate non-trivial implicit methods, and the copy + // and move assignment operators. The latter are exported even if they + // are trivial, because the address of an operator can be taken and + // should compare equal across libraries. S.MarkFunctionReferenced(Class->getLocation(), MD); // There is no later point when we will see the definition of this @@ -6056,7 +6108,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { Attr *ClassAttr = getDLLAttr(Class); // MSVC inherits DLL attributes to partial class template specializations. - if (Context.getTargetInfo().getCXXABI().isMicrosoft() && !ClassAttr) { + if (Context.getTargetInfo().shouldDLLImportComdatSymbols() && !ClassAttr) { if (auto *Spec = dyn_cast<ClassTemplatePartialSpecializationDecl>(Class)) { if (Attr *TemplateAttr = getDLLAttr(Spec->getSpecializedTemplate()->getTemplatedDecl())) { @@ -6076,7 +6128,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { return; } - if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + if (Context.getTargetInfo().shouldDLLImportComdatSymbols() && !ClassAttr->isInherited()) { // Diagnose dll attributes on members of class with dll attribute. for (Decl *Member : Class->decls()) { @@ -6141,8 +6193,7 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { if (MD->isInlined()) { // MinGW does not import or export inline methods. But do it for // template instantiations. - if (!Context.getTargetInfo().getCXXABI().isMicrosoft() && - !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment() && + if (!Context.getTargetInfo().shouldDLLImportComdatSymbols() && TSK != TSK_ExplicitInstantiationDeclaration && TSK != TSK_ExplicitInstantiationDefinition) continue; @@ -7331,9 +7382,10 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, // If a function is explicitly defaulted on its first declaration, it is // implicitly considered to be constexpr if the implicit declaration // would be. - MD->setConstexprKind( - Constexpr ? (MD->isConsteval() ? CSK_consteval : CSK_constexpr) - : CSK_unspecified); + MD->setConstexprKind(Constexpr ? (MD->isConsteval() + ? ConstexprSpecKind::Consteval + : ConstexprSpecKind::Constexpr) + : ConstexprSpecKind::Unspecified); if (!Type->hasExceptionSpec()) { // C++2a [except.spec]p3: @@ -8022,10 +8074,10 @@ private: if (ReturnFalse.isInvalid()) return StmtError(); - return S.ActOnIfStmt(Loc, false, nullptr, + return S.ActOnIfStmt(Loc, false, Loc, nullptr, S.ActOnCondition(nullptr, Loc, NotCond.get(), Sema::ConditionKind::Boolean), - ReturnFalse.get(), SourceLocation(), nullptr); + Loc, ReturnFalse.get(), SourceLocation(), nullptr); } StmtResult visitSubobjectArray(QualType Type, llvm::APInt Size, @@ -8177,9 +8229,9 @@ private: return StmtError(); // if (...) - return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, InitStmt, Cond, - ReturnStmt.get(), /*ElseLoc=*/SourceLocation(), - /*Else=*/nullptr); + return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, Loc, InitStmt, Cond, Loc, + ReturnStmt.get(), + /*ElseLoc=*/SourceLocation(), /*Else=*/nullptr); } case DefaultedComparisonKind::NotEqual: @@ -8212,7 +8264,7 @@ static void lookupOperatorsForDefaultedComparison(Sema &Self, Scope *S, UnresolvedSetImpl &Operators, OverloadedOperatorKind Op) { auto Lookup = [&](OverloadedOperatorKind OO) { - Self.LookupOverloadedOperatorName(OO, S, QualType(), QualType(), Operators); + Self.LookupOverloadedOperatorName(OO, S, Operators); }; // Every defaulted operator looks up itself. @@ -8425,7 +8477,7 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, // FIXME: Only applying this to the first declaration seems problematic, as // simple reorderings can affect the meaning of the program. if (First && !FD->isConstexpr() && Info.Constexpr) - FD->setConstexprKind(CSK_constexpr); + FD->setConstexprKind(ConstexprSpecKind::Constexpr); // C++2a [except.spec]p3: // If a declaration of a function does not have a noexcept-specifier @@ -9399,7 +9451,8 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, // brace-or-equal-initializer if (CSM == Sema::CXXDefaultConstructor && FI->hasInClassInitializer()) { if (Diagnose) - S.Diag(FI->getLocation(), diag::note_nontrivial_in_class_init) << FI; + S.Diag(FI->getLocation(), diag::note_nontrivial_default_member_init) + << FI; return false; } @@ -11106,8 +11159,8 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind, // Attempt to diagnose reasons why the STL definition of this type // might be foobar, including it failing to be a constant expression. // TODO Handle more ways the lookup or result can be invalid. - if (!VD->isStaticDataMember() || !VD->isConstexpr() || !VD->hasInit() || - !VD->checkInitIsICE()) + if (!VD->isStaticDataMember() || + !VD->isUsableInConstantExpressions(Context)) return UnsupportedSTLError(USS_InvalidMember, MemName, VD); // Attempt to evaluate the var decl as a constant expression and extract @@ -12936,7 +12989,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(), /*TInfo=*/nullptr, ExplicitSpecifier(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, - Constexpr ? CSK_constexpr : CSK_unspecified); + Constexpr ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); DefaultCon->setAccess(AS_public); DefaultCon->setDefaulted(); @@ -13057,7 +13111,7 @@ Sema::findInheritingConstructor(SourceLocation Loc, Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo, BaseCtor->getExplicitSpecifier(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, - Constexpr ? BaseCtor->getConstexprKind() : CSK_unspecified, + Constexpr ? BaseCtor->getConstexprKind() : ConstexprSpecKind::Unspecified, InheritedConstructor(Shadow, BaseCtor), BaseCtor->getTrailingRequiresClause()); if (Shadow->isInvalidDecl()) @@ -13214,7 +13268,8 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, QualType(), nullptr, /*isInline=*/true, /*isImplicitlyDeclared=*/true, - Constexpr ? CSK_constexpr : CSK_unspecified); + Constexpr ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); Destructor->setAccess(AS_public); Destructor->setDefaulted(); @@ -13849,7 +13904,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, /*StorageClass=*/SC_None, - /*isInline=*/true, Constexpr ? CSK_constexpr : CSK_unspecified, + /*isInline=*/true, + Constexpr ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified, SourceLocation()); CopyAssignment->setAccess(AS_public); CopyAssignment->setDefaulted(); @@ -14174,7 +14230,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { CXXMethodDecl *MoveAssignment = CXXMethodDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, /*StorageClass=*/SC_None, - /*isInline=*/true, Constexpr ? CSK_constexpr : CSK_unspecified, + /*isInline=*/true, + Constexpr ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified, SourceLocation()); MoveAssignment->setAccess(AS_public); MoveAssignment->setDefaulted(); @@ -14558,7 +14615,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ExplicitSpecifier(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, - Constexpr ? CSK_constexpr : CSK_unspecified); + Constexpr ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); CopyConstructor->setAccess(AS_public); CopyConstructor->setDefaulted(); @@ -14691,7 +14749,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( ExplicitSpecifier(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, - Constexpr ? CSK_constexpr : CSK_unspecified); + Constexpr ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); MoveConstructor->setAccess(AS_public); MoveConstructor->setDefaulted(); @@ -14793,9 +14852,13 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( SynthesizedFunctionScope Scope(*this, Conv); assert(!Conv->getReturnType()->isUndeducedType()); + QualType ConvRT = Conv->getType()->getAs<FunctionType>()->getReturnType(); + CallingConv CC = + ConvRT->getPointeeType()->getAs<FunctionType>()->getCallConv(); + CXXRecordDecl *Lambda = Conv->getParent(); FunctionDecl *CallOp = Lambda->getLambdaCallOperator(); - FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker(); + FunctionDecl *Invoker = Lambda->getLambdaStaticInvoker(CC); if (auto *TemplateArgs = Conv->getTemplateSpecializationArgs()) { CallOp = InstantiateFunctionDeclaration( @@ -14866,9 +14929,9 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( // (since it's unusable otherwise); in the case where we inline the // block literal, it has block literal lifetime semantics. if (!BuildBlock.isInvalid() && !getLangOpts().ObjCAutoRefCount) - BuildBlock = ImplicitCastExpr::Create(Context, BuildBlock.get()->getType(), - CK_CopyAndAutoreleaseBlockObject, - BuildBlock.get(), nullptr, VK_RValue); + BuildBlock = ImplicitCastExpr::Create( + Context, BuildBlock.get()->getType(), CK_CopyAndAutoreleaseBlockObject, + BuildBlock.get(), nullptr, VK_RValue, FPOptionsOverride()); if (BuildBlock.isInvalid()) { Diag(CurrentLocation, diag::note_lambda_to_block_conv); @@ -15032,24 +15095,14 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { DeclContext::lookup_result Lookup = ClassPattern->lookup(Field->getDeclName()); - // Lookup can return at most two results: the pattern for the field, or the - // injected class name of the parent record. No other member can have the - // same name as the field. - // In modules mode, lookup can return multiple results (coming from - // different modules). - assert((getLangOpts().Modules || (!Lookup.empty() && Lookup.size() <= 2)) && - "more than two lookup results for field name"); - FieldDecl *Pattern = dyn_cast<FieldDecl>(Lookup[0]); - if (!Pattern) { - assert(isa<CXXRecordDecl>(Lookup[0]) && - "cannot have other non-field member with same name"); - for (auto L : Lookup) - if (isa<FieldDecl>(L)) { - Pattern = cast<FieldDecl>(L); - break; - } - assert(Pattern && "We must have set the Pattern!"); + 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, @@ -15076,9 +15129,10 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { // 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_in_class_initializer_not_yet_parsed) + Diag(Loc, diag::err_default_member_initializer_not_yet_parsed) << OutermostClass << Field; - Diag(Field->getEndLoc(), diag::note_in_class_initializer_not_yet_parsed); + 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(); @@ -15503,6 +15557,18 @@ checkLiteralOperatorTemplateParameterList(Sema &SemaRef, SemaRef.Context.hasSameType(PmDecl->getType(), SemaRef.Context.CharTy)) return false; + // C++20 [over.literal]p5: + // A string literal operator template is a literal operator template + // whose template-parameter-list comprises a single non-type + // template-parameter of class type. + // + // As a DR resolution, we also allow placeholders for deduced class + // template specializations. + if (SemaRef.getLangOpts().CPlusPlus20 && + !PmDecl->isTemplateParameterPack() && + (PmDecl->getType()->isRecordType() || + PmDecl->getType()->getAs<DeducedTemplateSpecializationType>())) + return false; } else if (TemplateParams->size() == 2) { TemplateTypeParmDecl *PmType = dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(0)); @@ -15559,6 +15625,8 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { // template <char...> type operator "" name() and // template <class T, T...> type operator "" name() are the only valid // template signatures, and the only valid signatures with no parameters. + // + // C++20 also allows template <SomeClass T> type operator "" name(). if (TpDecl) { if (FnDecl->param_size() != 0) { Diag(FnDecl->getLocation(), @@ -15988,9 +16056,10 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, AssertExpr = FullAssertExpr.get(); llvm::APSInt Cond; - if (!Failed && VerifyIntegerConstantExpression(AssertExpr, &Cond, - diag::err_static_assert_expression_is_not_constant, - /*AllowFold=*/false).isInvalid()) + if (!Failed && VerifyIntegerConstantExpression( + AssertExpr, &Cond, + diag::err_static_assert_expression_is_not_constant) + .isInvalid()) Failed = true; if (!Failed && !Cond) { @@ -16282,7 +16351,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // Try to convert the decl specifier to a type. This works for // friend templates because ActOnTag never produces a ClassTemplateDecl // for a TUK_Friend. - Declarator TheDeclarator(DS, DeclaratorContext::MemberContext); + Declarator TheDeclarator(DS, DeclaratorContext::Member); TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator, S); QualType T = TSI->getType(); if (TheDeclarator.isInvalidType()) |