Index: clang/lib/Parse/ParseExprCXX.cpp =================================================================== --- clang/lib/Parse/ParseExprCXX.cpp +++ clang/lib/Parse/ParseExprCXX.cpp @@ -1124,7 +1124,16 @@ DeclSpec DS(AttrFactory); Declarator D(DS, Declarator::LambdaExprContext); TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); - Actions.PushLambdaScope(); + Actions.PushLambdaScope(); + + ParsedAttributes Attr(AttrFactory); + SourceLocation DeclLoc = Tok.getLocation(); + SourceLocation DeclEndLoc = DeclLoc; + if (getLangOpts().CUDA) { + // In CUDA code, GNU attributes are allowed to appear immediately after the + // "[...]", even if there is no "(...)" before the lambda body. + MaybeParseGNUAttributes(Attr, &DeclEndLoc); + } TypeResult TrailingReturnType; if (Tok.is(tok::l_paren)) { @@ -1133,13 +1142,11 @@ Scope::FunctionDeclarationScope | Scope::DeclScope); - SourceLocation DeclEndLoc; BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); SourceLocation LParenLoc = T.getOpenLocation(); // Parse parameter-declaration-clause. - ParsedAttributes Attr(AttrFactory); SmallVector ParamInfo; SourceLocation EllipsisLoc; @@ -1245,12 +1252,10 @@ Diag(Tok, diag::err_lambda_missing_parens) << TokKind << FixItHint::CreateInsertion(Tok.getLocation(), "() "); - SourceLocation DeclLoc = Tok.getLocation(); - SourceLocation DeclEndLoc = DeclLoc; + DeclEndLoc = DeclLoc; // GNU-style attributes must be parsed before the mutable specifier to be // compatible with GCC. - ParsedAttributes Attr(AttrFactory); MaybeParseGNUAttributes(Attr, &DeclEndLoc); // Parse 'mutable', if it's there. @@ -1296,8 +1301,35 @@ DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); + } else if (getLangOpts().CUDA) { + // CUDA code may have attributes, which we need to add if they weren't added + // in one of the if statements above. + SourceLocation NoLoc; + D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, + /*isAmbiguous=*/false, + /*LParenLoc=*/NoLoc, + /*Params=*/nullptr, + /*NumParams=*/0, + /*EllipsisLoc=*/NoLoc, + /*RParenLoc=*/NoLoc, + /*TypeQuals=*/0, + /*RefQualifierIsLValueRef=*/true, + /*RefQualifierLoc=*/NoLoc, + /*ConstQualifierLoc=*/NoLoc, + /*VolatileQualifierLoc=*/NoLoc, + /*RestrictQualifierLoc=*/NoLoc, + /*MutableLoc=*/NoLoc, + EST_None, + /*ESpecRange=*/SourceRange(), + /*Exceptions=*/nullptr, + /*ExceptionRanges=*/nullptr, + /*NumExceptions=*/0, + /*NoexceptExpr=*/nullptr, + /*ExceptionSpecTokens=*/nullptr, + DeclLoc, DeclEndLoc, D, + TrailingReturnType), + Attr, DeclEndLoc); } - // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using // it. Index: clang/test/Parser/lambda-attr.cu =================================================================== --- /dev/null +++ clang/test/Parser/lambda-attr.cu @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcuda-is-device -verify %s + +// expected-no-diagnostics + +__attribute__((device)) void device_attr() { + ([]() __attribute__((device)){})(); + ([] __attribute__((device)) () {})(); + ([] __attribute__((device)) {})(); + + ([&]() __attribute__((device)){})(); + ([&] __attribute__((device)) () {})(); + ([&] __attribute__((device)) {})(); + + ([&](int) __attribute__((device)){})(0); + ([&] __attribute__((device)) (int) {})(0); +} + +__attribute__((host)) __attribute__((device)) void host_device_attrs() { + ([]() __attribute__((host)) __attribute__((device)){})(); + ([] __attribute__((host)) __attribute__((device)) () {})(); + ([] __attribute__((host)) __attribute__((device)) {})(); + + ([&]() __attribute__((host)) __attribute__((device)){})(); + ([&] __attribute__((host)) __attribute__((device)) () {})(); + ([&] __attribute__((host)) __attribute__((device)) {})(); + + ([&](int) __attribute__((host)) __attribute__((device)){})(0); + ([&] __attribute__((host)) __attribute__((device)) (int) {})(0); +}