diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/AnalysisBasedWarnings.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaARM.cpp | 91 | ||||
-rw-r--r-- | clang/lib/Sema/SemaAvailability.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaConcept.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 304 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenACC.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenACCAtomic.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenACCClause.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenMP.cpp | 37 | ||||
-rw-r--r-- | clang/lib/Sema/SemaRISCV.cpp | 110 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 21 | ||||
-rw-r--r-- | clang/lib/Sema/SemaWasm.cpp | 49 | ||||
-rw-r--r-- | clang/lib/Sema/SemaX86.cpp | 62 |
15 files changed, 474 insertions, 283 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index d1400cb..829c81b 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2901,8 +2901,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( .setAlwaysAdd(Stmt::UnaryOperatorClass); } - bool EnableLifetimeSafetyAnalysis = !Diags.isIgnored( - diag::warn_experimental_lifetime_safety_dummy_warning, D->getBeginLoc()); + bool EnableLifetimeSafetyAnalysis = S.getLangOpts().EnableLifetimeSafety; // Install the logical handler. std::optional<LogicalErrorHandler> LEH; if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { @@ -3029,8 +3028,8 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( // TODO: Enable lifetime safety analysis for other languages once it is // stable. if (EnableLifetimeSafetyAnalysis && S.getLangOpts().CPlusPlus) { - if (CFG *cfg = AC.getCFG()) - runLifetimeSafetyAnalysis(*cast<DeclContext>(D), *cfg, AC); + if (AC.getCFG()) + lifetimes::runLifetimeSafetyAnalysis(AC); } // Check for violations of "called once" parameter properties. if (S.getLangOpts().ObjC && !S.getLangOpts().CPlusPlus && diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index bd603a9..8e27fab 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -1535,4 +1535,95 @@ bool SemaARM::areLaxCompatibleSveTypes(QualType FirstType, IsLaxCompatible(SecondType, FirstType); } +bool SemaARM::checkTargetVersionAttr(const StringRef Param, + const SourceLocation Loc) { + using namespace DiagAttrParams; + + llvm::SmallVector<StringRef, 8> Features; + Param.split(Features, '+'); + for (StringRef Feat : Features) { + Feat = Feat.trim(); + if (Feat == "default") + continue; + if (!getASTContext().getTargetInfo().validateCpuSupports(Feat)) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Feat << TargetVersion; + } + return false; +} + +bool SemaARM::checkTargetClonesAttr( + SmallVectorImpl<StringRef> &Params, SmallVectorImpl<SourceLocation> &Locs, + SmallVectorImpl<SmallString<64>> &NewParams) { + using namespace DiagAttrParams; + + if (!getASTContext().getTargetInfo().hasFeature("fmv")) + return true; + + assert(Params.size() == Locs.size() && + "Mismatch between number of string parameters and locations"); + + bool HasDefault = false; + bool HasNonDefault = false; + for (unsigned I = 0, E = Params.size(); I < E; ++I) { + const StringRef Param = Params[I].trim(); + const SourceLocation &Loc = Locs[I]; + + if (Param.empty()) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "" << TargetClones; + + if (Param == "default") { + if (HasDefault) + Diag(Loc, diag::warn_target_clone_duplicate_options); + else { + NewParams.push_back(Param); + HasDefault = true; + } + continue; + } + + bool HasCodeGenImpact = false; + llvm::SmallVector<StringRef, 8> Features; + llvm::SmallVector<StringRef, 8> ValidFeatures; + Param.split(Features, '+'); + for (StringRef Feat : Features) { + Feat = Feat.trim(); + if (!getASTContext().getTargetInfo().validateCpuSupports(Feat)) { + Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Feat << TargetClones; + continue; + } + if (getASTContext().getTargetInfo().doesFeatureAffectCodeGen(Feat)) + HasCodeGenImpact = true; + ValidFeatures.push_back(Feat); + } + + // Ignore features that don't impact code generation. + if (!HasCodeGenImpact) { + Diag(Loc, diag::warn_target_clone_no_impact_options); + continue; + } + + if (ValidFeatures.empty()) + continue; + + // Canonicalize attribute parameter. + llvm::sort(ValidFeatures); + SmallString<64> NewParam(llvm::join(ValidFeatures, "+")); + if (llvm::is_contained(NewParams, NewParam)) { + Diag(Loc, diag::warn_target_clone_duplicate_options); + continue; + } + + // Valid non-default argument. + NewParams.push_back(NewParam); + HasNonDefault = true; + } + if (!HasNonDefault) + return true; + + return false; +} + } // namespace clang diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index 8c6a173..68a698f 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -547,6 +547,12 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, return; } case AR_Deprecated: + // Suppress -Wdeprecated-declarations in implicit + // functions. + if (const auto *FD = dyn_cast_or_null<FunctionDecl>(S.getCurFunctionDecl()); + FD && FD->isImplicit()) + return; + if (ObjCPropertyAccess) diag = diag::warn_property_method_deprecated; else if (S.currentEvaluationContext().IsCaseExpr) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 5e523fe..c74b671 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3013,6 +3013,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_elementwise_maxnum: case Builtin::BI__builtin_elementwise_minimum: case Builtin::BI__builtin_elementwise_maximum: + case Builtin::BI__builtin_elementwise_minimumnum: + case Builtin::BI__builtin_elementwise_maximumnum: case Builtin::BI__builtin_elementwise_atan2: case Builtin::BI__builtin_elementwise_fmod: case Builtin::BI__builtin_elementwise_pow: diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 5205ca0b..044cf5c 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -588,6 +588,9 @@ static bool CheckConstraintSatisfaction( return true; for (const AssociatedConstraint &AC : AssociatedConstraints) { + if (AC.isNull()) + return true; + Sema::ArgPackSubstIndexRAII _(S, AC.ArgPackSubstIndex); ExprResult Res = calculateConstraintSatisfaction( S, Template, TemplateIDRange.getBegin(), TemplateArgsLists, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 14403e6..d7420bd 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3267,6 +3267,14 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, if (isa<UsedAttr>(I) || isa<RetainAttr>(I)) continue; + if (isa<InferredNoReturnAttr>(I)) { + if (auto *FD = dyn_cast<FunctionDecl>(New)) { + if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + continue; // Don't propagate inferred noreturn attributes to explicit + // specializations. + } + } + if (mergeDeclAttribute(*this, New, I, LocalAMK)) foundAny = true; } @@ -18476,6 +18484,10 @@ CreateNewDecl: // record. AddPushedVisibilityAttribute(New); + // If this is not a definition, process API notes for it now. + if (TUK != TagUseKind::Definition) + ProcessAPINotes(New); + if (isMemberSpecialization && !New->isInvalidDecl()) CompleteMemberSpecialization(New, Previous); @@ -20569,7 +20581,8 @@ TopLevelStmtDecl *Sema::ActOnStartTopLevelStmtDecl(Scope *S) { } void Sema::ActOnFinishTopLevelStmtDecl(TopLevelStmtDecl *D, Stmt *Statement) { - D->setStmt(Statement); + if (Statement) + D->setStmt(Statement); PopCompoundScope(); PopFunctionScopeInfo(); PopDeclContext(); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 78f4804..a4e8de4 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1970,6 +1970,13 @@ void clang::inferNoReturnAttr(Sema &S, const Decl *D) { if (!FD) return; + // Skip explicit specializations here as they may have + // a user-provided definition that may deliberately differ from the primary + // template. If an explicit specialization truly never returns, the user + // should explicitly mark it with [[noreturn]]. + if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + auto *NonConstFD = const_cast<FunctionDecl *>(FD); DiagnosticsEngine &Diags = S.getDiagnostics(); if (Diags.isIgnored(diag::warn_falloff_nonvoid, FD->getLocation()) && @@ -2034,7 +2041,8 @@ bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. if (!AL.existsInTarget(Context.getTargetInfo())) { if (AL.isRegularKeywordAttribute()) - Diag(AL.getLoc(), diag::err_keyword_not_supported_on_target); + Diag(AL.getLoc(), diag::err_keyword_not_supported_on_target) + << AL << AL.getRange(); else DiagnoseUnknownAttribute(AL); AL.setInvalid(); @@ -3254,9 +3262,8 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { - enum FirstParam { Unsupported, Duplicate, Unknown }; - enum SecondParam { None, CPU, Tune }; - enum ThirdParam { Target, TargetClones }; + using namespace DiagAttrParams; + if (AttrStr.contains("fpmath=")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "fpmath=" << Target; @@ -3331,80 +3338,22 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { return false; } -bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D, - StringRef AttrStr) { - enum FirstParam { Unsupported }; - enum SecondParam { None }; - enum ThirdParam { Target, TargetClones, TargetVersion }; - llvm::SmallVector<StringRef, 8> Features; - if (Context.getTargetInfo().getTriple().isRISCV()) { - llvm::SmallVector<StringRef, 8> AttrStrs; - AttrStr.split(AttrStrs, ';'); - - bool HasArch = false; - bool HasPriority = false; - bool HasDefault = false; - bool DuplicateAttr = false; - for (auto &AttrStr : AttrStrs) { - // Only support arch=+ext,... syntax. - if (AttrStr.starts_with("arch=+")) { - if (HasArch) - DuplicateAttr = true; - HasArch = true; - ParsedTargetAttr TargetAttr = - Context.getTargetInfo().parseTargetAttr(AttrStr); - - if (TargetAttr.Features.empty() || - llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) { - return !RISCV().isValidFMVExtension(Ext); - })) - return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << AttrStr << TargetVersion; - } else if (AttrStr.starts_with("default")) { - if (HasDefault) - DuplicateAttr = true; - HasDefault = true; - } else if (AttrStr.consume_front("priority=")) { - if (HasPriority) - DuplicateAttr = true; - HasPriority = true; - unsigned Digit; - if (AttrStr.getAsInteger(0, Digit)) - return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << AttrStr << TargetVersion; - } else { - return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << AttrStr << TargetVersion; - } - } - - if (((HasPriority || HasArch) && HasDefault) || DuplicateAttr || - (HasPriority && !HasArch)) - return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << AttrStr << TargetVersion; +static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Param; + SourceLocation Loc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Param, &Loc)) + return; - return false; - } - 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; + if (S.Context.getTargetInfo().getTriple().isAArch64()) { + if (S.ARM().checkTargetVersionAttr(Param, Loc)) + return; + } else if (S.Context.getTargetInfo().getTriple().isRISCV()) { + if (S.RISCV().checkTargetVersionAttr(Param, Loc)) + return; } - return false; -} -static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - StringRef Str; - SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || - S.checkTargetVersionAttr(LiteralLoc, D, Str)) - return; TargetVersionAttr *NewAttr = - ::new (S.Context) TargetVersionAttr(S.Context, AL, Str); + ::new (S.Context) TargetVersionAttr(S.Context, AL, Param); D->addAttr(NewAttr); } @@ -3419,158 +3368,7 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(NewAttr); } -bool Sema::checkTargetClonesAttrString( - SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal, - Decl *D, bool &HasDefault, bool &HasCommas, bool &HasNotDefault, - SmallVectorImpl<SmallString<64>> &StringsBuffer) { - enum FirstParam { Unsupported, Duplicate, Unknown }; - enum SecondParam { None, CPU, Tune }; - enum ThirdParam { Target, TargetClones }; - HasCommas = HasCommas || Str.contains(','); - const TargetInfo &TInfo = Context.getTargetInfo(); - // Warn on empty at the beginning of a string. - if (Str.size() == 0) - return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << "" << TargetClones; - - std::pair<StringRef, StringRef> Parts = {{}, Str}; - while (!Parts.second.empty()) { - Parts = Parts.second.split(','); - StringRef Cur = Parts.first.trim(); - SourceLocation CurLoc = - Literal->getLocationOfByte(Cur.data() - Literal->getString().data(), - getSourceManager(), getLangOpts(), TInfo); - - bool DefaultIsDupe = false; - bool HasCodeGenImpact = false; - if (Cur.empty()) - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << "" << TargetClones; - - if (TInfo.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 (!TInfo.validateCpuSupports(CurFeature)) { - Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << CurFeature << TargetClones; - continue; - } - if (TInfo.doesFeatureAffectCodeGen(CurFeature)) - HasCodeGenImpact = true; - CurFeatures.push_back(CurFeature); - } - // Canonize TargetClones Attributes - llvm::sort(CurFeatures); - SmallString<64> Res; - for (auto &CurFeat : CurFeatures) { - if (!Res.empty()) - 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 if (TInfo.getTriple().isRISCV()) { - // Suppress warn_target_clone_mixed_values - HasCommas = false; - - // Cur is split's parts of Str. RISC-V uses Str directly, - // so skip when encountered more than once. - if (!Str.starts_with(Cur)) - continue; - - llvm::SmallVector<StringRef, 8> AttrStrs; - Str.split(AttrStrs, ";"); - - bool IsPriority = false; - bool IsDefault = false; - for (auto &AttrStr : AttrStrs) { - // Only support arch=+ext,... syntax. - if (AttrStr.starts_with("arch=+")) { - ParsedTargetAttr TargetAttr = - Context.getTargetInfo().parseTargetAttr(AttrStr); - - if (TargetAttr.Features.empty() || - llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) { - return !RISCV().isValidFMVExtension(Ext); - })) - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Str << TargetClones; - } else if (AttrStr.starts_with("default")) { - IsDefault = true; - DefaultIsDupe = HasDefault; - HasDefault = true; - } else if (AttrStr.consume_front("priority=")) { - IsPriority = true; - unsigned Digit; - if (AttrStr.getAsInteger(0, Digit)) - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Str << TargetClones; - } else { - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Str << TargetClones; - } - } - - if (IsPriority && IsDefault) - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << Str << TargetClones; - - if (llvm::is_contained(StringsBuffer, Str) || DefaultIsDupe) - Diag(CurLoc, diag::warn_target_clone_duplicate_options); - StringsBuffer.push_back(Str); - } else { - // Other targets ( currently X86 ) - if (Cur.starts_with("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) || - Context.getTargetInfo().getFMVPriority(Cur) == 0) - return Diag(CurLoc, diag::warn_unsupported_target_attribute) - << 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().ends_with(",")) - return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << "" << TargetClones; - return false; -} - 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>()) { @@ -3581,31 +3379,6 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (checkAttrMutualExclusion<TargetClonesAttr>(S, D, AL)) return; - SmallVector<StringRef, 2> Strings; - SmallVector<SmallString<64>, 2> StringsBuffer; - bool HasCommas = false, HasDefault = false, HasNotDefault = false; - - for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { - StringRef CurStr; - SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(AL, I, CurStr, &LiteralLoc) || - S.checkTargetClonesAttrString( - LiteralLoc, CurStr, - cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()), D, - 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 (!HasDefault && !S.Context.getTargetInfo().getTriple().isAArch64()) { - S.Diag(AL.getLoc(), diag::err_target_clone_must_have_default); - return; - } - // FIXME: We could probably figure out how to get this to work for lambdas // someday. if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { @@ -3617,13 +3390,34 @@ 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; + SmallVector<StringRef, 2> Params; + SmallVector<SourceLocation, 2> Locations; + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { + StringRef Param; + SourceLocation Loc; + if (!S.checkStringLiteralArgumentAttr(AL, I, Param, &Loc)) + return; + Params.push_back(Param); + Locations.push_back(Loc); + } + + SmallVector<SmallString<64>, 2> NewParams; + if (S.Context.getTargetInfo().getTriple().isAArch64()) { + if (S.ARM().checkTargetClonesAttr(Params, Locations, NewParams)) + return; + } else if (S.Context.getTargetInfo().getTriple().isRISCV()) { + if (S.RISCV().checkTargetClonesAttr(Params, Locations, NewParams)) + return; + } else if (S.Context.getTargetInfo().getTriple().isX86()) { + if (S.X86().checkTargetClonesAttr(Params, Locations, NewParams)) + return; + } + Params.clear(); + for (auto &SmallStr : NewParams) + Params.push_back(SmallStr.str()); - cast<FunctionDecl>(D)->setIsMultiVersion(); TargetClonesAttr *NewAttr = ::new (S.Context) - TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size()); + TargetClonesAttr(S.Context, AL, Params.data(), Params.size()); D->addAttr(NewAttr); } diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 128a5db..8bfea62 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -699,11 +699,19 @@ ExprResult SemaOpenACC::ActOnVar(OpenACCDirectiveKind DK, OpenACCClauseKind CK, // OpenACC3.3 2.13: // A 'var' in a 'declare' directive must be a variable or array name. if ((CK == OpenACCClauseKind::UseDevice || - DK == OpenACCDirectiveKind::Declare) && - isa<ArraySectionExpr, ArraySubscriptExpr>(CurVarExpr)) { - Diag(VarExpr->getExprLoc(), diag::err_acc_not_a_var_ref_use_device_declare) - << (DK == OpenACCDirectiveKind::Declare); - return ExprError(); + DK == OpenACCDirectiveKind::Declare)) { + if (isa<ArraySubscriptExpr>(CurVarExpr)) { + Diag(VarExpr->getExprLoc(), + diag::err_acc_not_a_var_ref_use_device_declare) + << (DK == OpenACCDirectiveKind::Declare); + return ExprError(); + } + // As an extension, we allow 'array sections'/'sub-arrays' here, as that is + // effectively defining an array, and are in common use. + if (isa<ArraySectionExpr>(CurVarExpr)) + Diag(VarExpr->getExprLoc(), + diag::ext_acc_array_section_use_device_declare) + << (DK == OpenACCDirectiveKind::Declare); } // Sub-arrays/subscript-exprs are fine as long as the base is a diff --git a/clang/lib/Sema/SemaOpenACCAtomic.cpp b/clang/lib/Sema/SemaOpenACCAtomic.cpp index 9c8c8d1..a9319dc 100644 --- a/clang/lib/Sema/SemaOpenACCAtomic.cpp +++ b/clang/lib/Sema/SemaOpenACCAtomic.cpp @@ -576,6 +576,11 @@ class AtomicOperandChecker { return AssocStmt; } + const Expr *IgnoreBeforeCompare(const Expr *E) { + return E->IgnoreParenImpCasts()->IgnoreParenNoopCasts( + SemaRef.getASTContext()); + } + bool CheckVarRefsSame(IDACInfo::ExprKindTy FirstKind, const Expr *FirstX, IDACInfo::ExprKindTy SecondKind, const Expr *SecondX) { llvm::FoldingSetNodeID First_ID, Second_ID; @@ -648,8 +653,10 @@ class AtomicOperandChecker { if (CheckOperandVariable(AssignRes->RHS, PD)) return getRecoveryExpr(); - if (CheckVarRefsSame(FirstExprResults.ExprKind, FirstExprResults.X_Var, - IDACInfo::SimpleAssign, AssignRes->RHS)) + if (CheckVarRefsSame(FirstExprResults.ExprKind, + IgnoreBeforeCompare(FirstExprResults.X_Var), + IDACInfo::SimpleAssign, + IgnoreBeforeCompare(AssignRes->RHS))) return getRecoveryExpr(); break; } @@ -660,9 +667,10 @@ class AtomicOperandChecker { if (SecondExprResults.Failed) return getRecoveryExpr(); - if (CheckVarRefsSame(FirstExprResults.ExprKind, FirstExprResults.X_Var, + if (CheckVarRefsSame(FirstExprResults.ExprKind, + IgnoreBeforeCompare(FirstExprResults.X_Var), SecondExprResults.ExprKind, - SecondExprResults.X_Var)) + IgnoreBeforeCompare(SecondExprResults.X_Var))) return getRecoveryExpr(); break; } diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp index 3f90fe8..b54a012 100644 --- a/clang/lib/Sema/SemaOpenACCClause.cpp +++ b/clang/lib/Sema/SemaOpenACCClause.cpp @@ -1919,6 +1919,14 @@ ExprResult SemaOpenACC::CheckReductionVar(OpenACCDirectiveKind DirectiveKind, << EltTy << /*Sub array base type*/ 1; return ExprError(); } + } else if (VarExpr->getType()->isArrayType()) { + // Arrays are considered an 'aggregate variable' explicitly, so are OK, no + // additional checking required. + // + // Glossary: Aggregate variables – a variable of any non-scalar datatype, + // including array or composite variables. + // + // The next branch (record decl) checks for composite variables. } else if (auto *RD = VarExpr->getType()->getAsRecordDecl()) { if (!RD->isStruct() && !RD->isClass()) { Diag(VarExpr->getExprLoc(), diag::err_acc_reduction_composite_type) @@ -2246,7 +2254,13 @@ bool SemaOpenACC::CheckDeclareClause(SemaOpenACC::OpenACCParsedClause &Clause, continue; } } else { - const auto *DRE = cast<DeclRefExpr>(VarExpr); + + const Expr *VarExprTemp = VarExpr; + + while (const auto *ASE = dyn_cast<ArraySectionExpr>(VarExprTemp)) + VarExprTemp = ASE->getBase()->IgnoreParenImpCasts(); + + const auto *DRE = cast<DeclRefExpr>(VarExprTemp); if (const auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) { CurDecl = Var->getCanonicalDecl(); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 4ecc9b0..2c5d97c 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -2829,7 +2829,7 @@ static void checkReductionClauses(Sema &S, DSAStackTy *Stack, continue; } for (Expr *Ref : RC->varlist()) { - assert(Ref && "NULL expr in OpenMP nontemporal clause."); + assert(Ref && "NULL expr in OpenMP reduction clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = Ref; @@ -7612,6 +7612,23 @@ void SemaOpenMP::ActOnOpenMPDeclareVariantDirective( return; } + // OpenMP 6.0 [9.6.2 (page 332, line 31-33, adjust_args clause, Restrictions] + // If the `need_device_addr` adjust-op modifier is present, each list item + // that appears in the clause must refer to an argument in the declaration of + // the function variant that has a reference type + if (getLangOpts().OpenMP >= 60) { + for (Expr *E : AdjustArgsNeedDeviceAddr) { + E = E->IgnoreParenImpCasts(); + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) { + if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + if (!VD->getType()->isReferenceType()) + Diag(E->getExprLoc(), + diag::err_omp_non_by_ref_need_device_addr_modifier_argument); + } + } + } + } + auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( getASTContext(), VariantRef, &TI, const_cast<Expr **>(AdjustArgsNothing.data()), AdjustArgsNothing.size(), @@ -18344,7 +18361,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); + assert(RefExpr && "NULL expr in OpenMP shared clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -19991,7 +20008,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPAlignedClause( SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP linear clause."); + assert(RefExpr && "NULL expr in OpenMP aligned clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -20167,7 +20184,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> DstExprs; SmallVector<Expr *, 8> AssignmentOps; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP linear clause."); + assert(RefExpr && "NULL expr in OpenMP copyprivate clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -20526,7 +20543,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPDependClause( TotalDepCount = VarOffset.TotalDepCount; } else { for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP shared clause."); + assert(RefExpr && "NULL expr in OpenMP depend clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -23737,7 +23754,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPAllocateClause( // Analyze and build list of variables. SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP private clause."); + assert(RefExpr && "NULL expr in OpenMP allocate clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -23829,7 +23846,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPInclusiveClause(ArrayRef<Expr *> VarList, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + assert(RefExpr && "NULL expr in OpenMP inclusive clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -23870,7 +23887,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPExclusiveClause(ArrayRef<Expr *> VarList, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + assert(RefExpr && "NULL expr in OpenMP exclusive clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -24063,7 +24080,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPAffinityClause( SourceLocation EndLoc, Expr *Modifier, ArrayRef<Expr *> Locators) { SmallVector<Expr *, 8> Vars; for (Expr *RefExpr : Locators) { - assert(RefExpr && "NULL expr in OpenMP shared clause."); + assert(RefExpr && "NULL expr in OpenMP affinity clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr) || RefExpr->isTypeDependent()) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -24375,7 +24392,7 @@ ExprResult SemaOpenMP::ActOnOMPArraySectionExpr( return ExprError(); } } - } else if (ColonLocFirst.isValid() && + } else if (SemaRef.getLangOpts().OpenMP < 60 && ColonLocFirst.isValid() && (OriginalTy.isNull() || (!OriginalTy->isConstantArrayType() && !OriginalTy->isVariableArrayType()))) { // OpenMP 5.0, [2.1.5 Array Sections] diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index 43f7992..994cd07 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -1635,6 +1635,116 @@ bool SemaRISCV::isValidFMVExtension(StringRef Ext) { return -1 != RISCVISAInfo::getRISCVFeaturesBitsInfo(Ext).second; } +bool SemaRISCV::checkTargetVersionAttr(const StringRef Param, + const SourceLocation Loc) { + using namespace DiagAttrParams; + + llvm::SmallVector<StringRef, 8> AttrStrs; + Param.split(AttrStrs, ';'); + + bool HasArch = false; + bool HasPriority = false; + bool HasDefault = false; + bool DuplicateAttr = false; + for (StringRef AttrStr : AttrStrs) { + AttrStr = AttrStr.trim(); + // Only support arch=+ext,... syntax. + if (AttrStr.starts_with("arch=+")) { + DuplicateAttr = HasArch; + HasArch = true; + ParsedTargetAttr TargetAttr = + getASTContext().getTargetInfo().parseTargetAttr(AttrStr); + + if (TargetAttr.Features.empty() || + llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) { + return !isValidFMVExtension(Ext); + })) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << AttrStr << TargetVersion; + } else if (AttrStr == "default") { + DuplicateAttr = HasDefault; + HasDefault = true; + } else if (AttrStr.consume_front("priority=")) { + DuplicateAttr = HasPriority; + HasPriority = true; + unsigned Digit; + if (AttrStr.getAsInteger(0, Digit)) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << AttrStr << TargetVersion; + } else { + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << AttrStr << TargetVersion; + } + } + + if (((HasPriority || HasArch) && HasDefault) || DuplicateAttr || + (HasPriority && !HasArch)) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Param << TargetVersion; + + return false; +} + +bool SemaRISCV::checkTargetClonesAttr( + SmallVectorImpl<StringRef> &Params, SmallVectorImpl<SourceLocation> &Locs, + SmallVectorImpl<SmallString<64>> &NewParams) { + using namespace DiagAttrParams; + + assert(Params.size() == Locs.size() && + "Mismatch between number of string parameters and locations"); + + bool HasDefault = false; + for (unsigned I = 0, E = Params.size(); I < E; ++I) { + const StringRef Param = Params[I].trim(); + const SourceLocation &Loc = Locs[I]; + + llvm::SmallVector<StringRef, 8> AttrStrs; + Param.split(AttrStrs, ';'); + + bool IsPriority = false; + bool IsDefault = false; + for (StringRef AttrStr : AttrStrs) { + AttrStr = AttrStr.trim(); + // Only support arch=+ext,... syntax. + if (AttrStr.starts_with("arch=+")) { + ParsedTargetAttr TargetAttr = + getASTContext().getTargetInfo().parseTargetAttr(AttrStr); + + if (TargetAttr.Features.empty() || + llvm::any_of(TargetAttr.Features, [&](const StringRef Ext) { + return !isValidFMVExtension(Ext); + })) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Param << TargetClones; + } else if (AttrStr == "default") { + IsDefault = true; + HasDefault = true; + } else if (AttrStr.consume_front("priority=")) { + IsPriority = true; + unsigned Digit; + if (AttrStr.getAsInteger(0, Digit)) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Param << TargetClones; + } else { + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Param << TargetClones; + } + } + + if (IsPriority && IsDefault) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Param << TargetClones; + + if (llvm::is_contained(NewParams, Param)) + Diag(Loc, diag::warn_target_clone_duplicate_options); + NewParams.push_back(Param); + } + if (!HasDefault) + return Diag(Locs[0], diag::err_target_clone_must_have_default); + + return false; +} + SemaRISCV::SemaRISCV(Sema &S) : SemaBase(S) {} } // namespace clang diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index e1a975b..9e56e697 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -5523,6 +5523,15 @@ static TemplateDeductionResult CheckDeductionConsistency( // FIXME: A substitution can be incomplete on a non-structural part of the // type. Use the canonical type for now, until the TemplateInstantiator can // deal with that. + + // Workaround: Implicit deduction guides use InjectedClassNameTypes, whereas + // the explicit guides don't. The substitution doesn't transform these types, + // so let it transform their specializations instead. + bool IsDeductionGuide = isa<CXXDeductionGuideDecl>(FTD->getTemplatedDecl()); + if (IsDeductionGuide) { + if (auto *Injected = P->getAs<InjectedClassNameType>()) + P = Injected->getInjectedSpecializationType(); + } QualType InstP = S.SubstType(P.getCanonicalType(), MLTAL, FTD->getLocation(), FTD->getDeclName(), &IsIncompleteSubstitution); if (InstP.isNull() && !IsIncompleteSubstitution) @@ -5537,9 +5546,15 @@ static TemplateDeductionResult CheckDeductionConsistency( if (auto *PA = dyn_cast<PackExpansionType>(A); PA && !isa<PackExpansionType>(InstP)) A = PA->getPattern(); - if (!S.Context.hasSameType( - S.Context.getUnqualifiedArrayType(InstP.getNonReferenceType()), - S.Context.getUnqualifiedArrayType(A.getNonReferenceType()))) + auto T1 = S.Context.getUnqualifiedArrayType(InstP.getNonReferenceType()); + auto T2 = S.Context.getUnqualifiedArrayType(A.getNonReferenceType()); + if (IsDeductionGuide) { + if (auto *Injected = T1->getAs<InjectedClassNameType>()) + T1 = Injected->getInjectedSpecializationType(); + if (auto *Injected = T2->getAs<InjectedClassNameType>()) + T2 = Injected->getInjectedSpecializationType(); + } + if (!S.Context.hasSameType(T1, T2)) return TemplateDeductionResult::NonDeducedMismatch; return TemplateDeductionResult::Success; } diff --git a/clang/lib/Sema/SemaWasm.cpp b/clang/lib/Sema/SemaWasm.cpp index 6faea24..8998492 100644 --- a/clang/lib/Sema/SemaWasm.cpp +++ b/clang/lib/Sema/SemaWasm.cpp @@ -227,6 +227,53 @@ bool SemaWasm::BuiltinWasmTableCopy(CallExpr *TheCall) { return false; } +bool SemaWasm::BuiltinWasmTestFunctionPointerSignature(CallExpr *TheCall) { + if (SemaRef.checkArgCount(TheCall, 1)) + return true; + + Expr *FuncPtrArg = TheCall->getArg(0); + QualType ArgType = FuncPtrArg->getType(); + + // Check that the argument is a function pointer + const PointerType *PtrTy = ArgType->getAs<PointerType>(); + if (!PtrTy) { + return Diag(FuncPtrArg->getBeginLoc(), + diag::err_typecheck_expect_function_pointer) + << ArgType << FuncPtrArg->getSourceRange(); + } + + const FunctionProtoType *FuncTy = + PtrTy->getPointeeType()->getAs<FunctionProtoType>(); + if (!FuncTy) { + return Diag(FuncPtrArg->getBeginLoc(), + diag::err_typecheck_expect_function_pointer) + << ArgType << FuncPtrArg->getSourceRange(); + } + + // Check that the function pointer doesn't use reference types + if (FuncTy->getReturnType().isWebAssemblyReferenceType()) { + return Diag( + FuncPtrArg->getBeginLoc(), + diag::err_wasm_builtin_test_fp_sig_cannot_include_reference_type) + << 0 << FuncTy->getReturnType() << FuncPtrArg->getSourceRange(); + } + auto NParams = FuncTy->getNumParams(); + for (unsigned I = 0; I < NParams; I++) { + if (FuncTy->getParamType(I).isWebAssemblyReferenceType()) { + return Diag( + FuncPtrArg->getBeginLoc(), + diag:: + err_wasm_builtin_test_fp_sig_cannot_include_reference_type) + << 1 << FuncPtrArg->getSourceRange(); + } + } + + // Set return type to int (the result of the test) + TheCall->setType(getASTContext().IntTy); + + return false; +} + bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { @@ -249,6 +296,8 @@ bool SemaWasm::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, return BuiltinWasmTableFill(TheCall); case WebAssembly::BI__builtin_wasm_table_copy: return BuiltinWasmTableCopy(TheCall); + case WebAssembly::BI__builtin_wasm_test_function_pointer_signature: + return BuiltinWasmTestFunctionPointerSignature(TheCall); } return false; diff --git a/clang/lib/Sema/SemaX86.cpp b/clang/lib/Sema/SemaX86.cpp index 5c149bd..850bcb1 100644 --- a/clang/lib/Sema/SemaX86.cpp +++ b/clang/lib/Sema/SemaX86.cpp @@ -954,6 +954,11 @@ bool SemaX86::CheckBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, l = 0; u = 15; break; + case X86::BI__builtin_ia32_prefetchi: + i = 1; + l = 2; // _MM_HINT_T1 + u = 3; // _MM_HINT_T0 + break; } // Note that we don't force a hard error on the range check here, allowing @@ -1056,4 +1061,61 @@ void SemaX86::handleForceAlignArgPointerAttr(Decl *D, const ParsedAttr &AL) { X86ForceAlignArgPointerAttr(getASTContext(), AL)); } +bool SemaX86::checkTargetClonesAttr( + SmallVectorImpl<StringRef> &Params, SmallVectorImpl<SourceLocation> &Locs, + SmallVectorImpl<SmallString<64>> &NewParams) { + using namespace DiagAttrParams; + + assert(Params.size() == Locs.size() && + "Mismatch between number of string parameters and locations"); + + bool HasDefault = false; + bool HasComma = false; + for (unsigned I = 0, E = Params.size(); I < E; ++I) { + const StringRef Param = Params[I].trim(); + const SourceLocation &Loc = Locs[I]; + + if (Param.empty() || Param.ends_with(',')) + return Diag(Loc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "" << TargetClones; + + if (Param.contains(',')) + HasComma = true; + + StringRef LHS; + StringRef RHS = Param; + do { + std::tie(LHS, RHS) = RHS.split(','); + LHS = LHS.trim(); + const SourceLocation &CurLoc = + Loc.getLocWithOffset(LHS.data() - Param.data()); + + if (LHS.starts_with("arch=")) { + if (!getASTContext().getTargetInfo().isValidCPUName( + LHS.drop_front(sizeof("arch=") - 1))) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << CPU << LHS.drop_front(sizeof("arch=") - 1) + << TargetClones; + } else if (LHS == "default") + HasDefault = true; + else if (!getASTContext().getTargetInfo().isValidFeatureName(LHS) || + getASTContext().getTargetInfo().getFMVPriority(LHS) == 0) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << LHS << TargetClones; + + if (llvm::is_contained(NewParams, LHS)) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + // Note: Add even if there are duplicates, since it changes name mangling. + NewParams.push_back(LHS); + } while (!RHS.empty()); + } + if (HasComma && Params.size() > 1) + Diag(Locs[0], diag::warn_target_clone_mixed_values); + + if (!HasDefault) + return Diag(Locs[0], diag::err_target_clone_must_have_default); + + return false; +} + } // namespace clang |