Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -4524,7 +4524,9 @@ StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, Stmt *SubStmt, Scope *CurScope); - StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, + StmtResult ActOnLabelStmt(SourceLocation IdentLoc, + const ParsedAttributesView *Attrs, + SourceRange AttrsRange, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt); StmtResult ActOnAttributedStmt(SourceLocation AttrLoc, Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -666,10 +666,19 @@ LabelDecl *LD = Actions.LookupOrCreateLabel(IdentTok.getIdentifierInfo(), IdentTok.getLocation()); Actions.ProcessDeclAttributeList(Actions.CurScope, LD, attrs); + + ParsedAttributes StmtAttrs(AttrFactory); + for (size_t I = 0; I < attrs.size();) { + if (attrs[I].isStmtAttr()) + StmtAttrs.takeOneFrom(attrs, &attrs[I]); + else + ++I; + } + SourceRange AttributeRange = attrs.Range; attrs.clear(); - return Actions.ActOnLabelStmt(IdentTok.getLocation(), LD, ColonLoc, - SubStmt.get()); + return Actions.ActOnLabelStmt(IdentTok.getLocation(), &StmtAttrs, + AttributeRange, LD, ColonLoc, SubStmt.get()); } /// ParseCaseStatement Index: clang/lib/Sema/SemaDeclAttr.cpp =================================================================== --- clang/lib/Sema/SemaDeclAttr.cpp +++ clang/lib/Sema/SemaDeclAttr.cpp @@ -7363,8 +7363,11 @@ assert(AL.isTypeAttr() && "Non-type attribute not handled"); break; } - S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl) - << AL << D->getLocation(); + + // The statement attributes attached to a LabelDecl are handled separately. + if (!isa(D)) + S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl) + << AL << D->getLocation(); break; case ParsedAttr::AT_Interrupt: handleInterruptAttr(S, D, AL); Index: clang/lib/Sema/SemaStmt.cpp =================================================================== --- clang/lib/Sema/SemaStmt.cpp +++ clang/lib/Sema/SemaStmt.cpp @@ -531,9 +531,10 @@ return DS; } -StmtResult -Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, - SourceLocation ColonLoc, Stmt *SubStmt) { +StmtResult Sema::ActOnLabelStmt(SourceLocation IdentLoc, + const ParsedAttributesView *Attrs, + SourceRange AttrsRange, LabelDecl *TheDecl, + SourceLocation ColonLoc, Stmt *SubStmt) { // If the label was multiply defined, reject it now. if (TheDecl->getStmt()) { Diag(IdentLoc, diag::err_redefinition_of_label) << TheDecl->getDeclName(); @@ -552,6 +553,9 @@ TheDecl->setLocation(IdentLoc); } } + if (Attrs && !Attrs->empty()) + return ProcessStmtAttributes(LS, *Attrs, AttrsRange); + return LS; } Index: clang/lib/Sema/TreeTransform.h =================================================================== --- clang/lib/Sema/TreeTransform.h +++ clang/lib/Sema/TreeTransform.h @@ -1302,7 +1302,10 @@ /// Subclasses may override this routine to provide different behavior. StmtResult RebuildLabelStmt(SourceLocation IdentLoc, LabelDecl *L, SourceLocation ColonLoc, Stmt *SubStmt) { - return SemaRef.ActOnLabelStmt(IdentLoc, L, ColonLoc, SubStmt); + // The attributes are already processed in template declaration and are + // already properly rebuild. Only the LabelStmt itself needs to be rebuild. + return SemaRef.ActOnLabelStmt(IdentLoc, nullptr, SourceLocation(), L, + ColonLoc, SubStmt); } /// Build a new attributed statement. Index: clang/test/AST/ast-dump-attr.cpp =================================================================== --- clang/test/AST/ast-dump-attr.cpp +++ clang/test/AST/ast-dump-attr.cpp @@ -113,6 +113,35 @@ N: __attribute(()) ; // CHECK: LabelStmt {{.*}} 'N' // CHECK-NEXT: NullStmt + +[[likely]] O:; +// CHECK: AttributedStmt +// CHECK-NEXT: LikelyAttr +// CHECK-NEXT: LabelStmt {{.*}} 'O' + +[[likely]] P: __attribute__((unused)) int k; +// CHECK: AttributedStmt +// CHECK-NEXT: LikelyAttr +// CHECK-NEXT: LabelStmt {{.*}} 'P' +// CHECK: VarDecl{{.*}} k 'int' +// CHECK-NEXT: UnusedAttr{{.*}} +} + +template +T TestLabelTemplate() { +[[likely]] A: return T(); +// CHECK: FunctionTemplateDecl {{.*}} TestLabelTemplate +// CHECK: AttributedStmt +// CHECK-NEXT: LikelyAttr +// CHECK-NEXT: LabelStmt {{.*}} 'A' +} + +void TestLabelTemplateInstantiate() { +TestLabelTemplate(); +// CHECK: FunctionDecl {{.*}} TestLabelTemplate 'int ()' +// CHECK: AttributedStmt +// CHECK-NEXT: LikelyAttr +// CHECK-NEXT: LabelStmt {{.*}} 'A' } namespace Test { Index: clang/test/Sema/attr-likelihood.c =================================================================== --- clang/test/Sema/attr-likelihood.c +++ clang/test/Sema/attr-likelihood.c @@ -43,8 +43,7 @@ if (x) goto lbl; - // FIXME: allow the attribute on the label - [[clang::unlikely]] lbl : // expected-error {{'unlikely' attribute cannot be applied to a declaration}} + [[clang::unlikely]] lbl : [[clang::likely]] x = x + 1; [[clang::likely]]++ x; Index: clang/test/Sema/attr-nomerge.cpp =================================================================== --- clang/test/Sema/attr-nomerge.cpp +++ clang/test/Sema/attr-nomerge.cpp @@ -8,7 +8,7 @@ int x; [[clang::nomerge]] x = 10; // expected-warning {{nomerge attribute is ignored because there exists no call expression inside the statement}} - [[clang::nomerge]] label: bar(); // expected-error {{'nomerge' attribute cannot be applied to a declaration}} + [[clang::nomerge]] label: bar(); } Index: clang/test/SemaCXX/attr-likelihood.cpp =================================================================== --- clang/test/SemaCXX/attr-likelihood.cpp +++ clang/test/SemaCXX/attr-likelihood.cpp @@ -115,8 +115,7 @@ if (x) goto lbl; - // FIXME: allow the attribute on the label - [[unlikely]] lbl : // expected-error {{'unlikely' attribute cannot be applied to a declaration}} + [[unlikely]] lbl : [[likely]] x = x + 1; [[likely]]++ x; @@ -148,4 +147,14 @@ // expected-warning@+1 {{attribute 'likely' has no effect when annotating an 'if constexpr' statement}} } else [[likely]]; } + +void p() +{ +// Make sure the attributes aren't processed as statement attributes. +[[likely]] __label__ label; // expected-error {{expected expression}} +__label__ [[likely]] label; // expected-error {{expected expression}} +__label__ label [[likely]]; // expected-error {{expected expression}} + +[[likely]] label: __attribute__((unused)) int i; +} #endif