diff options
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 118 |
1 files changed, 84 insertions, 34 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index af174ac1ca1a..7be71ca49ea2 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10268,13 +10268,9 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S, const FunctionDecl *FD, const FunctionDecl *CausedFD, MultiVersionKind MVType) { - bool IsCPUSpecificCPUDispatchMVType = - MVType == MultiVersionKind::CPUDispatch || - MVType == MultiVersionKind::CPUSpecific; - const auto Diagnose = [FD, CausedFD, IsCPUSpecificCPUDispatchMVType]( - Sema &S, const Attr *A) { + const auto Diagnose = [FD, CausedFD, MVType](Sema &S, const Attr *A) { S.Diag(FD->getLocation(), diag::err_multiversion_disallowed_other_attr) - << IsCPUSpecificCPUDispatchMVType << A; + << static_cast<unsigned>(MVType) << A; if (CausedFD) S.Diag(CausedFD->getLocation(), diag::note_multiversioning_caused_here); return true; @@ -10292,6 +10288,10 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S, if (MVType != MultiVersionKind::Target) return Diagnose(S, A); break; + case attr::TargetClones: + if (MVType != MultiVersionKind::TargetClones) + return Diagnose(S, A); + break; default: if (!AttrCompatibleWithMultiVersion(A->getKind(), MVType)) return Diagnose(S, A); @@ -10318,6 +10318,7 @@ bool Sema::areMultiversionVariantFunctionsCompatible( DefaultedFuncs = 6, ConstexprFuncs = 7, ConstevalFuncs = 8, + Lambda = 9, }; enum Different { CallingConv = 0, @@ -10445,7 +10446,7 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, S.PDiag(diag::note_multiversioning_caused_here)), PartialDiagnosticAt(NewFD->getLocation(), S.PDiag(diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType), + << static_cast<unsigned>(MVType)), PartialDiagnosticAt(NewFD->getLocation(), S.PDiag(diag::err_multiversion_diff)), /*TemplatesSupported=*/false, @@ -10574,21 +10575,30 @@ static bool CheckTargetCausesMultiVersioning( return false; } +static bool MultiVersionTypesCompatible(MultiVersionKind Old, + MultiVersionKind New) { + if (Old == New || Old == MultiVersionKind::None || + New == MultiVersionKind::None) + return true; + + return (Old == MultiVersionKind::CPUDispatch && + New == MultiVersionKind::CPUSpecific) || + (Old == MultiVersionKind::CPUSpecific && + New == MultiVersionKind::CPUDispatch); +} + /// Check the validity of a new function declaration being added to an existing /// multiversioned declaration collection. static bool CheckMultiVersionAdditionalDecl( Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, MultiVersionKind NewMVType, const TargetAttr *NewTA, const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec, - bool &Redeclaration, NamedDecl *&OldDecl, bool &MergeTypeWithPrevious, - LookupResult &Previous) { + const TargetClonesAttr *NewClones, bool &Redeclaration, NamedDecl *&OldDecl, + bool &MergeTypeWithPrevious, LookupResult &Previous) { MultiVersionKind OldMVType = OldFD->getMultiVersionKind(); // Disallow mixing of multiversioning types. - if ((OldMVType == MultiVersionKind::Target && - NewMVType != MultiVersionKind::Target) || - (NewMVType == MultiVersionKind::Target && - OldMVType != MultiVersionKind::Target)) { + if (!MultiVersionTypesCompatible(OldMVType, NewMVType)) { S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed); S.Diag(OldFD->getLocation(), diag::note_previous_declaration); NewFD->setInvalidDecl(); @@ -10613,7 +10623,12 @@ static bool CheckMultiVersionAdditionalDecl( if (S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) continue; - if (NewMVType == MultiVersionKind::Target) { + switch (NewMVType) { + case MultiVersionKind::None: + assert(OldMVType == MultiVersionKind::TargetClones && + "Only target_clones can be omitted in subsequent declarations"); + break; + case MultiVersionKind::Target: { const auto *CurTA = CurFD->getAttr<TargetAttr>(); if (CurTA->getFeaturesStr() == NewTA->getFeaturesStr()) { NewFD->setIsMultiVersion(); @@ -10629,7 +10644,30 @@ static bool CheckMultiVersionAdditionalDecl( NewFD->setInvalidDecl(); return true; } - } else { + break; + } + case MultiVersionKind::TargetClones: { + const auto *CurClones = CurFD->getAttr<TargetClonesAttr>(); + Redeclaration = true; + OldDecl = CurFD; + MergeTypeWithPrevious = true; + NewFD->setIsMultiVersion(); + + if (CurClones && NewClones && + (CurClones->featuresStrs_size() != NewClones->featuresStrs_size() || + !std::equal(CurClones->featuresStrs_begin(), + CurClones->featuresStrs_end(), + NewClones->featuresStrs_begin()))) { + S.Diag(NewFD->getLocation(), diag::err_target_clone_doesnt_match); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + + return false; + } + case MultiVersionKind::CPUSpecific: + case MultiVersionKind::CPUDispatch: { const auto *CurCPUSpec = CurFD->getAttr<CPUSpecificAttr>(); const auto *CurCPUDisp = CurFD->getAttr<CPUDispatchAttr>(); // Handle CPUDispatch/CPUSpecific versions. @@ -10684,8 +10722,8 @@ static bool CheckMultiVersionAdditionalDecl( } } } - // If the two decls aren't the same MVType, there is no possible error - // condition. + break; + } } } @@ -10721,7 +10759,6 @@ static bool CheckMultiVersionAdditionalDecl( return false; } - /// Check the validity of a mulitversion function declaration. /// Also sets the multiversion'ness' of the function itself. /// @@ -10735,23 +10772,14 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, const auto *NewTA = NewFD->getAttr<TargetAttr>(); const auto *NewCPUDisp = NewFD->getAttr<CPUDispatchAttr>(); const auto *NewCPUSpec = NewFD->getAttr<CPUSpecificAttr>(); - - // Mixing Multiversioning types is prohibited. - if ((NewTA && NewCPUDisp) || (NewTA && NewCPUSpec) || - (NewCPUDisp && NewCPUSpec)) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed); - NewFD->setInvalidDecl(); - return true; - } - - MultiVersionKind MVType = NewFD->getMultiVersionKind(); + const auto *NewClones = NewFD->getAttr<TargetClonesAttr>(); + MultiVersionKind MVType = 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. if (NewFD->isMain()) { - if ((MVType == MultiVersionKind::Target && NewTA->isDefaultVersion()) || - MVType == MultiVersionKind::CPUDispatch || - MVType == MultiVersionKind::CPUSpecific) { + if (MVType != MultiVersionKind::None && + !(MVType == MultiVersionKind::Target && !NewTA->isDefaultVersion())) { S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main); NewFD->setInvalidDecl(); return true; @@ -10774,13 +10802,35 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, if (!OldFD->isMultiVersion() && MVType == MultiVersionKind::None) return false; - if (OldFD->isMultiVersion() && MVType == MultiVersionKind::None) { + // Multiversioned redeclarations aren't allowed to omit the attribute, except + // for target_clones. + if (OldFD->isMultiVersion() && MVType == MultiVersionKind::None && + OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones) { S.Diag(NewFD->getLocation(), diag::err_multiversion_required_in_redecl) << (OldFD->getMultiVersionKind() != MultiVersionKind::Target); NewFD->setInvalidDecl(); return true; } + if (!OldFD->isMultiVersion()) { + switch (MVType) { + case MultiVersionKind::Target: + return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA, + Redeclaration, OldDecl, + MergeTypeWithPrevious, Previous); + case MultiVersionKind::TargetClones: + if (OldFD->isUsed(false)) { + NewFD->setInvalidDecl(); + return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used); + } + OldFD->setIsMultiVersion(); + break; + case MultiVersionKind::CPUDispatch: + case MultiVersionKind::CPUSpecific: + case MultiVersionKind::None: + break; + } + } // Handle the target potentially causes multiversioning case. if (!OldFD->isMultiVersion() && MVType == MultiVersionKind::Target) return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA, @@ -10791,8 +10841,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, // appropriate attribute in the current function decl. Resolve that these are // still compatible with previous declarations. return CheckMultiVersionAdditionalDecl( - S, OldFD, NewFD, MVType, NewTA, NewCPUDisp, NewCPUSpec, Redeclaration, - OldDecl, MergeTypeWithPrevious, Previous); + S, OldFD, NewFD, MVType, NewTA, NewCPUDisp, NewCPUSpec, NewClones, + Redeclaration, OldDecl, MergeTypeWithPrevious, Previous); } /// Perform semantic checking of a new function declaration. |