diff options
Diffstat (limited to 'clang')
32 files changed, 550 insertions, 159 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9b6e00b..c9b577b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -857,6 +857,11 @@ Bug Fixes to C++ Support (`#64607 <https://github.com/llvm/llvm-project/issues/64607>`_) (`#64086 <https://github.com/llvm/llvm-project/issues/64086>`_) +- Fixed a regression where clang forgets how to substitute into constraints on template-template + parameters. Fixes: + (`#57410 <https://github.com/llvm/llvm-project/issues/57410>`_) and + (`#76604 <https://github.com/llvm/llvm-project/issues/57410>`_) + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d150e08..a97182c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6160,23 +6160,19 @@ def err_illegal_initializer_type : Error<"illegal initializer type %0">; def ext_init_list_type_narrowing : ExtWarn< "type %0 cannot be narrowed to %1 in initializer list">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; -// *_narrowing_const_reference diagnostics have the same messages, but are -// controlled by -Wc++11-narrowing-const-reference for narrowing involving a -// const reference. def ext_init_list_type_narrowing_const_reference : ExtWarn< - "type %0 cannot be narrowed to %1 in initializer list">, + ext_init_list_type_narrowing.Summary>, InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure; def ext_init_list_variable_narrowing : ExtWarn< "non-constant-expression cannot be narrowed from type %0 to %1 in " "initializer list">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; def ext_init_list_variable_narrowing_const_reference : ExtWarn< - "non-constant-expression cannot be narrowed from type %0 to %1 in " - "initializer list">, InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure; + ext_init_list_variable_narrowing.Summary>, InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure; def ext_init_list_constant_narrowing : ExtWarn< "constant expression evaluates to %0 which cannot be narrowed to type %1">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; def ext_init_list_constant_narrowing_const_reference : ExtWarn< - "constant expression evaluates to %0 which cannot be narrowed to type %1">, + ext_init_list_constant_narrowing.Summary>, InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure; def warn_init_list_type_narrowing : Warning< "type %0 cannot be narrowed to %1 in initializer list in C++11">, diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index 3eb0bf8..f6a628d 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -93,6 +93,9 @@ enum class OpenACCClauseKind { /// 'default' clause, allowed on parallel, serial, kernel (and compound) /// constructs. Default, + /// 'if' clause, allowed on all the Compute Constructs, Data Constructs, + /// Executable Constructs, and Combined Constructs. + If, /// Represents an invalid clause, for the purposes of parsing. Invalid, }; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 9ffae72..5e5570b 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2034,23 +2034,25 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { return ToDCOrErr.takeError(); } - DeclContext *ToDC = *ToDCOrErr; - // Remove all declarations, which may be in wrong order in the - // lexical DeclContext and then add them in the proper order. - for (auto *D : FromDC->decls()) { - if (!MightNeedReordering(D)) - continue; + if (const auto *FromRD = dyn_cast<RecordDecl>(FromDC)) { + DeclContext *ToDC = *ToDCOrErr; + // Remove all declarations, which may be in wrong order in the + // lexical DeclContext and then add them in the proper order. + for (auto *D : FromRD->decls()) { + if (!MightNeedReordering(D)) + continue; - assert(D && "DC contains a null decl"); - if (Decl *ToD = Importer.GetAlreadyImportedOrNull(D)) { - // Remove only the decls which we successfully imported. - assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD)); - // Remove the decl from its wrong place in the linked list. - ToDC->removeDecl(ToD); - // Add the decl to the end of the linked list. - // This time it will be at the proper place because the enclosing for - // loop iterates in the original (good) order of the decls. - ToDC->addDeclInternal(ToD); + assert(D && "DC contains a null decl"); + if (Decl *ToD = Importer.GetAlreadyImportedOrNull(D)) { + // Remove only the decls which we successfully imported. + assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD)); + // Remove the decl from its wrong place in the linked list. + ToDC->removeDecl(ToD); + // Add the decl to the end of the linked list. + // This time it will be at the proper place because the enclosing for + // loop iterates in the original (good) order of the decls. + ToDC->addDeclInternal(ToD); + } } } diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index e0c9e18..c5d14b4 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -488,7 +488,6 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { return NoMatchPromotionTypeConfusion; break; case BuiltinType::Half: - case BuiltinType::Float16: case BuiltinType::Float: if (T == C.DoubleTy) return MatchPromotion; diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index a82d1c3..21ea250 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -290,10 +290,10 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, } bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (!CheckDummy(S, OpPC, Ptr)) - return false; if (!CheckLive(S, OpPC, Ptr, AK_Read)) return false; + if (!CheckDummy(S, OpPC, Ptr)) + return false; if (!CheckExtern(S, OpPC, Ptr)) return false; if (!CheckRange(S, OpPC, Ptr, AK_Read)) diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 828d4ea..c05dea0 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1813,9 +1813,6 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) { const T &Offset = S.Stk.pop<T>(); const Pointer &Ptr = S.Stk.peek<Pointer>(); - if (!CheckArray(S, OpPC, Ptr)) - return false; - if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) return false; @@ -1843,9 +1840,6 @@ inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) { const T &Offset = S.Stk.pop<T>(); const Pointer &Ptr = S.Stk.pop<Pointer>(); - if (!CheckArray(S, OpPC, Ptr)) - return false; - if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) return false; diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 6bc57a8..59ae12e 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -237,22 +237,15 @@ ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const { static std::vector<std::string> collectNonISAExtFeature(ArrayRef<std::string> FeaturesNeedOverride, int XLen) { - auto ParseResult = - llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesNeedOverride); - - if (!ParseResult) { - consumeError(ParseResult.takeError()); - return std::vector<std::string>(); - } - - std::vector<std::string> ImpliedFeatures = (*ParseResult)->toFeatureVector(); - std::vector<std::string> NonISAExtFeatureVec; + auto IsNonISAExtFeature = [](const std::string &Feature) { + assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-')); + StringRef Ext = StringRef(Feature).drop_front(); // drop the +/- + return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext); + }; llvm::copy_if(FeaturesNeedOverride, std::back_inserter(NonISAExtFeatureVec), - [&](const std::string &Feat) { - return !llvm::is_contained(ImpliedFeatures, Feat); - }); + IsNonISAExtFeature); return NonISAExtFeatureVec; } diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 65512f1..18fc9d4 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -471,12 +471,23 @@ findClangRelativeSysroot(const Driver &D, const llvm::Triple &LiteralTriple, return make_error_code(std::errc::no_such_file_or_directory); } +static bool looksLikeMinGWSysroot(const std::string &Directory) { + StringRef Sep = llvm::sys::path::get_separator(); + if (!llvm::sys::fs::exists(Directory + Sep + "include" + Sep + "_mingw.h")) + return false; + if (!llvm::sys::fs::exists(Directory + Sep + "lib" + Sep + "libkernel32.a")) + return false; + return true; +} + toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); + std::string InstallBase = + std::string(llvm::sys::path::parent_path(getDriver().getInstalledDir())); // The sequence for detecting a sysroot here should be kept in sync with // the testTriple function below. llvm::Triple LiteralTriple = getLiteralTriple(D, getTriple()); @@ -487,13 +498,17 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, else if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot( getDriver(), LiteralTriple, getTriple(), SubdirName)) Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get())); + // If the install base of Clang seems to have mingw sysroot files directly + // in the toplevel include and lib directories, use this as base instead of + // looking for a triple prefixed GCC in the path. + else if (looksLikeMinGWSysroot(InstallBase)) + Base = InstallBase; else if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, getTriple())) Base = std::string(llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get()))); else - Base = std::string( - llvm::sys::path::parent_path(getDriver().getInstalledDir())); + Base = InstallBase; Base += llvm::sys::path::get_separator(); findGccLibDir(LiteralTriple); @@ -778,9 +793,15 @@ static bool testTriple(const Driver &D, const llvm::Triple &Triple, if (D.SysRoot.size()) return true; llvm::Triple LiteralTriple = getLiteralTriple(D, Triple); + std::string InstallBase = + std::string(llvm::sys::path::parent_path(D.getInstalledDir())); if (llvm::ErrorOr<std::string> TargetSubdir = findClangRelativeSysroot(D, LiteralTriple, Triple, SubdirName)) return true; + // If the install base itself looks like a mingw sysroot, we'll use that + // - don't use any potentially unrelated gcc to influence what triple to use. + if (looksLikeMinGWSysroot(InstallBase)) + return false; if (llvm::ErrorOr<std::string> GPPName = findGcc(LiteralTriple, Triple)) return true; // If we neither found a colocated sysroot or a matching gcc executable, diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 3ac3aa3c..8b43438 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -5151,6 +5151,14 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, return true; if (Left.IsUnterminatedLiteral) return true; + // FIXME: Breaking after newlines seems useful in general. Turn this into an + // option and recognize more cases like endl etc, and break independent of + // what comes after operator lessless. + if (Right.is(tok::lessless) && Right.Next && + Right.Next->is(tok::string_literal) && Left.is(tok::string_literal) && + Left.TokenText.ends_with("\\n\"")) { + return true; + } if (Right.is(TT_RequiresClause)) { switch (Style.RequiresClausePosition) { case FormatStyle::RCPS_OwnLine: diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index ea5d13d..42d55d0 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -984,7 +984,9 @@ static void inferFrameworkLink(Module *Mod) { assert(!Mod->isSubFramework() && "Can only infer linking for top-level frameworks"); - Mod->LinkLibraries.push_back(Module::LinkLibrary(Mod->Name, + StringRef FrameworkName(Mod->Name); + FrameworkName.consume_back("_Private"); + Mod->LinkLibraries.push_back(Module::LinkLibrary(FrameworkName.str(), /*IsFramework=*/true)); } diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 94c3d0c..84e994e 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -80,6 +80,10 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) { if (Tok.is(tok::kw_default)) return OpenACCClauseKind::Default; + // if is also a keyword, make sure we parse it correctly. + if (Tok.is(tok::kw_if)) + return OpenACCClauseKind::If; + if (!Tok.is(tok::identifier)) return OpenACCClauseKind::Invalid; @@ -88,6 +92,7 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) { .Case("auto", OpenACCClauseKind::Auto) .Case("default", OpenACCClauseKind::Default) .Case("finalize", OpenACCClauseKind::Finalize) + .Case("if", OpenACCClauseKind::If) .Case("if_present", OpenACCClauseKind::IfPresent) .Case("independent", OpenACCClauseKind::Independent) .Case("nohost", OpenACCClauseKind::NoHost) @@ -324,7 +329,7 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) { } bool ClauseHasRequiredParens(OpenACCClauseKind Kind) { - return Kind == OpenACCClauseKind::Default; + return Kind == OpenACCClauseKind::Default || Kind == OpenACCClauseKind::If; } bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { @@ -356,6 +361,19 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { break; } + case OpenACCClauseKind::If: { + // FIXME: It isn't clear if the spec saying 'condition' means the same as + // it does in an if/while/etc (See ParseCXXCondition), however as it was + // written with Fortran/C in mind, we're going to assume it just means an + // 'expression evaluating to boolean'. + ExprResult CondExpr = + P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression()); + // An invalid expression can be just about anything, so just give up on + // this clause list. + if (CondExpr.isInvalid()) + return true; + break; + } default: llvm_unreachable("Not a required parens type?"); } @@ -372,8 +390,10 @@ bool ParseOpenACCClauseParams(Parser &P, OpenACCClauseKind Kind) { // However, they all are named with a single-identifier (or auto/default!) // token, followed in some cases by either braces or parens. bool ParseOpenACCClause(Parser &P) { - if (!P.getCurToken().isOneOf(tok::identifier, tok::kw_auto, tok::kw_default)) - return P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier; + // A number of clause names are actually keywords, so accept a keyword that + // can be converted to a name. + if (expectIdentifierOrKeyword(P)) + return true; OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken()); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index e469e42..408ee5f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10377,11 +10377,6 @@ void InitializationSequence::dump() const { dump(llvm::errs()); } -static bool NarrowingErrs(const LangOptions &L) { - return L.CPlusPlus11 && - (!L.MicrosoftExt || L.isCompatibleWithMSVC(LangOptions::MSVC2015)); -} - static void DiagnoseNarrowingInInitList(Sema &S, const ImplicitConversionSequence &ICS, QualType PreNarrowingType, @@ -10402,6 +10397,19 @@ static void DiagnoseNarrowingInInitList(Sema &S, return; } + auto MakeDiag = [&](bool IsConstRef, unsigned DefaultDiagID, + unsigned ConstRefDiagID, unsigned WarnDiagID) { + unsigned DiagID; + auto &L = S.getLangOpts(); + if (L.CPlusPlus11 && + (!L.MicrosoftExt || L.isCompatibleWithMSVC(LangOptions::MSVC2015))) + DiagID = IsConstRef ? ConstRefDiagID : DefaultDiagID; + else + DiagID = WarnDiagID; + return S.Diag(PostInit->getBeginLoc(), DiagID) + << PostInit->getSourceRange(); + }; + // C++11 [dcl.init.list]p7: Check whether this is a narrowing conversion. APValue ConstantValue; QualType ConstantType; @@ -10417,13 +10425,9 @@ static void DiagnoseNarrowingInInitList(Sema &S, // narrowing conversion even if the value is a constant and can be // represented exactly as an integer. QualType T = EntityType.getNonReferenceType(); - S.Diag(PostInit->getBeginLoc(), - NarrowingErrs(S.getLangOpts()) - ? (T == EntityType - ? diag::ext_init_list_type_narrowing - : diag::ext_init_list_type_narrowing_const_reference) - : diag::warn_init_list_type_narrowing) - << PostInit->getSourceRange() + MakeDiag(T != EntityType, diag::ext_init_list_type_narrowing, + diag::ext_init_list_type_narrowing_const_reference, + diag::warn_init_list_type_narrowing) << PreNarrowingType.getLocalUnqualifiedType() << T.getLocalUnqualifiedType(); break; @@ -10431,14 +10435,10 @@ static void DiagnoseNarrowingInInitList(Sema &S, case NK_Constant_Narrowing: { // A constant value was narrowed. - QualType T = EntityType.getNonReferenceType(); - S.Diag(PostInit->getBeginLoc(), - NarrowingErrs(S.getLangOpts()) - ? (T == EntityType - ? diag::ext_init_list_constant_narrowing - : diag::ext_init_list_constant_narrowing_const_reference) - : diag::warn_init_list_constant_narrowing) - << PostInit->getSourceRange() + MakeDiag(EntityType.getNonReferenceType() != EntityType, + diag::ext_init_list_constant_narrowing, + diag::ext_init_list_constant_narrowing_const_reference, + diag::warn_init_list_constant_narrowing) << ConstantValue.getAsString(S.getASTContext(), ConstantType) << EntityType.getNonReferenceType().getLocalUnqualifiedType(); break; @@ -10446,14 +10446,10 @@ static void DiagnoseNarrowingInInitList(Sema &S, case NK_Variable_Narrowing: { // A variable's value may have been narrowed. - QualType T = EntityType.getNonReferenceType(); - S.Diag(PostInit->getBeginLoc(), - NarrowingErrs(S.getLangOpts()) - ? (T == EntityType - ? diag::ext_init_list_variable_narrowing - : diag::ext_init_list_variable_narrowing_const_reference) - : diag::warn_init_list_variable_narrowing) - << PostInit->getSourceRange() + MakeDiag(EntityType.getNonReferenceType() != EntityType, + diag::ext_init_list_variable_narrowing, + diag::ext_init_list_variable_narrowing_const_reference, + diag::warn_init_list_variable_narrowing) << PreNarrowingType.getLocalUnqualifiedType() << EntityType.getNonReferenceType().getLocalUnqualifiedType(); break; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 9fb7671..e6c267b 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1259,6 +1259,43 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, if ((OldTemplate == nullptr) != (NewTemplate == nullptr)) return true; + if (NewTemplate) { + // C++ [temp.over.link]p4: + // The signature of a function template consists of its function + // signature, its return type and its template parameter list. The names + // of the template parameters are significant only for establishing the + // relationship between the template parameters and the rest of the + // signature. + // + // We check the return type and template parameter lists for function + // templates first; the remaining checks follow. + bool SameTemplateParameterList = SemaRef.TemplateParameterListsAreEqual( + NewTemplate, NewTemplate->getTemplateParameters(), OldTemplate, + OldTemplate->getTemplateParameters(), false, Sema::TPL_TemplateMatch); + bool SameReturnType = SemaRef.Context.hasSameType( + Old->getDeclaredReturnType(), New->getDeclaredReturnType()); + // FIXME(GH58571): Match template parameter list even for non-constrained + // template heads. This currently ensures that the code prior to C++20 is + // not newly broken. + bool ConstraintsInTemplateHead = + NewTemplate->getTemplateParameters()->hasAssociatedConstraints() || + OldTemplate->getTemplateParameters()->hasAssociatedConstraints(); + // C++ [namespace.udecl]p11: + // The set of declarations named by a using-declarator that inhabits a + // class C does not include member functions and member function + // templates of a base class that "correspond" to (and thus would + // conflict with) a declaration of a function or function template in + // C. + // Comparing return types is not required for the "correspond" check to + // decide whether a member introduced by a shadow declaration is hidden. + if (UseMemberUsingDeclRules && ConstraintsInTemplateHead && + !SameTemplateParameterList) + return true; + if (!UseMemberUsingDeclRules && + (!SameTemplateParameterList || !SameReturnType)) + return true; + } + // Is the function New an overload of the function Old? QualType OldQType = SemaRef.Context.getCanonicalType(Old->getType()); QualType NewQType = SemaRef.Context.getCanonicalType(New->getType()); @@ -1410,43 +1447,6 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, } } - if (NewTemplate) { - // C++ [temp.over.link]p4: - // The signature of a function template consists of its function - // signature, its return type and its template parameter list. The names - // of the template parameters are significant only for establishing the - // relationship between the template parameters and the rest of the - // signature. - // - // We check the return type and template parameter lists for function - // templates first; the remaining checks follow. - bool SameTemplateParameterList = SemaRef.TemplateParameterListsAreEqual( - NewTemplate, NewTemplate->getTemplateParameters(), OldTemplate, - OldTemplate->getTemplateParameters(), false, Sema::TPL_TemplateMatch); - bool SameReturnType = SemaRef.Context.hasSameType( - Old->getDeclaredReturnType(), New->getDeclaredReturnType()); - // FIXME(GH58571): Match template parameter list even for non-constrained - // template heads. This currently ensures that the code prior to C++20 is - // not newly broken. - bool ConstraintsInTemplateHead = - NewTemplate->getTemplateParameters()->hasAssociatedConstraints() || - OldTemplate->getTemplateParameters()->hasAssociatedConstraints(); - // C++ [namespace.udecl]p11: - // The set of declarations named by a using-declarator that inhabits a - // class C does not include member functions and member function - // templates of a base class that "correspond" to (and thus would - // conflict with) a declaration of a function or function template in - // C. - // Comparing return types is not required for the "correspond" check to - // decide whether a member introduced by a shadow declaration is hidden. - if (UseMemberUsingDeclRules && ConstraintsInTemplateHead && - !SameTemplateParameterList) - return true; - if (!UseMemberUsingDeclRules && - (!SameTemplateParameterList || !SameReturnType)) - return true; - } - if (!UseOverrideRules) { Expr *NewRC = New->getTrailingRequiresClause(), *OldRC = Old->getTrailingRequiresClause(); @@ -13994,21 +13994,19 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, OverloadCandidateSet::iterator Best; OverloadingResult OverloadResult = CandidateSet.BestViableFunction(*this, Fn->getBeginLoc(), Best); - FunctionDecl *FDecl = Best->Function; // Model the case with a call to a templated function whose definition // encloses the call and whose return type contains a placeholder type as if // the UnresolvedLookupExpr was type-dependent. - if (OverloadResult == OR_Success && FDecl && - FDecl->isTemplateInstantiation() && - FDecl->getReturnType()->isUndeducedType()) { - if (auto TP = FDecl->getTemplateInstantiationPattern(false)) { - if (TP->willHaveBody()) { - CallExpr *CE = - CallExpr::Create(Context, Fn, Args, Context.DependentTy, VK_PRValue, - RParenLoc, CurFPFeatureOverrides()); - result = CE; - return result; + if (OverloadResult == OR_Success) { + const FunctionDecl *FDecl = Best->Function; + if (FDecl && FDecl->isTemplateInstantiation() && + FDecl->getReturnType()->isUndeducedType()) { + if (const auto *TP = + FDecl->getTemplateInstantiationPattern(/*ForDefinition=*/false); + TP && TP->willHaveBody()) { + return CallExpr::Create(Context, Fn, Args, Context.DependentTy, + VK_PRValue, RParenLoc, CurFPFeatureOverrides()); } } } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 09dd119..7f20413 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -344,15 +344,26 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( using namespace TemplateInstArgsHelpers; const Decl *CurDecl = ND; + + if (!CurDecl) + CurDecl = Decl::castFromDeclContext(DC); + if (Innermost) { Result.addOuterTemplateArguments(const_cast<NamedDecl *>(ND), Innermost->asArray(), Final); - CurDecl = Response::UseNextDecl(ND).NextDecl; + // Populate placeholder template arguments for TemplateTemplateParmDecls. + // This is essential for the case e.g. + // + // template <class> concept Concept = false; + // template <template <Concept C> class T> void foo(T<int>) + // + // where parameter C has a depth of 1 but the substituting argument `int` + // has a depth of 0. + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) + HandleDefaultTempArgIntoTempTempParam(TTP, Result); + CurDecl = Response::UseNextDecl(CurDecl).NextDecl; } - if (!ND) - CurDecl = Decl::castFromDeclContext(DC); - while (!CurDecl->isFileContextDecl()) { Response R; if (const auto *VarTemplSpec = @@ -380,10 +391,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( R = Response::ChangeDecl(CTD->getLexicalDeclContext()); } else if (!isa<DeclContext>(CurDecl)) { R = Response::DontClearRelativeToPrimaryNextDecl(CurDecl); - if (CurDecl->getDeclContext()->isTranslationUnit()) { - if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) { - R = HandleDefaultTempArgIntoTempTempParam(TTP, Result); - } + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(CurDecl)) { + R = HandleDefaultTempArgIntoTempTempParam(TTP, Result); } } else { R = HandleGenericDeclContext(CurDecl); diff --git a/clang/test/AST/Interp/arrays.cpp b/clang/test/AST/Interp/arrays.cpp index c455731..4aa10da5 100644 --- a/clang/test/AST/Interp/arrays.cpp +++ b/clang/test/AST/Interp/arrays.cpp @@ -72,6 +72,14 @@ constexpr int getElementFromEnd(const int *Arr, int size, int index) { static_assert(getElementFromEnd(data, 5, 0) == 1, ""); static_assert(getElementFromEnd(data, 5, 4) == 5, ""); +constexpr int getFirstElem(const int *a) { + return a[0]; // expected-note {{read of dereferenced null pointer}} \ + // ref-note {{read of dereferenced null pointer}} +} +static_assert(getFirstElem(nullptr) == 1, ""); // expected-error {{not an integral constant expression}} \ + // expected-note {{in call to}} \ + // ref-error {{not an integral constant expression}} \ + // ref-note {{in call to}} constexpr static int arr[2] = {1,2}; constexpr static int arr2[2] = {3,4}; diff --git a/clang/test/CXX/over/over.load/p2-0x.cpp b/clang/test/CXX/over/over.load/p2-0x.cpp index 183f3cb..8fd9a1c 100644 --- a/clang/test/CXX/over/over.load/p2-0x.cpp +++ b/clang/test/CXX/over/over.load/p2-0x.cpp @@ -24,6 +24,11 @@ class Y { void k() &&; // expected-error{{cannot overload a member function with ref-qualifier '&&' with a member function without a ref-qualifier}} }; +struct GH76358 { + template<int> void f() && {} + template<typename T> void f() const {} +}; + #if __cplusplus >= 202002L namespace GH58962 { diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp index 449b623..f586069 100644 --- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp +++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp @@ -59,3 +59,32 @@ struct Nothing {}; // FIXME: Wait the standard to clarify the intent. template<> template<> Z<Nothing> S5<Z>::V<Nothing>; + +namespace GH57410 { + +template<typename T> +concept True = true; + +template<typename T> +concept False = false; // #False + +template <class> struct S {}; + +template<template<True T> typename Wrapper> +using Test = Wrapper<int>; + +template<template<False T> typename Wrapper> // #TTP-Wrapper +using Test = Wrapper<int>; // expected-error {{constraints not satisfied for template template parameter 'Wrapper' [with T = int]}} + +// expected-note@#TTP-Wrapper {{'int' does not satisfy 'False'}} +// expected-note@#False {{evaluated to false}} + +template <typename U, template<False> typename T> +void foo(T<U>); // #foo + +void bar() { + foo<int>(S<int>{}); // expected-error {{no matching function for call to 'foo'}} + // expected-note@#foo {{substitution failure [with U = int]: constraints not satisfied for template template parameter 'T' [with $0 = int]}} +} + +} diff --git a/clang/test/CodeGen/RISCV/riscv-func-attr-target.c b/clang/test/CodeGen/RISCV/riscv-func-attr-target.c index 506acab..759c33a 100644 --- a/clang/test/CodeGen/RISCV/riscv-func-attr-target.c +++ b/clang/test/CodeGen/RISCV/riscv-func-attr-target.c @@ -40,8 +40,8 @@ __attribute__((target("cpu=sifive-u54"))) void testAttrCpuOnly() {} // CHECK: attributes #1 = { {{.*}}"target-cpu"="rocket-rv64" "target-features"="+64bit,+a,+d,+f,+m,+save-restore,+v,+zicsr,+zifencei,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b,-relax,-zbb,-zfa" "tune-cpu"="generic-rv64" } // CHECK: attributes #2 = { {{.*}}"target-features"="+64bit,+a,+m,+save-restore,+zbb,+zifencei,-relax,-zfa" } // CHECK: attributes #3 = { {{.*}}"target-features"="+64bit,+a,+d,+experimental-zicond,+f,+m,+save-restore,+v,+zbb,+zicsr,+zifencei,+zve32f,+zve32x,+zve64d,+zve64f,+zve64x,+zvl128b,+zvl32b,+zvl64b,-relax,-zfa" } -// CHECK: attributes #4 = { {{.*}}"target-features"="+64bit,+a,+c,+d,+f,+m,+save-restore,+zbb,+zicsr,+zifencei,-relax,-zfa" } -// CHECK: attributes #5 = { {{.*}}"target-features"="+64bit,+m,+save-restore,-relax,-zbb,-zfa" } +// CHECK: attributes #4 = { {{.*}}"target-features"="+64bit,+a,+c,+d,+f,+m,+save-restore,+zbb,+zicsr,+zifencei,-relax" } +// CHECK: attributes #5 = { {{.*}}"target-features"="+64bit,+m,+save-restore,-relax" } // CHECK: attributes #6 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+a,+m,+save-restore,+zbb,+zifencei,-relax,-zfa" } -// CHECK: attributes #7 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+m,+save-restore,-relax,-zbb,-zfa" } -// CHECK: attributes #8 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+a,+c,+d,+f,+m,+save-restore,+zicsr,+zifencei,-relax,-zbb,-zfa" } +// CHECK: attributes #7 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+m,+save-restore,-relax" } +// CHECK: attributes #8 = { {{.*}}"target-cpu"="sifive-u54" "target-features"="+64bit,+a,+c,+d,+f,+m,+save-restore,+zicsr,+zifencei,-relax" } diff --git a/clang/test/Driver/linker-wrapper-image.c b/clang/test/Driver/linker-wrapper-image.c index 40dde2e..03caa1e 100644 --- a/clang/test/Driver/linker-wrapper-image.c +++ b/clang/test/Driver/linker-wrapper-image.c @@ -19,7 +19,7 @@ // OPENMP-COFF: @__start_omp_offloading_entries = hidden constant [0 x %struct.__tgt_offload_entry] zeroinitializer, section "omp_offloading_entries$OA" // OPENMP-COFF-NEXT: @__stop_omp_offloading_entries = hidden constant [0 x %struct.__tgt_offload_entry] zeroinitializer, section "omp_offloading_entries$OZ" -// OPENMP-NEXT: @.omp_offloading.device_image = internal unnamed_addr constant [[[SIZE:[0-9]+]] x i8] c"\10\FF\10\AD\01{{.*}}", section ".llvm.offloading", align 8 +// OPENMP: @.omp_offloading.device_image = internal unnamed_addr constant [[[SIZE:[0-9]+]] x i8] c"\10\FF\10\AD{{.*}}", section ".llvm.offloading", align 8 // OPENMP-NEXT: @.omp_offloading.device_images = internal unnamed_addr constant [1 x %__tgt_device_image] [%__tgt_device_image { ptr getelementptr inbounds ([[[BEGIN:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 1, i64 0), ptr getelementptr inbounds ([[[END:[0-9]+]] x i8], ptr @.omp_offloading.device_image, i64 1, i64 0), ptr @__start_omp_offloading_entries, ptr @__stop_omp_offloading_entries }] // OPENMP-NEXT: @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 1, ptr @.omp_offloading.device_images, ptr @__start_omp_offloading_entries, ptr @__stop_omp_offloading_entries } // OPENMP-NEXT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 1, ptr @.omp_offloading.descriptor_reg, ptr null }] diff --git a/clang/test/Driver/mingw-sysroot.cpp b/clang/test/Driver/mingw-sysroot.cpp index 911dab4..50152b2 100644 --- a/clang/test/Driver/mingw-sysroot.cpp +++ b/clang/test/Driver/mingw-sysroot.cpp @@ -14,6 +14,12 @@ // RUN: ln -s %S/Inputs/mingw_ubuntu_posix_tree/usr/x86_64-w64-mingw32 %T/testroot-clang/x86_64-w64-mingw32 // RUN: ln -s %S/Inputs/mingw_arch_tree/usr/i686-w64-mingw32 %T/testroot-clang/i686-w64-mingw32 +// RUN: rm -rf %T/testroot-clang-native +// RUN: mkdir -p %T/testroot-clang-native/bin +// RUN: ln -s %clang %T/testroot-clang-native/bin/clang +// RUN: mkdir -p %T/testroot-clang-native/include/_mingw.h +// RUN: mkdir -p %T/testroot-clang-native/lib/libkernel32.a + // RUN: rm -rf %T/testroot-custom-triple // RUN: mkdir -p %T/testroot-custom-triple/bin // RUN: ln -s %clang %T/testroot-custom-triple/bin/clang @@ -58,6 +64,28 @@ // RUN: env "PATH=%T/testroot-gcc/bin:%PATH%" %T/testroot-gcc/bin/x86_64-w64-mingw32-clang -target x86_64-w64-mingw32 -rtlib=platform -stdlib=libstdc++ --sysroot="" -c -### %s 2>&1 | FileCheck -check-prefix=CHECK_TESTROOT_GCC %s +// If we're executing clang from a directory with what looks like a mingw sysroot, +// with headers in <base>/include and libs in <base>/lib, use that rather than looking +// for another GCC in the path. +// +// Note, this test has a surprising quirk: We're testing with an install directory, +// testroot-clang-native, which lacks the "x86_64-w64-mingw32" subdirectory, it only +// has the include and lib subdirectories without any triple prefix. +// +// Since commit fd15cb935d7aae25ad62bfe06fe9f17cea585978, we avoid using the +// <base>/include and <base>/lib directories when cross compiling. So technically, this +// case testcase only works exactly as expected when running on x86_64 Windows, when +// this target isn't considered cross compiling. +// +// However we do still pass the include directory <base>/x86_64-w64-mingw32/include to +// the -cc1 interface, even if it is missing. Thus, this test looks for this path name, +// that indicates that we did choose the right base, even if this particular directory +// actually doesn't exist here. + +// RUN: env "PATH=%T/testroot-gcc/bin:%PATH%" %T/testroot-clang-native/bin/clang -target x86_64-w64-mingw32 -rtlib=compiler-rt -stdlib=libstdc++ --sysroot="" -c -### %s 2>&1 | FileCheck -check-prefix=CHECK_TESTROOT_CLANG_NATIVE %s +// CHECK_TESTROOT_CLANG_NATIVE: "{{[^"]+}}/testroot-clang-native{{/|\\\\}}x86_64-w64-mingw32{{/|\\\\}}include" + + // If the user requests a different arch via the -m32 option, which changes // x86_64 into i386, check that the driver notices that it can't find a // sysroot for i386 but there is one for i686, and uses that one. diff --git a/clang/test/Driver/riscv-rvv-vector-bits.c b/clang/test/Driver/riscv-rvv-vector-bits.c index e92b66c..24af5f0 100644 --- a/clang/test/Driver/riscv-rvv-vector-bits.c +++ b/clang/test/Driver/riscv-rvv-vector-bits.c @@ -44,7 +44,7 @@ // CHECK-BAD-VALUE-ERROR: error: unsupported argument '{{.*}}' to option '-mrvv-vector-bits=' -// Error if using attribute without -msve-vector-bits=<bits> or if using -msve-vector-bits=<bits>+ syntax +// Error if using attribute without -mrvv-vector-bits=<bits> or if using -mrvv-vector-bits=<bits>+ syntax // ----------------------------------------------------------------------------- // RUN: not %clang -c %s -o /dev/null -target riscv64-linux-gnu \ // RUN: -march=rv64gc_zve64x 2>&1 | FileCheck --check-prefix=CHECK-NO-FLAG-ERROR %s diff --git a/clang/test/Modules/Inputs/AutolinkTBD.framework/AutolinkTBD.tbd b/clang/test/Modules/Inputs/AutolinkTBD.framework/AutolinkTBD.tbd deleted file mode 100644 index 4aa0f85..0000000 --- a/clang/test/Modules/Inputs/AutolinkTBD.framework/AutolinkTBD.tbd +++ /dev/null @@ -1 +0,0 @@ -empty file - clang only needs to check if it exists. diff --git a/clang/test/Modules/Inputs/AutolinkTBD.framework/Headers/AutolinkTBD.h b/clang/test/Modules/Inputs/AutolinkTBD.framework/Headers/AutolinkTBD.h deleted file mode 100644 index 914983c..0000000 --- a/clang/test/Modules/Inputs/AutolinkTBD.framework/Headers/AutolinkTBD.h +++ /dev/null @@ -1 +0,0 @@ -extern int foo(void); diff --git a/clang/test/Modules/autolinkTBD.m b/clang/test/Modules/autolinkTBD.m deleted file mode 100644 index 69253294..0000000 --- a/clang/test/Modules/autolinkTBD.m +++ /dev/null @@ -1,16 +0,0 @@ -// UNSUPPORTED: target={{.*}}-zos{{.*}}, target={{.*}}-aix{{.*}} -// RUN: rm -rf %t -// RUN: %clang_cc1 -emit-llvm -o - -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs %s | FileCheck %s -// RUN: %clang_cc1 -emit-llvm -fno-autolink -o - -fmodules-cache-path=%t -fmodules -fimplicit-module-maps -F %S/Inputs %s | FileCheck --check-prefix=CHECK-AUTOLINK-DISABLED %s - -@import AutolinkTBD; - -int f(void) { - return foo(); -} - -// CHECK: !llvm.linker.options = !{![[AUTOLINK_FRAMEWORK:[0-9]+]]} -// CHECK: ![[AUTOLINK_FRAMEWORK]] = !{!"-framework", !"AutolinkTBD"} - -// CHECK-AUTOLINK-DISABLED: !llvm.module.flags -// CHECK-AUTOLINK-DISABLED-NOT: !llvm.linker.options diff --git a/clang/test/Modules/autolink_private_module.m b/clang/test/Modules/autolink_private_module.m new file mode 100644 index 0000000..54bebc3 --- /dev/null +++ b/clang/test/Modules/autolink_private_module.m @@ -0,0 +1,25 @@ +// Test that autolink hints for frameworks don't use the private module name. +// RUN: rm -rf %t && mkdir %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -emit-llvm -o - -fmodules-cache-path=%t/ModuleCache -fmodules -fimplicit-module-maps -F %t/Frameworks %t/test.m | FileCheck %s + +// CHECK: !{!"-framework", !"Autolink"} +// CHECK-NOT: !{!"-framework", !"Autolink_Private"} + +//--- test.m +#include <Autolink/Autolink.h> +#include <Autolink/Autolink_Private.h> + +//--- Frameworks/Autolink.framework/Headers/Autolink.h +void public(); + +//--- Frameworks/Autolink.framework/PrivateHeaders/Autolink_Private.h +void private(); + +//--- Frameworks/Autolink.framework/Modules/module.modulemap +framework module Autolink { header "Autolink.h"} + +//--- Frameworks/Autolink.framework/Modules/module.private.modulemap +framework module Autolink_Private { header "Autolink_Private.h"} + diff --git a/clang/test/Modules/explicit-specializations.cppm b/clang/test/Modules/explicit-specializations.cppm new file mode 100644 index 0000000..9141440 --- /dev/null +++ b/clang/test/Modules/explicit-specializations.cppm @@ -0,0 +1,133 @@ +// Testing that the compiler can select the correct template specialization +// from different template aliasing. +// +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/b.cpp -fprebuilt-module-path=%t \ +// RUN: -fsyntax-only -verify + +//--- a.cppm + +// For template type parameters +export module a; +export template <class C> +struct S { + static constexpr bool selected = false; +}; + +export struct A {}; + +export template <> +struct S<A> { + static constexpr bool selected = true; +}; + +export using B = A; + +// For template template parameters + +export template <template<typename> typename C> +struct V { + static constexpr bool selected = false; +}; + +export template <> +struct V<S> { + static constexpr bool selected = true; +}; + +// For template non type parameters +export template <int X> +struct Numbers { + static constexpr bool selected = false; + static constexpr int value = X; +}; + +export template<> +struct Numbers<43> { + static constexpr bool selected = true; + static constexpr int value = 43; +}; + +export template <const int *> +struct Pointers { + static constexpr bool selected = false; +}; + +export int IntegralValue = 0; +export template<> +struct Pointers<&IntegralValue> { + static constexpr bool selected = true; +}; + +export template <void *> +struct NullPointers { + static constexpr bool selected = false; +}; + +export template<> +struct NullPointers<nullptr> { + static constexpr bool selected = true; +}; + +export template<int (&)[5]> +struct Array { + static constexpr bool selected = false; +}; + +export int array[5]; +export template<> +struct Array<array> { + static constexpr bool selected = true; +}; + +//--- b.cpp +// expected-no-diagnostics +import a; + +// Testing for different qualifiers +static_assert(S<B>::selected); +static_assert(S<::B>::selected); +static_assert(::S<B>::selected); +static_assert(::S<::B>::selected); +typedef A C; +static_assert(S<C>::selected); +static_assert(S<::C>::selected); +static_assert(::S<C>::selected); +static_assert(::S<::C>::selected); + +namespace D { + C getAType(); + typedef C E; +} + +static_assert(S<D::E>::selected); +static_assert(S<decltype(D::getAType())>::selected); + +// Testing we can select the correct specialization for different +// template template argument alising. + +static_assert(V<S>::selected); +static_assert(V<::S>::selected); +static_assert(::V<S>::selected); +static_assert(::V<::S>::selected); + +// Testing for template non type parameters +static_assert(Numbers<43>::selected); +static_assert(Numbers<21 * 2 + 1>::selected); +static_assert(Numbers<42 + 1>::selected); +static_assert(Numbers<44 - 1>::selected); +static_assert(Numbers<Numbers<43>::value>::selected); +static_assert(!Numbers<44>::selected); + +static_assert(Pointers<&IntegralValue>::selected); +static_assert(!Pointers<nullptr>::selected); +static_assert(NullPointers<nullptr>::selected); +static_assert(!NullPointers<(void*)&IntegralValue>::selected); + +static_assert(Array<array>::selected); +int another_array[5]; +static_assert(!Array<another_array>::selected); diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c index aedf0c7..b247210 100644 --- a/clang/test/ParserOpenACC/parse-clauses.c +++ b/clang/test/ParserOpenACC/parse-clauses.c @@ -148,8 +148,92 @@ void DefaultClause() { // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} #pragma acc serial default(present), seq for(;;){} +} + +void IfClause() { + // expected-error@+2{{expected '('}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial loop if + for(;;){} + // expected-error@+2{{expected '('}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if seq + for(;;){} + + // expected-error@+2{{expected '('}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if, seq + for(;;){} + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if( + for(;;){} + // expected-error@+2{{use of undeclared identifier 'seq'}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if( seq + for(;;){} + + // expected-error@+3{{expected expression}} + // expected-error@+2{{use of undeclared identifier 'seq'}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if(, seq + for(;;){} + + // expected-error@+3{{expected '('}} + // expected-error@+2{{expected identifier}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if) + for(;;){} + + // expected-error@+3{{expected '('}} + // expected-error@+2{{expected identifier}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if) seq + for(;;){} + + // expected-error@+3{{expected '('}} + // expected-error@+2{{expected identifier}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if), seq + for(;;){} + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if() + for(;;){} + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if() seq + for(;;){} + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if(), seq + for(;;){} + + // expected-error@+2{{use of undeclared identifier 'invalid_expr'}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if(invalid_expr) + for(;;){} + + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if() seq + for(;;){} + + int i, j; + + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if(i > j) + for(;;){} + + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial if(1+5>3), seq + for(;;){} } // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} diff --git a/clang/test/Sema/attr-format-Float16.c b/clang/test/Sema/attr-format-Float16.c new file mode 100644 index 0000000..6c3dfe1 --- /dev/null +++ b/clang/test/Sema/attr-format-Float16.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux-pc -target-feature +sse2 %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux-pc %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple spir-unknown-unknown %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple armv7a-linux-gnu %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-linux-gnu %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple riscv32 %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple riscv64 %s + +void a(const char *a, ...) __attribute__((format(printf, 1, 2))); // no-error + +void b(char *a, _Float16 b) __attribute__((format(printf, 1, 2))); // expected-warning {{GCC requires a function with the 'format' attribute to be variadic}} + +void call_no_default_promotion(void) { + a("%f", (_Float16)1.0); // expected-warning{{format specifies type 'double' but the argument has type '_Float16'}} + b("%f", (_Float16)1.0); // expected-warning{{format specifies type 'double' but the argument has type '_Float16'}} +} diff --git a/clang/test/SemaCXX/attr-format-Float16.cpp b/clang/test/SemaCXX/attr-format-Float16.cpp new file mode 100644 index 0000000..c61611d --- /dev/null +++ b/clang/test/SemaCXX/attr-format-Float16.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -triple i686-linux-pc -target-feature +sse2 %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple x86_64-linux-pc %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple spir-unknown-unknown %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple armv7a-linux-gnu %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-linux-gnu %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple riscv32 %s +// RUN: %clang_cc1 -fsyntax-only -verify -triple riscv64 %s + +template <typename... Args> +__attribute__((format(printf, 1, 2))) +void format(const char *fmt, Args &&...args); // expected-warning{{GCC requires a function with the 'format' attribute to be variadic}} + +template<typename... Args> +__attribute__((format(scanf, 1, 2))) +int scan(const char *fmt, Args &&...args); // expected-warning{{GCC requires a function with the 'format' attribute to be variadic}} + +void do_format() { + format("%f", (_Float16)123.f); // expected-warning{{format specifies type 'double' but the argument has type '_Float16'}} + + _Float16 Float16; + scan("%f", &Float16); // expected-warning{{format specifies type 'float *' but the argument has type '_Float16 *'}} + scan("%lf", &Float16); // expected-warning{{format specifies type 'double *' but the argument has type '_Float16 *'}} + scan("%Lf", &Float16); // expected-warning{{format specifies type 'long double *' but the argument has type '_Float16 *'}} +} diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 881993e..25ef5c6 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -26708,6 +26708,8 @@ TEST_F(FormatTest, PPBranchesInBracedInit) { TEST_F(FormatTest, StreamOutputOperator) { verifyFormat("std::cout << \"foo\" << \"bar\" << baz;"); + verifyFormat("std::cout << \"foo\\n\"\n" + " << \"bar\";"); } TEST_F(FormatTest, BreakAdjacentStringLiterals) { diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 2cafc04..decc078 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -2499,6 +2499,15 @@ TEST_F(TokenAnnotatorTest, BraceKind) { EXPECT_BRACE_KIND(Tokens[6], BK_Block); } +TEST_F(TokenAnnotatorTest, StreamOperator) { + auto Tokens = annotate("\"foo\\n\" << aux << \"foo\\n\" << \"foo\";"); + ASSERT_EQ(Tokens.size(), 9u) << Tokens; + EXPECT_FALSE(Tokens[1]->MustBreakBefore); + EXPECT_FALSE(Tokens[3]->MustBreakBefore); + // Only break between string literals if the former ends with \n. + EXPECT_TRUE(Tokens[5]->MustBreakBefore); +} + } // namespace } // namespace format } // namespace clang |