https://github.com/osamakader updated https://github.com/llvm/llvm-project/pull/166004
>From b953ef3b73c99738144568b70a396b5cfd80ebaa Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Tue, 16 Dec 2025 21:25:35 +0100 Subject: [PATCH 01/10] Fix handling of 'auto' type specifier conflicts This commit fixes several issues related to 'auto' type specifier handling. Core implementation: - Add ConflictingTypeSpecifier flag to DeclSpec to track when 'auto' conflicts with another type specifier (e.g., 'auto int' or 'int auto'). This allows Finish() to properly handle the conflict based on language mode rather than immediately emitting an error during parsing. 1. Fix 'auto auto' duplicate detection: Keep TypeSpecType as TST_auto after emitting error so subsequent checks can emit function-specific errors (e.g., 'not allowed in function prototype'). 2. Fix OpenCL 'auto' and 'register' storage class errors: Reorder checks to prioritize OpenCL-specific handling before C++11+ checks. Use SetStorageClassSpec to trigger OpenCL validation and emit version-specific error messages. 3. Fix C23 'int auto' and 'constexpr int auto' handling: - For 'constexpr int auto': Treat 'auto' as type specifier conflict (don't convert to storage class), emit single error message. - For 'int auto' without constexpr: Convert 'auto' to storage class specifier (no type conflict error), only emit 'illegal storage class' if applicable. 4. Fix template parameter parsing: Skip type name lookup when 'auto' is set in template parameter context to avoid false ambiguity errors for placeholder variables. 5. Fix concept constraint syntax: Detect 'C<T> auto' pattern and skip type conflict detection for concept constraints. 6. Update test expectations: Align error messages and line numbers with actual diagnostic locations and behavior. Signed-off-by: Osama Abdelkader <[email protected]> --- .../clang/Basic/DiagnosticSemaKinds.td | 2 + clang/include/clang/Sema/DeclSpec.h | 13 +- clang/lib/Parse/ParseDecl.cpp | 66 +++++- clang/lib/Sema/DeclSpec.cpp | 203 ++++++++++++++++++ .../test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp | 105 ++++----- .../dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp | 8 +- .../dcl.spec.auto/p3-generic-lambda-1y.cpp | 10 +- .../dcl.spec/dcl.type/dcl.spec.auto/p3.cpp | 7 +- clang/test/CXX/drs/cwg3xx.cpp | 18 +- clang/test/SemaCXX/auto-cxx0x.cpp | 4 +- clang/test/SemaCXX/class.cpp | 9 +- clang/test/SemaCXX/static-data-member.cpp | 7 +- 12 files changed, 378 insertions(+), 74 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c638c23f24bb5..e022cc3de7612 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2749,6 +2749,8 @@ def err_decltype_auto_invalid : Error< "'decltype(auto)' not allowed here">; def err_decltype_auto_cannot_be_combined : Error< "'decltype(auto)' cannot be combined with other type specifiers">; +def err_auto_type_specifier : Error< + "'auto' cannot be combined with a type specifier">; def err_decltype_auto_function_declarator_not_declaration : Error< "'decltype(auto)' can only be used as a return type " "in a function declaration">; diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 61706bc8f4229..5e0b7345dd899 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -428,6 +428,12 @@ class DeclSpec { SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; SourceLocation TQ_pipeLoc; + // Track conflicting type specifier when 'auto' is set (for Finish() + // detection) + LLVM_PREFERRED_TYPE(TST) + unsigned ConflictingTypeSpecifier : 7; + SourceLocation ConflictingTypeSpecifierLoc; + WrittenBuiltinSpecs writtenBS; void SaveWrittenBuiltinSpecs(); @@ -472,14 +478,14 @@ class DeclSpec { TypeSpecSign(static_cast<unsigned>(TypeSpecifierSign::Unspecified)), TypeSpecType(TST_unspecified), TypeAltiVecVector(false), TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false), - TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false), TypeQualifiers(TQ_unspecified), OB_state(static_cast<unsigned>(OverflowBehaviorState::Unspecified)), FS_inline_specified(false), FS_forceinline_specified(false), FS_virtual_specified(false), FS_noreturn_specified(false), FriendSpecifiedFirst(false), ConstexprSpecifier(static_cast<unsigned>( ConstexprSpecKind::Unspecified)), - Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {} + Attrs(attrFactory), ConflictingTypeSpecifier(TST_unspecified), + ConflictingTypeSpecifierLoc(), writtenBS(), ObjCQualifiers(nullptr) {} // storage-class-specifier SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } @@ -519,6 +525,9 @@ class DeclSpec { return static_cast<TypeSpecifierSign>(TypeSpecSign); } TST getTypeSpecType() const { return (TST)TypeSpecType; } + bool hasConflictingTypeSpecifier() const { + return ConflictingTypeSpecifier != TST_unspecified; + } bool isTypeAltiVecVector() const { return TypeAltiVecVector; } bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; } bool isTypeAltiVecBool() const { return TypeAltiVecBool; } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 55ea562faacaa..4ada0589a363c 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3775,7 +3775,9 @@ void Parser::ParseDeclarationSpecifiers( // This identifier can only be a typedef name if we haven't already seen // a type-specifier. Without this check we misparse: // typedef int X; struct Y { short X; }; as 'short int'. - if (DS.hasTypeSpecifier()) + // However, if 'auto' is set, we need to check if this identifier is a + // type name to detect conflicts (e.g., "auto MyInt"). + if (DS.hasTypeSpecifier() && DS.getTypeSpecType() != DeclSpec::TST_auto) goto DoneWithDeclSpec; // If the token is an identifier named "__declspec" and Microsoft @@ -3860,6 +3862,14 @@ void Parser::ParseDeclarationSpecifiers( DS.isFriendSpecified())) goto DoneWithDeclSpec; + // If 'auto' is set and we're in a template parameter context, the + // identifier is always the parameter name, not a type specifier, so skip + // type name lookup to avoid false ambiguity errors. + if (DS.getTypeSpecType() == DeclSpec::TST_auto && + DSContext == DeclSpecContext::DSC_template_param) { + goto DoneWithDeclSpec; + } + ParsedType TypeRep = Actions.getTypeName( *Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), nullptr, false, false, nullptr, false, false, @@ -3867,11 +3877,16 @@ void Parser::ParseDeclarationSpecifiers( // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. + // However, if 'auto' is already set, we can't have an implicit int. if (!TypeRep) { if (TryAnnotateTypeConstraint()) goto DoneWithDeclSpec; if (Tok.isNot(tok::identifier)) continue; + // If 'auto' is set, the identifier must be a type name or it's an + // error. Don't try to parse it as implicit int. + if (DS.getTypeSpecType() == DeclSpec::TST_auto) + goto DoneWithDeclSpec; ParsedAttributes Attrs(AttrFactory); if (ParseImplicitInt(DS, nullptr, TemplateInfo, AS, DSContext, Attrs)) { if (!Attrs.empty()) { @@ -3883,6 +3898,47 @@ void Parser::ParseDeclarationSpecifiers( goto DoneWithDeclSpec; } + // If 'auto' is set and this identifier is a type name, check if it's + // followed by declarator tokens (like '=', '(', '[', etc.). If so, this + // identifier is likely the variable name, not a type specifier, so we + // should stop parsing declaration specifiers. + // Also check for concept constraint syntax (C<T> auto param) where + // the identifier before 'auto' might be a concept, not a type conflict. + // Also check for template parameters (template<auto V>) and lambda + // parameters + // ([](auto c)) where the identifier is a parameter name, not a type + // conflict. + if (DS.getTypeSpecType() == DeclSpec::TST_auto && TypeRep) { + // Check if the next token indicates this is a declarator + tok::TokenKind NextKind = NextToken().getKind(); + if (NextKind == tok::equal || NextKind == tok::l_paren || + NextKind == tok::l_square || NextKind == tok::amp || + NextKind == tok::ampamp || NextKind == tok::star || + NextKind == tok::coloncolon || NextKind == tok::comma || + NextKind == tok::semi || NextKind == tok::colon || + NextKind == tok::greater || NextKind == tok::r_paren || + NextKind == tok::arrow) { + // This identifier is likely the variable/parameter name, stop parsing + // decl specifiers. Note: ':' is for range-based for loops: + // for (auto Arg: x). + // Note: '>' is for template parameters: template<auto V> + // Note: ')' is for function/lambda parameters: [](auto c) + // Note: '->' is for lambda return types: [](auto c) -> int + goto DoneWithDeclSpec; + } + // Check for concept constraint syntax: C<T> auto param) + // If the identifier is followed by 'auto' and then an identifier that's + // followed by ')', this might be concept syntax, not a type conflict. + if (NextKind == tok::identifier) { + // Look ahead to see if this is followed by ')' (function parameter) + Token AfterNext = GetLookAheadToken(2); + if (AfterNext.is(tok::r_paren)) { + // This might be concept constraint syntax, skip conflict detection + goto DoneWithDeclSpec; + } + } + } + // Likewise, if this is a context where the identifier could be a template // name, check whether this is a deduction guide declaration. CXXScopeSpec SS; @@ -4137,12 +4193,9 @@ void Parser::ParseDeclarationSpecifiers( } }; - if (MayBeTypeSpecifier()) { + if (!getLangOpts().CPlusPlus && MayBeTypeSpecifier()) { isInvalid = DS.SetStorageClassSpec(Actions, DeclSpec::SCS_auto, Loc, PrevSpec, DiagID, Policy); - if (!isInvalid && !getLangOpts().C23) - Diag(Tok, diag::ext_auto_storage_class) - << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); } else isInvalid = DS.SetTypeSpecType(DeclSpec::TST_auto, Loc, PrevSpec, DiagID, Policy); @@ -4700,7 +4753,8 @@ void Parser::ParseDeclarationSpecifiers( DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : Tok.getLocation()); // If the specifier wasn't legal, issue a diagnostic. - if (isInvalid) { + // Skip diagnostic if 'auto' conflict will be handled in Finish() + if (isInvalid && !DS.hasConflictingTypeSpecifier()) { assert(PrevSpec && "Method did not return previous specifier!"); assert(DiagID); diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 660b1805c450e..cb4d416490dea 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -759,6 +759,17 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { + // Store conflicting type specifier for Finish() to detect: + // - If 'auto' is already set, store the conflicting type (e.g., "auto int") + // - If 'auto' is being set after another type, store TST_auto (e.g., "int + // auto") + if (TypeSpecType == TST_auto) { + ConflictingTypeSpecifier = T; + ConflictingTypeSpecifierLoc = TagKwLoc; + } else if (T == TST_auto) { + ConflictingTypeSpecifier = TST_auto; + ConflictingTypeSpecifierLoc = TagKwLoc; + } PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -790,6 +801,17 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { + // Store conflicting type specifier for Finish() to detect: + // - If 'auto' is already set, store the conflicting type (e.g., "auto int") + // - If 'auto' is being set after another type, store TST_auto (e.g., "int + // auto") + if (TypeSpecType == TST_auto) { + ConflictingTypeSpecifier = T; + ConflictingTypeSpecifierLoc = Loc; + } else if (T == TST_auto) { + ConflictingTypeSpecifier = TST_auto; + ConflictingTypeSpecifierLoc = Loc; + } PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -822,6 +844,17 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { + // Store conflicting type specifier for Finish() to detect: + // - If 'auto' is already set, store the conflicting type (e.g., "auto int") + // - If 'auto' is being set after another type, store TST_auto (e.g., "int + // auto") + if (TypeSpecType == TST_auto) { + ConflictingTypeSpecifier = T; + ConflictingTypeSpecifierLoc = TagKwLoc; + } else if (T == TST_auto) { + ConflictingTypeSpecifier = TST_auto; + ConflictingTypeSpecifierLoc = TagKwLoc; + } PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -852,6 +885,17 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { + // Store conflicting type specifier for Finish() to detect: + // - If 'auto' is already set, store the conflicting type (e.g., "auto int") + // - If 'auto' is being set after another type, store TST_auto (e.g., "int + // auto") + if (TypeSpecType == TST_auto) { + ConflictingTypeSpecifier = T; + ConflictingTypeSpecifierLoc = Loc; + } else if (T == TST_auto) { + ConflictingTypeSpecifier = TST_auto; + ConflictingTypeSpecifierLoc = Loc; + } PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -1198,6 +1242,164 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { << Hints[4] << Hints[5] << Hints[6] << Hints[7]; } + // If 'auto' type specifier is combined with another type specifier, we need + // to handle it based on the language: + // - In C++11+: Emit error (cannot combine type specifiers) + // - In C23: Convert 'auto' to storage class (valid) + // - In OpenCL: Convert 'auto' to storage class, then OpenCL will reject it + // Handle both cases: + // - "auto int" (TypeSpecType == TST_auto, ConflictingTypeSpecifier == + // TST_int) + // - "int auto" (TypeSpecType == TST_int, ConflictingTypeSpecifier == + // TST_auto) + if (ConflictingTypeSpecifier != TST_unspecified) { + // Special case: "auto auto" - duplicate 'auto', emit error + if (TypeSpecType == TST_auto && ConflictingTypeSpecifier == TST_auto) { + // Both are 'auto', emit "cannot combine with previous 'auto' declaration + // specifier" error This matches GCC's "duplicate 'auto'" behavior Note: + // We keep TypeSpecType = TST_auto (don't set to TST_error) so that later + // checks in SemaType.cpp can emit "not allowed in function prototype" and + // "not allowed in function return type" errors as needed. + const char *PrevSpec = "auto"; + unsigned DiagID = diag::err_invalid_decl_spec_combination; + S.Diag(ConflictingTypeSpecifierLoc, DiagID) << PrevSpec << PrevSpec; + // Clear the conflict tracking but keep TypeSpecType = TST_auto + ConflictingTypeSpecifier = TST_unspecified; + ConflictingTypeSpecifierLoc = SourceLocation(); + } else if ((S.getLangOpts().C23 && !S.getLangOpts().CPlusPlus) || + (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)) { + // In C23 or C++98, convert 'auto' to storage class specifier + if (TypeSpecType == TST_auto) { + // "auto int" case: Convert 'auto' to storage class specifier + StorageClassSpec = SCS_auto; + StorageClassSpecLoc = TSTLoc; + TypeSpecType = ConflictingTypeSpecifier; + TSTLoc = ConflictingTypeSpecifierLoc; + // Clear the conflict tracking + ConflictingTypeSpecifier = TST_unspecified; + ConflictingTypeSpecifierLoc = SourceLocation(); + } else if (ConflictingTypeSpecifier == TST_auto) { + // "int auto" case: Convert 'auto' to storage class specifier + // In C23, if 'constexpr' is present, treat 'auto' as a type specifier + // conflict with 'int' rather than converting it to storage class, so we + // emit the "cannot combine with previous 'int' declaration specifier" + // error and mark the type as error to prevent further processing. + // Otherwise, convert 'auto' to storage class specifier (no type + // conflict error). + if (S.getLangOpts().C23 && !S.getLangOpts().CPlusPlus && + getConstexprSpecifier() != ConstexprSpecKind::Unspecified) { + // constexpr int auto: treat as type specifier conflict + const char *PrevSpec = + getSpecifierName((TST)TypeSpecType, S.getPrintingPolicy()); + unsigned DiagID = diag::err_invalid_decl_spec_combination; + S.Diag(ConflictingTypeSpecifierLoc, DiagID) << PrevSpec << "auto"; + TypeSpecType = TST_error; + ConflictingTypeSpecifier = TST_unspecified; + ConflictingTypeSpecifierLoc = SourceLocation(); + return; + } + // int auto (without constexpr): Convert 'auto' to storage class + // specifier. No type conflict error - auto is treated as storage class, + // not type specifier. + StorageClassSpec = SCS_auto; + StorageClassSpecLoc = ConflictingTypeSpecifierLoc; + // TypeSpecType already has the correct type (e.g., TST_int) + // Clear the conflict tracking + ConflictingTypeSpecifier = TST_unspecified; + ConflictingTypeSpecifierLoc = SourceLocation(); + } + } else if (S.getLangOpts().OpenCL) { + // For OpenCL (C or C++), convert 'auto' to storage class specifier first + // (OpenCL will then reject it via SetStorageClassSpec checks) + // This must come before the C++11+ check to handle OpenCL C++ + if (TypeSpecType == TST_auto) { + // "auto int" case: Convert 'auto' to storage class specifier + // Use SetStorageClassSpec to trigger OpenCL-specific error checking + const char *PrevSpec = nullptr; + unsigned DiagID = 0; + if (SetStorageClassSpec( + S, SCS_auto, TSTLoc, PrevSpec, DiagID, + S.getPrintingPolicy())) { // OpenCL rejected it, emit the error + // with version string + if (S.getLangOpts().OpenCL && S.getLangOpts().CPlusPlus) { + S.Diag(TSTLoc, DiagID) + << S.getLangOpts().getOpenCLVersionString() << PrevSpec << 1; + } else { + S.Diag(TSTLoc, DiagID) << PrevSpec; + } + TypeSpecType = TST_error; + } else { + StorageClassSpec = SCS_auto; + StorageClassSpecLoc = TSTLoc; + TypeSpecType = ConflictingTypeSpecifier; + TSTLoc = ConflictingTypeSpecifierLoc; + } + // Clear the conflict tracking + ConflictingTypeSpecifier = TST_unspecified; + ConflictingTypeSpecifierLoc = SourceLocation(); + } else if (ConflictingTypeSpecifier == TST_auto) { + // "int auto" case: Convert 'auto' to storage class specifier + // Use SetStorageClassSpec to trigger OpenCL-specific error checking + const char *PrevSpec = nullptr; + unsigned DiagID = 0; + if (SetStorageClassSpec(S, SCS_auto, ConflictingTypeSpecifierLoc, + PrevSpec, DiagID, S.getPrintingPolicy())) { + // OpenCL rejected it, emit the error with version string + if (S.getLangOpts().OpenCL && S.getLangOpts().CPlusPlus) { + S.Diag(ConflictingTypeSpecifierLoc, DiagID) + << S.getLangOpts().getOpenCLVersionString() << PrevSpec << 1; + } else { + S.Diag(ConflictingTypeSpecifierLoc, DiagID) << PrevSpec; + } + TypeSpecType = TST_error; + } else { + StorageClassSpec = SCS_auto; + StorageClassSpecLoc = ConflictingTypeSpecifierLoc; + } + // Clear the conflict tracking + ConflictingTypeSpecifier = TST_unspecified; + ConflictingTypeSpecifierLoc = SourceLocation(); + } + } else if (S.getLangOpts().CPlusPlus && S.getLangOpts().CPlusPlus11 && + !S.getLangOpts().C23) { + // In C++11+ (but not C23 or OpenCL), emit error (cannot combine type + // specifiers) + if (TypeSpecType == TST_auto) { + // "auto int" case + S.Diag(ConflictingTypeSpecifierLoc, diag::err_auto_type_specifier) + << FixItHint::CreateRemoval(ConflictingTypeSpecifierLoc); + } else if (ConflictingTypeSpecifier == TST_auto) { + // "int auto" case + S.Diag(ConflictingTypeSpecifierLoc, diag::err_auto_type_specifier) + << FixItHint::CreateRemoval(ConflictingTypeSpecifierLoc); + } + // Mark as error to prevent further processing + TypeSpecType = TST_error; + } else if (!S.getLangOpts().CPlusPlus) { + // For C, C23, etc., convert 'auto' to storage class specifier + // (This is already handled above for C23, but keep for other C dialects) + // In C, C23, OpenCL, etc., convert 'auto' to storage class specifier + if (TypeSpecType == TST_auto) { + // "auto int" case: Convert 'auto' to storage class specifier + StorageClassSpec = SCS_auto; + StorageClassSpecLoc = TSTLoc; + TypeSpecType = ConflictingTypeSpecifier; + TSTLoc = ConflictingTypeSpecifierLoc; + // Clear the conflict tracking + ConflictingTypeSpecifier = TST_unspecified; + ConflictingTypeSpecifierLoc = SourceLocation(); + } else if (ConflictingTypeSpecifier == TST_auto) { + // "int auto" case: Convert 'auto' to storage class specifier + StorageClassSpec = SCS_auto; + StorageClassSpecLoc = ConflictingTypeSpecifierLoc; + // TypeSpecType already has the correct type (e.g., TST_int) + // Clear the conflict tracking + ConflictingTypeSpecifier = TST_unspecified; + ConflictingTypeSpecifierLoc = SourceLocation(); + } + } + } + // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { // No vector long long without VSX (or ZVector). @@ -1426,6 +1628,7 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { S.getLangOpts().getHLSLVersion() < LangOptions::HLSL_202y && TypeSpecType == TST_auto) S.Diag(TSTLoc, diag::ext_hlsl_auto_type_specifier) << /*HLSL*/ 1; + // Emit warning for 'auto' storage class in pre-C++11 dialects if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11 && StorageClassSpec == SCS_auto) S.Diag(StorageClassSpecLoc, diag::warn_auto_storage_class) diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp index 723a79628116c..3a3f752a9e93b 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.stc/p2.cpp @@ -1,66 +1,75 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify=cxx98 -std=c++98 %s +// RUN: %clang_cc1 -fsyntax-only -verify=cxx11 -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify=cxx17 -std=c++17 %s // The auto or register specifiers can be applied only to names of objects // declared in a block (6.3) or to function parameters (8.4). -auto int ao; // expected-error {{illegal storage class on file-scoped variable}} -#if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} -#endif +auto int ao; +// cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} +// cxx17-error@-2 {{'auto' cannot be combined with a type specifier}} +// cxx98-error@-3 {{illegal storage class on file-scoped variable}} -auto void af(); // expected-error {{illegal storage class on function}} -#if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} -#endif +auto void af(); +// cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} +// cxx17-error@-2 {{'auto' cannot be combined with a type specifier}} +// cxx98-error@-3 {{illegal storage class on function}} -register int ro; // expected-error {{illegal storage class on file-scoped variable}} -#if __cplusplus >= 201703L -// expected-error@-2 {{ISO C++17 does not allow 'register' storage class specifier}} -#elif __cplusplus >= 201103L -// expected-warning@-4 {{'register' storage class specifier is deprecated}} -#endif +register int ro; +// cxx98-error@-1 {{illegal storage class on file-scoped variable}} +// cxx11-error@-2 {{illegal storage class on file-scoped variable}} +// cxx11-warning@-3 {{'register' storage class specifier is deprecated and incompatible with C++17}} +// cxx17-error@-4 {{illegal storage class on file-scoped variable}} +// cxx17-error@-5 {{ISO C++17 does not allow 'register' storage class specifier}} -register void rf(); // expected-error {{illegal storage class on function}} +register void rf(); +// cxx98-error@-1 {{illegal storage class on function}} +// cxx11-error@-2 {{illegal storage class on function}} +// cxx17-error@-3 {{illegal storage class on function}} struct S { - auto int ao; // expected-error {{storage class specified for a member declaration}} -#if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} -#endif - auto void af(); // expected-error {{storage class specified for a member declaration}} -#if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} -#endif + auto int ao; + // cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} + // cxx17-error@-2 {{'auto' cannot be combined with a type specifier}} + // cxx98-error@-3 {{storage class specified for a member declaration}} + auto void af(); + // cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} + // cxx17-error@-2 {{'auto' cannot be combined with a type specifier}} + // cxx98-error@-3 {{storage class specified for a member declaration}} - register int ro; // expected-error {{storage class specified for a member declaration}} - register void rf(); // expected-error {{storage class specified for a member declaration}} + register int ro; + // cxx98-error@-1 {{storage class specified for a member declaration}} + // cxx11-error@-2 {{storage class specified for a member declaration}} + // cxx17-error@-3 {{storage class specified for a member declaration}} + register void rf(); + // cxx98-error@-1 {{storage class specified for a member declaration}} + // cxx11-error@-2 {{storage class specified for a member declaration}} + // cxx17-error@-3 {{storage class specified for a member declaration}} }; void foo(auto int ap, register int rp) { -#if __cplusplus >= 201703L -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} -// expected-error@-3 {{ISO C++17 does not allow 'register' storage class specifier}} -#elif __cplusplus >= 201103L -// expected-warning@-5 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} -// expected-warning@-6 {{'register' storage class specifier is deprecated}} -#endif + // cxx17-error@-1 {{'auto' cannot be combined with a type specifier}} + // cxx17-error@-2 {{ISO C++17 does not allow 'register' storage class specifier}} + // cxx11-error@-3 {{'auto' cannot be combined with a type specifier}} + // cxx11-warning@-4 {{'register' storage class specifier is deprecated and incompatible with C++17}} auto int abo; -#if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} -#endif - auto void abf(); // expected-error {{illegal storage class on function}} -#if __cplusplus >= 201103L // C++11 or later -// expected-warning@-2 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} -#endif + // cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} + // cxx17-error@-2 {{'auto' cannot be combined with a type specifier}} + auto void abf(); + // cxx11-error@-1 {{'auto' cannot be combined with a type specifier}} + // cxx11-warning@-2 {{empty parentheses interpreted as a function declaration}} + // cxx11-note@-3 {{replace parentheses with an initializer to declare a variable}} + // cxx17-error@-4 {{'auto' cannot be combined with a type specifier}} + // cxx17-warning@-5 {{empty parentheses interpreted as a function declaration}} + // cxx17-note@-6 {{replace parentheses with an initializer to declare a variable}} + // cxx98-error@-7 {{illegal storage class on function}} register int rbo; -#if __cplusplus >= 201703L -// expected-error@-2 {{ISO C++17 does not allow 'register' storage class specifier}} -#elif __cplusplus >= 201103L -// expected-warning@-4 {{'register' storage class specifier is deprecated}} -#endif + // cxx17-error@-1 {{ISO C++17 does not allow 'register' storage class specifier}} + // cxx11-warning@-2 {{'register' storage class specifier is deprecated and incompatible with C++17}} - register void rbf(); // expected-error {{illegal storage class on function}} + register void rbf(); + // cxx98-error@-1 {{illegal storage class on function}} + // cxx11-error@-2 {{illegal storage class on function}} + // cxx17-error@-3 {{illegal storage class on function}} } diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp index e8f12156a4242..880014d591706 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-1y.cpp @@ -56,7 +56,13 @@ namespace p3_example { auto x = 5; const auto *v = &x, u = 6; static auto y = 0.0; - auto int r; // expected-warning {{storage class}} expected-error {{file-scope}} + auto int r; +#if __cplusplus >= 201103L + // expected-error@-2 {{'auto' cannot be combined with a type specifier}} +#else + // expected-warning@-4 {{storage class}} + // expected-error@-5 {{file-scope}} +#endif static_assert(is_same<decltype(x), int>(), ""); static_assert(is_same<decltype(v), const int*>(), ""); diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp index ca8d50fe22728..240c673f6b0db 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3-generic-lambda-1y.cpp @@ -63,10 +63,10 @@ int main() auto l = [](auto (*)(auto)) { }; //expected-error{{'auto' not allowed}} //FIXME: These diagnostics might need some work. - auto l2 = [](char auto::*pm) { }; // expected-error {{cannot combine with previous 'char' declaration specifier}} \ - expected-error{{'pm' does not point into a class}} - auto l3 = [](char (auto::*pmf)()) { }; // expected-error{{'auto' not allowed}}\ - expected-error{{'pmf' does not point into a class}}\ - expected-error{{function cannot return function type 'char ()'}} + auto l2 = [](char auto::*pm) { }; //expected-error{{'auto' cannot be combined with a type specifier}}\ + expected-error{{'pm' does not point into a class}} + auto l3 = [](char (auto::*pmf)()) { }; //expected-error{{'auto' not allowed}}\ + expected-error{{'pmf' does not point into a class}}\ + expected-error{{function cannot return function type 'char ()'}} } } diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp index 440c78201293b..8d7765523461c 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.spec.auto/p3.cpp @@ -42,7 +42,12 @@ void p3example() { static auto y = 0.0; // In C++98: 'auto' storage class specifier is redundant and incompatible with C++0x // In C++0x: 'auto' storage class specifier is not permitted in C++0x, and will not be supported in future releases - auto int r; // expected-warning {{'auto' storage class specifier}} + auto int r; +#if __cplusplus >= 201103L + // expected-error@-2 {{'auto' cannot be combined with a type specifier}} +#else + // expected-warning@-4 {{'auto' storage class specifier}} +#endif same<__typeof(x), int> xHasTypeInt; same<__typeof(v), const int*> vHasTypeConstIntPtr; diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp index 10bf57e422f33..923ee43a9ca80 100644 --- a/clang/test/CXX/drs/cwg3xx.cpp +++ b/clang/test/CXX/drs/cwg3xx.cpp @@ -1705,13 +1705,23 @@ namespace cwg395 { // cwg395: 3.0 namespace cwg396 { // cwg396: 3.0 void f() { auto int a(); - // since-cxx11-error@-1 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} - // expected-error@-2 {{illegal storage class on function}} +#if __cplusplus >= 201103L + // expected-error@-2 {{'auto' cannot be combined with a type specifier}} + // expected-warning@-3 {{empty parentheses interpreted as a function declaration}} + // expected-note@-4 {{replace parentheses with an initializer to declare a variable}} +#else + // expected-error@-6 {{illegal storage class on function}} + // since-cxx11-error@-7 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} +#endif int (i); // #cwg396-i auto int (i); - // since-cxx11-error@-1 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} - // expected-error@-2 {{redefinition of 'i'}} +#if __cplusplus >= 201103L + // expected-error@-2 {{'auto' cannot be combined with a type specifier}} +#else + // expected-error@-4 {{redefinition of 'i'}} // expected-note@#cwg396-i {{previous definition is here}} + // since-cxx11-error@-5 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} +#endif } } // namespace cwg396 diff --git a/clang/test/SemaCXX/auto-cxx0x.cpp b/clang/test/SemaCXX/auto-cxx0x.cpp index f429bebb9941a..594cbf40f7179 100644 --- a/clang/test/SemaCXX/auto-cxx0x.cpp +++ b/clang/test/SemaCXX/auto-cxx0x.cpp @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++1y void f() { - auto int a; // expected-warning {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} - int auto b; // expected-error {{cannot combine with previous 'int' declaration specifier}} + auto int a; // expected-error {{'auto' cannot be combined with a type specifier}} + int auto b; // expected-error {{'auto' cannot be combined with a type specifier}} } typedef auto PR25449(); // expected-error {{'auto' not allowed in typedef}} diff --git a/clang/test/SemaCXX/class.cpp b/clang/test/SemaCXX/class.cpp index f1e02d5158aac..71c71a1acc807 100644 --- a/clang/test/SemaCXX/class.cpp +++ b/clang/test/SemaCXX/class.cpp @@ -2,11 +2,12 @@ // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98 -Wc++11-compat %s -std=c++98 class C { public: - auto int errx; // expected-error {{storage class specified for a member declaration}} -#if __cplusplus <= 199711L - // expected-warning@-2 {{'auto' storage class specifier is redundant}} + auto int errx; +#if __cplusplus >= 201103L + // expected-error@-2 {{'auto' cannot be combined with a type specifier}} #else - // expected-warning@-4 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} + // expected-error@-4 {{storage class specified for a member declaration}} + // expected-warning@-5 {{'auto' storage class specifier is redundant}} #endif register int erry; // expected-error {{storage class specified for a member declaration}} extern int errz; // expected-error {{storage class specified for a member declaration}} diff --git a/clang/test/SemaCXX/static-data-member.cpp b/clang/test/SemaCXX/static-data-member.cpp index fb63da9b40099..2dbcae1745e5b 100644 --- a/clang/test/SemaCXX/static-data-member.cpp +++ b/clang/test/SemaCXX/static-data-member.cpp @@ -13,7 +13,12 @@ double ABC::a = 1.0; extern double ABC::b = 1.0; // expected-error {{static data member definition cannot specify a storage class}} static double ABC::c = 1.0; // expected-error {{'static' can only be specified inside the class definition}} __private_extern__ double ABC::d = 1.0; // expected-error {{static data member definition cannot specify a storage class}} -auto double ABC::e = 1.0; // expected-error {{static data member definition cannot specify a storage class}} +auto double ABC::e = 1.0; +#if __cplusplus >= 201103L +// expected-error@-2 {{'auto' cannot be combined with a type specifier}} +#else +// expected-error@-4 {{static data member definition cannot specify a storage class}} +#endif #if __cplusplus < 201703L register double ABC::f = 1.0; // expected-error {{static data member definition cannot specify a storage class}} #endif >From b842181fe6ab357b301bfe06d9d909c01dc16bab Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Sat, 14 Mar 2026 22:02:07 +0100 Subject: [PATCH 02/10] Add more auto type tests, and some refactoring Signed-off-by: Osama Abdelkader <[email protected]> --- clang/include/clang/Sema/DeclSpec.h | 11 ++++------- clang/lib/Parse/ParseDecl.cpp | 15 ++++++--------- clang/test/SemaCXX/auto-cxx0x.cpp | 6 ++++++ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 5e0b7345dd899..36260dd69be31 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -362,6 +362,9 @@ class DeclSpec { unsigned TypeSpecSat : 1; LLVM_PREFERRED_TYPE(bool) unsigned ConstrainedAuto : 1; + // Track conflicting type specifier when 'auto' is set (for Finish() detection) + LLVM_PREFERRED_TYPE(TST) + unsigned ConflictingTypeSpecifier : 7; // type-qualifiers LLVM_PREFERRED_TYPE(TQ) @@ -426,13 +429,7 @@ class DeclSpec { SourceLocation FS_explicitCloseParenLoc; SourceLocation FS_forceinlineLoc; SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; - SourceLocation TQ_pipeLoc; - - // Track conflicting type specifier when 'auto' is set (for Finish() - // detection) - LLVM_PREFERRED_TYPE(TST) - unsigned ConflictingTypeSpecifier : 7; - SourceLocation ConflictingTypeSpecifierLoc; + SourceLocation TQ_pipeLoc, ConflictingTypeSpecifierLoc; WrittenBuiltinSpecs writtenBS; void SaveWrittenBuiltinSpecs(); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 4ada0589a363c..82877b47614d9 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3910,14 +3910,11 @@ void Parser::ParseDeclarationSpecifiers( // conflict. if (DS.getTypeSpecType() == DeclSpec::TST_auto && TypeRep) { // Check if the next token indicates this is a declarator - tok::TokenKind NextKind = NextToken().getKind(); - if (NextKind == tok::equal || NextKind == tok::l_paren || - NextKind == tok::l_square || NextKind == tok::amp || - NextKind == tok::ampamp || NextKind == tok::star || - NextKind == tok::coloncolon || NextKind == tok::comma || - NextKind == tok::semi || NextKind == tok::colon || - NextKind == tok::greater || NextKind == tok::r_paren || - NextKind == tok::arrow) { + Token Next = NextToken(); + if (Next.isOneOf(tok::equal, tok::l_paren, tok::l_square, tok::amp, + tok::ampamp, tok::star, tok::coloncolon, tok::comma, + tok::semi, tok::colon, tok::greater, tok::r_paren, + tok::arrow)) { // This identifier is likely the variable/parameter name, stop parsing // decl specifiers. Note: ':' is for range-based for loops: // for (auto Arg: x). @@ -3929,7 +3926,7 @@ void Parser::ParseDeclarationSpecifiers( // Check for concept constraint syntax: C<T> auto param) // If the identifier is followed by 'auto' and then an identifier that's // followed by ')', this might be concept syntax, not a type conflict. - if (NextKind == tok::identifier) { + if (Next.is(tok::identifier)) { // Look ahead to see if this is followed by ')' (function parameter) Token AfterNext = GetLookAheadToken(2); if (AfterNext.is(tok::r_paren)) { diff --git a/clang/test/SemaCXX/auto-cxx0x.cpp b/clang/test/SemaCXX/auto-cxx0x.cpp index 594cbf40f7179..00ede3358b6b4 100644 --- a/clang/test/SemaCXX/auto-cxx0x.cpp +++ b/clang/test/SemaCXX/auto-cxx0x.cpp @@ -3,6 +3,12 @@ void f() { auto int a; // expected-error {{'auto' cannot be combined with a type specifier}} int auto b; // expected-error {{'auto' cannot be combined with a type specifier}} + unsigned auto int x; // expected-error {{'auto' cannot be combined with a type specifier}} expected-error-re {{'{{.*}}' cannot be signed or unsigned}} + signed auto int s; // expected-error {{'auto' cannot be combined with a type specifier}} expected-error-re {{'{{.*}}' cannot be signed or unsigned}} + auto double y; // expected-error {{'auto' cannot be combined with a type specifier}} + auto float z; // expected-error {{'auto' cannot be combined with a type specifier}} + long auto int l; // expected-error {{'auto' cannot be combined with a type specifier}} expected-error-re {{'long {{.*}}' is invalid}} + auto int arr[10]; // expected-error {{'auto' cannot be combined with a type specifier}} } typedef auto PR25449(); // expected-error {{'auto' not allowed in typedef}} >From db20607696a44513edd0f93f396f94cda342efb9 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Sat, 14 Mar 2026 22:14:56 +0100 Subject: [PATCH 03/10] Fix DeclSpec merge conflict Signed-off-by: Osama Abdelkader <[email protected]> --- clang/include/clang/Sema/DeclSpec.h | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 36260dd69be31..721da6e623333 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -475,6 +475,7 @@ class DeclSpec { TypeSpecSign(static_cast<unsigned>(TypeSpecifierSign::Unspecified)), TypeSpecType(TST_unspecified), TypeAltiVecVector(false), TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false), + TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false), TypeQualifiers(TQ_unspecified), OB_state(static_cast<unsigned>(OverflowBehaviorState::Unspecified)), FS_inline_specified(false), FS_forceinline_specified(false), >From 954cc290d922fcd672abbba13b6b7a7fcbbd4250 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Sat, 14 Mar 2026 22:27:37 +0100 Subject: [PATCH 04/10] Fix format error Signed-off-by: Osama Abdelkader <[email protected]> --- clang/include/clang/Sema/DeclSpec.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 721da6e623333..b3c9a9c0750f6 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -362,7 +362,8 @@ class DeclSpec { unsigned TypeSpecSat : 1; LLVM_PREFERRED_TYPE(bool) unsigned ConstrainedAuto : 1; - // Track conflicting type specifier when 'auto' is set (for Finish() detection) + // Track conflicting type specifier when 'auto' is set (for Finish() + // detection) LLVM_PREFERRED_TYPE(TST) unsigned ConflictingTypeSpecifier : 7; >From 6cc608c1c1f901310250c35b36846c285ec8f079 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Sat, 14 Mar 2026 22:32:50 +0100 Subject: [PATCH 05/10] Reordering constructor initializers to match member declaration order Signed-off-by: Osama Abdelkader <[email protected]> --- clang/include/clang/Sema/DeclSpec.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index b3c9a9c0750f6..e6a6338cfaed2 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -477,14 +477,15 @@ class DeclSpec { TypeSpecType(TST_unspecified), TypeAltiVecVector(false), TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false), TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false), + ConflictingTypeSpecifier(TST_unspecified), TypeQualifiers(TQ_unspecified), OB_state(static_cast<unsigned>(OverflowBehaviorState::Unspecified)), FS_inline_specified(false), FS_forceinline_specified(false), FS_virtual_specified(false), FS_noreturn_specified(false), FriendSpecifiedFirst(false), ConstexprSpecifier(static_cast<unsigned>( ConstexprSpecKind::Unspecified)), - Attrs(attrFactory), ConflictingTypeSpecifier(TST_unspecified), - ConflictingTypeSpecifierLoc(), writtenBS(), ObjCQualifiers(nullptr) {} + Attrs(attrFactory), ConflictingTypeSpecifierLoc(), writtenBS(), + ObjCQualifiers(nullptr) {} // storage-class-specifier SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } >From db56433a7095ff65ebe72be336c9e5bb28a766d7 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Sun, 10 May 2026 16:22:46 +0200 Subject: [PATCH 06/10] clean up ParseDecl auto type part Signed-off-by: Osama Abdelkader <[email protected]> --- clang/lib/Parse/ParseDecl.cpp | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 82877b47614d9..6dc07ee3ddd21 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3898,18 +3898,10 @@ void Parser::ParseDeclarationSpecifiers( goto DoneWithDeclSpec; } - // If 'auto' is set and this identifier is a type name, check if it's - // followed by declarator tokens (like '=', '(', '[', etc.). If so, this - // identifier is likely the variable name, not a type specifier, so we - // should stop parsing declaration specifiers. - // Also check for concept constraint syntax (C<T> auto param) where - // the identifier before 'auto' might be a concept, not a type conflict. - // Also check for template parameters (template<auto V>) and lambda - // parameters - // ([](auto c)) where the identifier is a parameter name, not a type - // conflict. + // If 'auto' is set and this identifier is a type name, stop parsing + // declaration specifiers when the next token indicates this is the + // declarator-id rather than another type specifier. if (DS.getTypeSpecType() == DeclSpec::TST_auto && TypeRep) { - // Check if the next token indicates this is a declarator Token Next = NextToken(); if (Next.isOneOf(tok::equal, tok::l_paren, tok::l_square, tok::amp, tok::ampamp, tok::star, tok::coloncolon, tok::comma, @@ -3923,17 +3915,6 @@ void Parser::ParseDeclarationSpecifiers( // Note: '->' is for lambda return types: [](auto c) -> int goto DoneWithDeclSpec; } - // Check for concept constraint syntax: C<T> auto param) - // If the identifier is followed by 'auto' and then an identifier that's - // followed by ')', this might be concept syntax, not a type conflict. - if (Next.is(tok::identifier)) { - // Look ahead to see if this is followed by ')' (function parameter) - Token AfterNext = GetLookAheadToken(2); - if (AfterNext.is(tok::r_paren)) { - // This might be concept constraint syntax, skip conflict detection - goto DoneWithDeclSpec; - } - } } // Likewise, if this is a context where the identifier could be a template >From d27dc824ee6d9072fbaf28fae9f06c97d0ccd4bf Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Sun, 10 May 2026 16:23:45 +0200 Subject: [PATCH 07/10] use since-cxx11-error for auto type in cwg3xx.cpp test Signed-off-by: Osama Abdelkader <[email protected]> --- clang/test/CXX/drs/cwg3xx.cpp | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp index 923ee43a9ca80..05db04255780b 100644 --- a/clang/test/CXX/drs/cwg3xx.cpp +++ b/clang/test/CXX/drs/cwg3xx.cpp @@ -1704,24 +1704,16 @@ namespace cwg395 { // cwg395: 3.0 namespace cwg396 { // cwg396: 3.0 void f() { - auto int a(); -#if __cplusplus >= 201103L - // expected-error@-2 {{'auto' cannot be combined with a type specifier}} - // expected-warning@-3 {{empty parentheses interpreted as a function declaration}} - // expected-note@-4 {{replace parentheses with an initializer to declare a variable}} -#else - // expected-error@-6 {{illegal storage class on function}} - // since-cxx11-error@-7 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} -#endif + auto int a(); // #cwg396-a + // cxx98-error@#cwg396-a {{illegal storage class on function}} + // since-cxx11-error@#cwg396-a {{'auto' cannot be combined with a type specifier}} + // since-cxx11-warning@#cwg396-a {{empty parentheses interpreted as a function declaration}} + // since-cxx11-note@#cwg396-a {{replace parentheses with an initializer to declare a variable}} int (i); // #cwg396-i - auto int (i); -#if __cplusplus >= 201103L - // expected-error@-2 {{'auto' cannot be combined with a type specifier}} -#else - // expected-error@-4 {{redefinition of 'i'}} - // expected-note@#cwg396-i {{previous definition is here}} - // since-cxx11-error@-5 {{'auto' storage class specifier is not permitted in C++11, and will not be supported in future releases}} -#endif + auto int (i); // #cwg396-auto-i + // cxx98-error@#cwg396-auto-i {{redefinition of 'i'}} + // cxx98-note@#cwg396-i {{previous definition is here}} + // since-cxx11-error@#cwg396-auto-i {{'auto' cannot be combined with a type specifier}} } } // namespace cwg396 >From a13b98edc4daae2ad694864d5b1ca0253dc92348 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Sat, 23 May 2026 18:26:01 +0200 Subject: [PATCH 08/10] refactor conflicting type tracking Signed-off-by: Osama Abdelkader <[email protected]> --- clang/include/clang/Sema/DeclSpec.h | 40 ++++++++++++++++++++++++ clang/lib/Sema/DeclSpec.cpp | 48 +++-------------------------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index e6a6338cfaed2..3e76bfc920152 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -434,6 +434,46 @@ class DeclSpec { WrittenBuiltinSpecs writtenBS; void SaveWrittenBuiltinSpecs(); + void setConflictingTypeSpecifier(TST T, SourceLocation Loc) { + // Store conflicting type specifier for Finish() to detect: + // - If 'auto' is already set, store the conflicting type (e.g., "auto int") + // - If 'auto' is being set after another type, store TST_auto + // (e.g., "int auto"). + if (TypeSpecType == TST_auto) { + ConflictingTypeSpecifier = T; + ConflictingTypeSpecifierLoc = Loc; + } else if (T == TST_auto) { + ConflictingTypeSpecifier = TST_auto; + ConflictingTypeSpecifierLoc = Loc; + } + } + void setConflictingTypeSpecifier(TST T, SourceLocation Loc, + SourceLocation NameLoc, ParsedType Rep) { + setConflictingTypeSpecifier(T, Loc); + if (TypeSpecType == TST_auto) { + TypeRep = Rep; + TSTNameLoc = NameLoc; + TypeSpecOwned = false; + } + } + void setConflictingTypeSpecifier(TST T, SourceLocation Loc, Expr *Rep) { + setConflictingTypeSpecifier(T, Loc); + if (TypeSpecType == TST_auto) { + ExprRep = Rep; + TSTNameLoc = Loc; + TypeSpecOwned = false; + } + } + void setConflictingTypeSpecifier(TST T, SourceLocation Loc, + SourceLocation NameLoc, Decl *Rep, + bool Owned) { + setConflictingTypeSpecifier(T, Loc); + if (TypeSpecType == TST_auto) { + DeclRep = Rep; + TSTNameLoc = NameLoc; + TypeSpecOwned = Owned && Rep != nullptr; + } + } ObjCDeclSpec *ObjCQualifiers; diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index cb4d416490dea..17409acf0c3ed 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -759,17 +759,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { - // Store conflicting type specifier for Finish() to detect: - // - If 'auto' is already set, store the conflicting type (e.g., "auto int") - // - If 'auto' is being set after another type, store TST_auto (e.g., "int - // auto") - if (TypeSpecType == TST_auto) { - ConflictingTypeSpecifier = T; - ConflictingTypeSpecifierLoc = TagKwLoc; - } else if (T == TST_auto) { - ConflictingTypeSpecifier = TST_auto; - ConflictingTypeSpecifierLoc = TagKwLoc; - } + setConflictingTypeSpecifier(T, TagKwLoc, TagNameLoc, Rep); PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -801,17 +791,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { - // Store conflicting type specifier for Finish() to detect: - // - If 'auto' is already set, store the conflicting type (e.g., "auto int") - // - If 'auto' is being set after another type, store TST_auto (e.g., "int - // auto") - if (TypeSpecType == TST_auto) { - ConflictingTypeSpecifier = T; - ConflictingTypeSpecifierLoc = Loc; - } else if (T == TST_auto) { - ConflictingTypeSpecifier = TST_auto; - ConflictingTypeSpecifierLoc = Loc; - } + setConflictingTypeSpecifier(T, Loc, Rep); PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -844,17 +824,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { - // Store conflicting type specifier for Finish() to detect: - // - If 'auto' is already set, store the conflicting type (e.g., "auto int") - // - If 'auto' is being set after another type, store TST_auto (e.g., "int - // auto") - if (TypeSpecType == TST_auto) { - ConflictingTypeSpecifier = T; - ConflictingTypeSpecifierLoc = TagKwLoc; - } else if (T == TST_auto) { - ConflictingTypeSpecifier = TST_auto; - ConflictingTypeSpecifierLoc = TagKwLoc; - } + setConflictingTypeSpecifier(T, TagKwLoc, TagNameLoc, Rep, Owned); PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; @@ -885,17 +855,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, if (TypeSpecType == TST_error) return false; if (TypeSpecType != TST_unspecified) { - // Store conflicting type specifier for Finish() to detect: - // - If 'auto' is already set, store the conflicting type (e.g., "auto int") - // - If 'auto' is being set after another type, store TST_auto (e.g., "int - // auto") - if (TypeSpecType == TST_auto) { - ConflictingTypeSpecifier = T; - ConflictingTypeSpecifierLoc = Loc; - } else if (T == TST_auto) { - ConflictingTypeSpecifier = TST_auto; - ConflictingTypeSpecifierLoc = Loc; - } + setConflictingTypeSpecifier(T, Loc); PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); DiagID = diag::err_invalid_decl_spec_combination; return true; >From 92611c2bcc17c59560bbee0e318d75f176be59a3 Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Sat, 23 May 2026 19:51:47 +0200 Subject: [PATCH 09/10] add c2x auto with typedef specifier Signed-off-by: Osama Abdelkader <[email protected]> --- clang/test/Parser/c2x-auto.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/test/Parser/c2x-auto.c b/clang/test/Parser/c2x-auto.c index d60c96e2b168f..8d40ec0e28267 100644 --- a/clang/test/Parser/c2x-auto.c +++ b/clang/test/Parser/c2x-auto.c @@ -168,6 +168,13 @@ void t1() { int auto d2 = 0; } +void typedef_type_specifiers(void) { + typedef int MyInt; + + auto MyInt a = 0; + MyInt auto b = 0; +} + void t2() { auto long long a1 = 0; long auto long a2 = 0; >From e755a5766fbab2edaca7e30e764fb1259dfa31be Mon Sep 17 00:00:00 2001 From: Osama Abdelkader <[email protected]> Date: Sat, 23 May 2026 19:52:52 +0200 Subject: [PATCH 10/10] add release note - reject auto with type spec in c++ Signed-off-by: Osama Abdelkader <[email protected]> --- clang/docs/ReleaseNotes.rst | 97 ++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c17143e3c0398..1a04fe1fe5e3c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -40,6 +40,37 @@ Potentially Breaking Changes C/C++ Language Potentially Breaking Changes ------------------------------------------- +- Clang now makes it ill-formed to try to ``break`` out of or ``continue`` a loop inside its own condition, + increment, or init-statement in all C and C++ language modes. This means that code such as + + .. code-block:: c++ + + while (({ break; })) {} + + is now ill-formed. An outer loop can still be broken out of or continued so long as the inner loop is + in the body of the outer loop: + + .. code-block:: c++ + + // Ok, this breaks out of the 'for' loop. + for (;;) { + while (({ break; true; })) {} + } + + // Error: can't break out of the 'for' loop from within its own increment. + for (;;({ while (({ break; true; })) {} })) {} + + This also resolves a divergence from GCC: in a construct such as + + .. code-block:: c++ + + for (;;) { + while (({ break; true; })) {} + } + + Clang would previously ``break`` out of the ``while`` loop, whereas GCC (since version 9) would + ``break`` out of the ``for`` loop here. Now, Clang and GCC both break out of the ``for`` loop. + C++ Specific Potentially Breaking Changes ----------------------------------------- @@ -54,6 +85,12 @@ C++ Specific Potentially Breaking Changes matching the deduction of array sizes from ``int(&)[N]``. This is a breaking change for code that depended on the previously deduced type. (#GH195033) +- Clang now rejects nested local classes defined in a different + block scope than their parent class. (#GH193472) + +- Clang now rejects C++ declarations that combine the ``auto`` type specifier + with another type specifier, such as ``auto int``. + ABI Changes in This Version --------------------------- @@ -155,6 +192,8 @@ C++2c Feature Support C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ +- Partially implement Itanium mangling for pack indexing. Partially substituted packs are not yet supported. (#GH112003) + C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -171,12 +210,20 @@ Resolutions to C++ Defect Reports - Clang now allows omitting ``typename`` before a template name in a conversion operator, implementing `CWG2413 <https://wg21.link/cwg2413>`_. +- Clang now uses non-reference types for structured bindings whose initializer + returns a prvalue. This resolves `CWG3135 <https://wg21.link/cwg3135>`_. + C Language Changes ------------------ C2y Feature Support ^^^^^^^^^^^^^^^^^^^ +- Implemented the type-specific C2y ``<stdbit.h>`` rotate functions with constexpr + evaluation support: + ``stdc_rotate_left_{uc,us,ui,ul,ull}`` and + ``stdc_rotate_right_{uc,us,ui,ul,ull}``. + C23 Feature Support ^^^^^^^^^^^^^^^^^^^ - Clang now allows C23 ``constexpr`` struct member access through the dot operator in constant expressions. (#GH178349) @@ -250,6 +297,11 @@ Non-comprehensive list of changes in this release enabling tools such as language servers and refactoring engines to accurately map source locations back to explicit instantiation sites. +- ``typeid`` on references and pointers of ``final`` types no longer emits a + vtable lookup at runtime. + +- Updated support for Unicode from 15.1 to 18.0. + New Compiler Flags ------------------ - New option ``-fms-anonymous-structs`` / ``-fno-ms-anonymous-structs`` added @@ -364,6 +416,13 @@ Attribute Changes in Clang - Clang now allows GNU attributes between a member declarator and bit-field width. (#GH184954) +- The ``[[clang::noescape]]`` attribute now disallows deallocating memory + through the annotated parameter. This information is currently not exposed to + LLVM for optimization purposes, to prevent breaking existing adopters. It may + instead be used by warnings and static analyses to provide more information + about pointer lifetimes. It may be used to power optimizations in the future, + however there are no concrete plans to do so at the moment. + Improvements to Clang's diagnostics ----------------------------------- - Fixed bug in ``-Wdocumentation`` so that it correctly handles explicit @@ -492,6 +551,16 @@ Improvements to Clang's diagnostics - Fixed false positive host-device mismatch errors in discarded `if constexpr` branches for CUDA/HIP; such calls are now correctly skipped. +- Clang now errors when a function declaration aliases a variable or vice versa. (#GH195550) + +- Added ``-Wattribute-alias`` to diagnose type mismatches between an alias and its aliased function. (#GH195550) + +- The diagnostics around ``__block`` now explain why a variable cannot be marked ``__block``. (#GH197213) + +- Extended ``-Wnonportable-include-path`` to warn about trailing whitespace and dots in ``#include`` paths. (#GH190610) + +- Clang now emits error when attribute is missing closing ``]]`` followed by ``;;``. (#GH187223) + Improvements to Clang's time-trace ---------------------------------- @@ -536,6 +605,7 @@ Bug Fixes in This Version - Fixed an issue where an assert was thrown instead of an error if no vulkan env was specified with ``--triple spirv``. (#GH189964) - Fixed incorrect rejection of ``auto`` with reordered declaration specifiers in C23. (#GH164121) - Fixed a crash where constexpr evaluation encountered invalid overrides. (#GH183290) +- Fixed a bug where Clang fails to find instantiation of Decls in constraint checking. (#GH173086) - Fixed a crash when assigning to an element of an ``ext_vector_type`` with ``bool`` element type. (#GH189260) - Fixed a crash caused by declaring multiple ``ownership_returns`` attributes with mismatched or missing arguments. (#GH188733) - Clang now emits an error for friend declarations of lambda members. (#GH26540) @@ -543,6 +613,8 @@ Bug Fixes in This Version - Fixed a crash when parsing invalid ``static_assert`` declarations with string-literal messages (#GH187690). - Fixed a potential stack-use-after-return issue in Clang when copy-initializing an array via an element-at-a-time copy loop (#GH192026) +- Fixed an issue where certain designated initializers would be rejected for constexpr variables. (#GH193373) +- Fixed a crash when ``#embed`` is used with C++ modules (#GH195350) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -563,6 +635,8 @@ Bug Fixes to C++ Support - Clang now rejects constant template parameters with block pointer types, since these are not implemented anyway and would lead to crashes. (#GH189247) - Fixed a crash on error recovery when dealing with invalid templates. (#GH183075) - Fixed a crash when instantiating ``requires`` expressions involving substitution failures in C++ concepts. (#GH176402) +- Concepts appearing in the require-clause of a member function no longer have access to non-public members of that class, + or to a current class object. (#GH115838) (#GH194803) (#GH197067) - We no longer caches invalid variable specializations. (#GH132592) - Fixed an incorrect template argument deduction when matching packs of template template parameters when one of its parameters is also a pack. (#GH181166) @@ -573,15 +647,19 @@ Bug Fixes to C++ Support - Fixed a crash when diagnosing an invalid static member function with an explicit object parameter (#GH177741) - Clang incorrectly instantiated variable specializations outside of the immediate context. (#GH54439) - Fixed a crash when pack expansions are used as arguments for non-pack parameters of built-in templates. (#GH180307) +- Fix a problem where a substitution failure when evaluating a type requirement + could directly make the program ill-formed. - Fix a problem where pack index expressions where incorrectly being regarded as equivalent. - Fixed a bug where captured variables in non-mutable lambdas were incorrectly treated as mutable when used inside decltype in the return type. (#GH180460) - Fixed a crash when evaluating uninitialized GCC vector/ext_vector_type vectors in ``constexpr``. (#GH180044) - Fixed a crash when `explicit(bool)` is used with an incomplete enumeration. (#GH183887) - Fixed a crash on ``typeid`` of incomplete local types during template instantiation. (#GH63242), (#GH176397) +- Fixed spurious diagnostics produced when checking if constraints are equivalent for redeclarations, + which could make the program mistakenly ill-formed. - Fixed a crash when an immediate-invoked ``consteval`` lambda is used as an invalid initializer. (#GH185270) - Fixed an assertion failure when using a global destructor with a target with a non-default program address space. (#GH186484) - +- Fixed a crash when instantiating an invalid out-of-line static data member definition in a local class. (#GH176152) - Inherited constructors in ``dllexport`` classes are now exported for ABI-compatible cases, matching MSVC behavior. Constructors with variadic arguments or callee-cleanup parameters are not yet supported and produce a warning. (#GH162640) @@ -593,6 +671,9 @@ Bug Fixes to C++ Support - Fixed a crash in Itanium C++ name mangling for a lambda in a local class field initializer inside a constructor/destructor. (#GH176395) - Fixed crashes in Itanium C++ name mangling for lambdas with trailing requires-clauses involving requires-expressions. (#GH100774) (#GH123854) - Fixed an invalid rejection and assertion failure while generating ``operator=`` for fields with the ``__restrict`` qualifier. (#GH37979) +- Fixed a use-after-free bug when parsing default arguments containing lambdas in declarations with template-id declarators. (#GH196725) +- Fixed a crash in constant evaluation using placement new on an array which was later initialized. (#GH196450) +- Fixed an issue where Clang incorrectly accepted invalid unqualified uses of local nested class names outside their declaring scope. (#GH184622) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -601,9 +682,12 @@ Bug Fixes to AST Handling parameter list. This also adds asserts to prevent this from happening again. - Fixed a crash when parsing Doxygen ``@param`` commands attached to invalid declarations or non-function entities. (#GH182737) - Fixed the SourceLocation and SourceRange of reversed rewritten CXXOperatorCallExpr. (#GH192467) +- Fixed a assertion when ``__block`` is used on global variables in C mode. (#GH183974) Miscellaneous Bug Fixes ^^^^^^^^^^^^^^^^^^^^^^^ +- Fixed a crash whith the AST text dumper, when dumping a reference to a + decomposition with no bindinds. (#GH198842) - Fixed the arguments of the format attribute on ``__builtin_os_log_format``. Previously, they were off by 1. Miscellaneous Clang Crashes Fixed @@ -699,6 +783,10 @@ AIX Support (instead of `all`) which only extracts static init from archive members which would otherwise be referenced. (See https://www.ibm.com/docs/en/aix/7.2.0?topic=l-ld-command for details). +- The driver now uses ``-lcompiler_rt`` instead of ``-latomic``, and the compiler-rt + archive has been renamed from ``libatomic.a`` to ``libcompiler_rt.a`` to avoid conflicts + between the LLVM libatomic and the GNU libatomic from the AIX toolbox as they share + the same library name. NetBSD Support ^^^^^^^^^^^^^^ @@ -749,6 +837,10 @@ clang-format - Add ``AllowShortRecordOnASingleLine`` option and set it to ``EmptyAndAttached`` for LLVM style. - Add ``BreakFunctionDeclarationParameters`` option to always break before function declaration parameters. +- Add ``EnumAssignments`` option to ``AlignConsecutiveAssignments`` for aligning + enum assignments without affecting other assignments. +- Add ``BreakBeforeReturnType`` option to break before the function return + type. libclang -------- @@ -756,6 +848,7 @@ libclang - Visit switch initializer statements (https://bugs.kde.org/show_bug.cgi?id=415537#c2) - Fix crash in clang_getBinaryOperatorKindSpelling and clang_getUnaryOperatorKindSpelling - The clang_Module_getASTFile API is deprecated and now always returns nullptr +- The clang_Cursor_getCommentRange API will now return a comment range for macro definitions that have documentation comments. Code Completion --------------- @@ -809,6 +902,8 @@ OpenMP Support - Added support for ``transparent`` clause in task and taskloop directives. - Added support for ``use_device_ptr`` clause to accept an optional ``fallback`` modifier (``fb_nullify`` or ``fb_preserve``) with OpenMP >= 61. +- Added support for ``local`` clause with declare_target directive when + OpenMP >= 60. Improvements ^^^^^^^^^^^^ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
