erichkeane created this revision. erichkeane added reviewers: rnk, echristo, aaron.ballman, rsmith. Herald added subscribers: mgrang, mgorny.
I'm currently working on the cpu_dispatch and cpu_specific multiversion support, which is making this functionality require a significant amount of functions. It seems that it would be easier to refactor this and add additional mechanisms if unencumbered by the rest of SemaDecl (which itself is getting quite large). Repository: rC Clang https://reviews.llvm.org/D43628 Files: include/clang/Sema/Sema.h lib/Sema/CMakeLists.txt lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclMultiVersion.cpp
Index: lib/Sema/SemaDeclMultiVersion.cpp =================================================================== --- lib/Sema/SemaDeclMultiVersion.cpp +++ lib/Sema/SemaDeclMultiVersion.cpp @@ -0,0 +1,353 @@ +//==SemaDeclMultiVersion.cpp - Semantic Analysis for MultiVersion Functions===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for MultiVersion Function +// Declarations. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaInternal.h" + +using namespace clang; +using namespace sema; + +/// \brief Check the target 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"); + TargetAttr::ParsedTargetAttr ParseInfo = TA->parse(); + 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] == '-') { + 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; + } + } + return false; +} + +static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, + const FunctionDecl *NewFD, + bool CausesMV) { + enum DoesntSupport { + FuncTemplates = 0, + VirtFuncs = 1, + DeducedReturn = 2, + Constructors = 3, + Destructors = 4, + DeletedFuncs = 5, + DefaultedFuncs = 6 + }; + enum Different { + CallingConv = 0, + ReturnType = 1, + ConstexprSpec = 2, + InlineSpec = 3, + StorageClass = 4, + Linkage = 5 + }; + + // For now, disallow all other attributes. These should be opt-in, but + // an analysis of all of them is a future FIXME. + if (CausesMV && OldFD && + std::distance(OldFD->attr_begin(), OldFD->attr_end()) != 1) { + S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs); + S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + return true; + } + + if (std::distance(NewFD->attr_begin(), NewFD->attr_end()) != 1) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs); + + if (NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) + << FuncTemplates; + + if (const auto *NewCXXFD = dyn_cast<CXXMethodDecl>(NewFD)) { + if (NewCXXFD->isVirtual()) + return S.Diag(NewCXXFD->getLocation(), + diag::err_multiversion_doesnt_support) + << VirtFuncs; + + if (const auto *NewCXXCtor = dyn_cast<CXXConstructorDecl>(NewFD)) + return S.Diag(NewCXXCtor->getLocation(), + diag::err_multiversion_doesnt_support) + << Constructors; + + if (const auto *NewCXXDtor = dyn_cast<CXXDestructorDecl>(NewFD)) + return S.Diag(NewCXXDtor->getLocation(), + diag::err_multiversion_doesnt_support) + << Destructors; + } + + if (NewFD->isDeleted()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) + << DeletedFuncs; + + if (NewFD->isDefaulted()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) + << DefaultedFuncs; + + QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType()); + const auto *NewType = cast<FunctionType>(NewQType); + QualType NewReturnType = NewType->getReturnType(); + + if (NewReturnType->isUndeducedType()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) + << DeducedReturn; + + // Only allow transition to MultiVersion if it hasn't been used. + if (OldFD && CausesMV && OldFD->isUsed(false)) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used); + + // Ensure the return type is identical. + if (OldFD) { + QualType OldQType = S.getASTContext().getCanonicalType(OldFD->getType()); + const auto *OldType = cast<FunctionType>(OldQType); + FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); + FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); + + if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << CallingConv; + + QualType OldReturnType = OldType->getReturnType(); + + if (OldReturnType != NewReturnType) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << ReturnType; + + if (OldFD->isConstexpr() != NewFD->isConstexpr()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << ConstexprSpec; + + if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << InlineSpec; + + if (OldFD->getStorageClass() != NewFD->getStorageClass()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << StorageClass; + + if (OldFD->isExternC() != NewFD->isExternC()) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) + << Linkage; + + if (S.CheckEquivalentExceptionSpec( + OldFD->getType()->getAs<FunctionProtoType>(), OldFD->getLocation(), + NewFD->getType()->getAs<FunctionProtoType>(), NewFD->getLocation())) + return true; + } + return false; +} + +/// \brief Check the validity of a mulitversion function declaration. +/// Also sets the multiversion'ness' of the function itself. +/// +/// This sets NewFD->isInvalidDecl() to true if there was an error. +/// +/// Returns true if there was an error, false otherwise. +bool Sema::CheckMultiVersionFunction(FunctionDecl *NewFD, + bool &Redeclaration, NamedDecl *&OldDecl, + bool &MergeTypeWithPrevious, + LookupResult &Previous) { + const auto *NewTA = NewFD->getAttr<TargetAttr>(); + if (NewFD->isMain()) { + if (NewTA && NewTA->isDefaultVersion()) { + Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main); + NewFD->setInvalidDecl(); + return true; + } + return false; + } + + // If there is no matching previous decl, only 'default' can + // cause MultiVersioning. + if (!OldDecl) { + if (NewTA && NewTA->isDefaultVersion()) { + if (!NewFD->getType()->getAs<FunctionProtoType>()) { + Diag(NewFD->getLocation(), diag::err_multiversion_noproto); + NewFD->setInvalidDecl(); + return true; + } + if (CheckMultiVersionAdditionalRules(*this, nullptr, NewFD, true)) { + NewFD->setInvalidDecl(); + return true; + } + if (!getASTContext().getTargetInfo().supportsMultiVersioning()) { + Diag(NewFD->getLocation(), diag::err_multiversion_not_supported); + NewFD->setInvalidDecl(); + return true; + } + + NewFD->setIsMultiVersion(); + } + return false; + } + + if (OldDecl->getDeclContext()->getRedeclContext() != + NewFD->getDeclContext()->getRedeclContext()) + return false; + + FunctionDecl *OldFD = OldDecl->getAsFunction(); + // Unresolved 'using' statements (the other way OldDecl can be not a function) + // likely cannot cause a problem here. + if (!OldFD) + return false; + + if (!OldFD->isMultiVersion() && !NewTA) + return false; + + if (OldFD->isMultiVersion() && !NewTA) { + Diag(NewFD->getLocation(), diag::err_target_required_in_redecl); + NewFD->setInvalidDecl(); + return true; + } + + TargetAttr::ParsedTargetAttr NewParsed = NewTA->parse(); + // Sort order doesn't matter, it just needs to be consistent. + std::sort(NewParsed.Features.begin(), NewParsed.Features.end()); + + const auto *OldTA = OldFD->getAttr<TargetAttr>(); + if (!OldFD->isMultiVersion()) { + // If the old decl is NOT MultiVersioned yet, and we don't cause that + // to change, this is a simple redeclaration. + if (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()) + return false; + + // Otherwise, this decl causes MultiVersioning. + if (!getASTContext().getTargetInfo().supportsMultiVersioning()) { + Diag(NewFD->getLocation(), diag::err_multiversion_not_supported); + Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + + if (!OldFD->getType()->getAs<FunctionProtoType>()) { + Diag(OldFD->getLocation(), diag::err_multiversion_noproto); + Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + NewFD->setInvalidDecl(); + return true; + } + + if (CheckMultiVersionValue(*this, NewFD)) { + NewFD->setInvalidDecl(); + return true; + } + + if (CheckMultiVersionValue(*this, OldFD)) { + Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + NewFD->setInvalidDecl(); + return true; + } + + TargetAttr::ParsedTargetAttr OldParsed = + OldTA->parse(std::less<std::string>()); + + if (OldParsed == NewParsed) { + Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + + for (const auto *FD : OldFD->redecls()) { + const auto *CurTA = FD->getAttr<TargetAttr>(); + if (!CurTA || CurTA->isInherited()) { + Diag(FD->getLocation(), diag::err_target_required_in_redecl); + Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + NewFD->setInvalidDecl(); + return true; + } + } + + if (CheckMultiVersionAdditionalRules(*this, OldFD, NewFD, true)) { + NewFD->setInvalidDecl(); + return true; + } + + OldFD->setIsMultiVersion(); + NewFD->setIsMultiVersion(); + Redeclaration = false; + MergeTypeWithPrevious = false; + OldDecl = nullptr; + Previous.clear(); + return false; + } + + bool UseMemberUsingDeclRules = + CurContext->isRecord() && !NewFD->getFriendObjectKind(); + + // Next, check ALL 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) + continue; + if (IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) + continue; + + const auto *CurTA = CurFD->getAttr<TargetAttr>(); + if (CurTA->getFeaturesStr() == NewTA->getFeaturesStr()) { + NewFD->setIsMultiVersion(); + Redeclaration = true; + OldDecl = ND; + return false; + } + + TargetAttr::ParsedTargetAttr CurParsed = + CurTA->parse(std::less<std::string>()); + + if (CurParsed == NewParsed) { + Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } + + // Else, this is simply a non-redecl case. + if (CheckMultiVersionValue(*this, NewFD)) { + NewFD->setInvalidDecl(); + return true; + } + + if (CheckMultiVersionAdditionalRules(*this, OldFD, NewFD, false)) { + NewFD->setInvalidDecl(); + return true; + } + + NewFD->setIsMultiVersion(); + Redeclaration = false; + MergeTypeWithPrevious = false; + OldDecl = nullptr; + Previous.clear(); + return false; +} Index: lib/Sema/CMakeLists.txt =================================================================== --- lib/Sema/CMakeLists.txt +++ lib/Sema/CMakeLists.txt @@ -31,6 +31,7 @@ SemaDecl.cpp SemaDeclAttr.cpp SemaDeclCXX.cpp + SemaDeclMultiVersion.cpp SemaDeclObjC.cpp SemaExceptionSpec.cpp SemaExpr.cpp Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -9159,341 +9159,6 @@ D->getFriendObjectKind() != Decl::FOK_None); } -/// \brief Check the target 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"); - TargetAttr::ParsedTargetAttr ParseInfo = TA->parse(); - 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] == '-') { - 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; - } - } - return false; -} - -static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, - const FunctionDecl *NewFD, - bool CausesMV) { - enum DoesntSupport { - FuncTemplates = 0, - VirtFuncs = 1, - DeducedReturn = 2, - Constructors = 3, - Destructors = 4, - DeletedFuncs = 5, - DefaultedFuncs = 6 - }; - enum Different { - CallingConv = 0, - ReturnType = 1, - ConstexprSpec = 2, - InlineSpec = 3, - StorageClass = 4, - Linkage = 5 - }; - - // For now, disallow all other attributes. These should be opt-in, but - // an analysis of all of them is a future FIXME. - if (CausesMV && OldFD && - std::distance(OldFD->attr_begin(), OldFD->attr_end()) != 1) { - S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs); - S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); - return true; - } - - if (std::distance(NewFD->attr_begin(), NewFD->attr_end()) != 1) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs); - - if (NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << FuncTemplates; - - if (const auto *NewCXXFD = dyn_cast<CXXMethodDecl>(NewFD)) { - if (NewCXXFD->isVirtual()) - return S.Diag(NewCXXFD->getLocation(), - diag::err_multiversion_doesnt_support) - << VirtFuncs; - - if (const auto *NewCXXCtor = dyn_cast<CXXConstructorDecl>(NewFD)) - return S.Diag(NewCXXCtor->getLocation(), - diag::err_multiversion_doesnt_support) - << Constructors; - - if (const auto *NewCXXDtor = dyn_cast<CXXDestructorDecl>(NewFD)) - return S.Diag(NewCXXDtor->getLocation(), - diag::err_multiversion_doesnt_support) - << Destructors; - } - - if (NewFD->isDeleted()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << DeletedFuncs; - - if (NewFD->isDefaulted()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << DefaultedFuncs; - - QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType()); - const auto *NewType = cast<FunctionType>(NewQType); - QualType NewReturnType = NewType->getReturnType(); - - if (NewReturnType->isUndeducedType()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << DeducedReturn; - - // Only allow transition to MultiVersion if it hasn't been used. - if (OldFD && CausesMV && OldFD->isUsed(false)) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used); - - // Ensure the return type is identical. - if (OldFD) { - QualType OldQType = S.getASTContext().getCanonicalType(OldFD->getType()); - const auto *OldType = cast<FunctionType>(OldQType); - FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); - FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); - - if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << CallingConv; - - QualType OldReturnType = OldType->getReturnType(); - - if (OldReturnType != NewReturnType) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << ReturnType; - - if (OldFD->isConstexpr() != NewFD->isConstexpr()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << ConstexprSpec; - - if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << InlineSpec; - - if (OldFD->getStorageClass() != NewFD->getStorageClass()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << StorageClass; - - if (OldFD->isExternC() != NewFD->isExternC()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << Linkage; - - if (S.CheckEquivalentExceptionSpec( - OldFD->getType()->getAs<FunctionProtoType>(), OldFD->getLocation(), - NewFD->getType()->getAs<FunctionProtoType>(), NewFD->getLocation())) - return true; - } - return false; -} - -/// \brief Check the validity of a mulitversion function declaration. -/// Also sets the multiversion'ness' of the function itself. -/// -/// This sets NewFD->isInvalidDecl() to true if there was an error. -/// -/// Returns true if there was an error, false otherwise. -static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, - bool &Redeclaration, NamedDecl *&OldDecl, - bool &MergeTypeWithPrevious, - LookupResult &Previous) { - const auto *NewTA = NewFD->getAttr<TargetAttr>(); - if (NewFD->isMain()) { - if (NewTA && NewTA->isDefaultVersion()) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main); - NewFD->setInvalidDecl(); - return true; - } - return false; - } - - // If there is no matching previous decl, only 'default' can - // cause MultiVersioning. - if (!OldDecl) { - if (NewTA && NewTA->isDefaultVersion()) { - if (!NewFD->getType()->getAs<FunctionProtoType>()) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto); - NewFD->setInvalidDecl(); - return true; - } - if (CheckMultiVersionAdditionalRules(S, nullptr, NewFD, true)) { - NewFD->setInvalidDecl(); - return true; - } - if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported); - NewFD->setInvalidDecl(); - return true; - } - - NewFD->setIsMultiVersion(); - } - return false; - } - - if (OldDecl->getDeclContext()->getRedeclContext() != - NewFD->getDeclContext()->getRedeclContext()) - return false; - - FunctionDecl *OldFD = OldDecl->getAsFunction(); - // Unresolved 'using' statements (the other way OldDecl can be not a function) - // likely cannot cause a problem here. - if (!OldFD) - return false; - - if (!OldFD->isMultiVersion() && !NewTA) - return false; - - if (OldFD->isMultiVersion() && !NewTA) { - S.Diag(NewFD->getLocation(), diag::err_target_required_in_redecl); - NewFD->setInvalidDecl(); - return true; - } - - TargetAttr::ParsedTargetAttr NewParsed = NewTA->parse(); - // Sort order doesn't matter, it just needs to be consistent. - std::sort(NewParsed.Features.begin(), NewParsed.Features.end()); - - const auto *OldTA = OldFD->getAttr<TargetAttr>(); - if (!OldFD->isMultiVersion()) { - // If the old decl is NOT MultiVersioned yet, and we don't cause that - // to change, this is a simple redeclaration. - if (!OldTA || OldTA->getFeaturesStr() == NewTA->getFeaturesStr()) - return false; - - // Otherwise, this decl causes MultiVersioning. - if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported); - S.Diag(OldFD->getLocation(), diag::note_previous_declaration); - NewFD->setInvalidDecl(); - return true; - } - - if (!OldFD->getType()->getAs<FunctionProtoType>()) { - S.Diag(OldFD->getLocation(), diag::err_multiversion_noproto); - S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); - NewFD->setInvalidDecl(); - return true; - } - - if (CheckMultiVersionValue(S, NewFD)) { - NewFD->setInvalidDecl(); - return true; - } - - if (CheckMultiVersionValue(S, OldFD)) { - S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); - NewFD->setInvalidDecl(); - return true; - } - - TargetAttr::ParsedTargetAttr OldParsed = - OldTA->parse(std::less<std::string>()); - - if (OldParsed == NewParsed) { - 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>(); - if (!CurTA || CurTA->isInherited()) { - S.Diag(FD->getLocation(), diag::err_target_required_in_redecl); - S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); - NewFD->setInvalidDecl(); - return true; - } - } - - if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, true)) { - NewFD->setInvalidDecl(); - return true; - } - - OldFD->setIsMultiVersion(); - NewFD->setIsMultiVersion(); - Redeclaration = false; - MergeTypeWithPrevious = false; - OldDecl = nullptr; - Previous.clear(); - return false; - } - - bool UseMemberUsingDeclRules = - S.CurContext->isRecord() && !NewFD->getFriendObjectKind(); - - // Next, check ALL 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) - continue; - if (S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) - continue; - - const auto *CurTA = CurFD->getAttr<TargetAttr>(); - if (CurTA->getFeaturesStr() == NewTA->getFeaturesStr()) { - NewFD->setIsMultiVersion(); - Redeclaration = true; - OldDecl = ND; - return false; - } - - TargetAttr::ParsedTargetAttr CurParsed = - CurTA->parse(std::less<std::string>()); - - if (CurParsed == NewParsed) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); - S.Diag(CurFD->getLocation(), diag::note_previous_declaration); - NewFD->setInvalidDecl(); - return true; - } - } - - // Else, this is simply a non-redecl case. - if (CheckMultiVersionValue(S, NewFD)) { - NewFD->setInvalidDecl(); - return true; - } - - if (CheckMultiVersionAdditionalRules(S, OldFD, NewFD, false)) { - NewFD->setInvalidDecl(); - return true; - } - - NewFD->setIsMultiVersion(); - Redeclaration = false; - MergeTypeWithPrevious = false; - OldDecl = nullptr; - Previous.clear(); - return false; -} - /// \brief Perform semantic checking of a new function declaration. /// /// Performs semantic analysis of the new function declaration @@ -9581,7 +9246,7 @@ } } - if (CheckMultiVersionFunction(*this, NewFD, Redeclaration, OldDecl, + if (CheckMultiVersionFunction(NewFD, Redeclaration, OldDecl, MergeTypeWithPrevious, Previous)) return Redeclaration; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1533,6 +1533,10 @@ private: bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T, TypeDiagnoser *Diagnoser); + bool CheckMultiVersionFunction(FunctionDecl *NewFD, bool &Redeclaration, + NamedDecl *&OldDecl, + bool &MergeTypeWithPrevious, + LookupResult &Previous); struct ModuleScope { clang::Module *Module = nullptr;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits