summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2014-03-12 00:01:07 +0000
committerAaron Ballman <aaron@aaronballman.com>2014-03-12 00:01:07 +0000
commit4bfb063cae5d2dbe59778bbcd7fea4ca143c7743 (patch)
tree30e4c247b54f169eee4dd8c8db19ee3d3011a5c4
parentbdad57cc7071298713825aab8f86d51b0e218bb4 (diff)
downloadclang-4bfb063cae5d2dbe59778bbcd7fea4ca143c7743.tar.gz
clang-4bfb063cae5d2dbe59778bbcd7fea4ca143c7743.tar.bz2
clang-4bfb063cae5d2dbe59778bbcd7fea4ca143c7743.tar.xz
Allow GNU-style attributes on lambda expressions.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@203628 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Parse/ParseExprCXX.cpp15
-rw-r--r--test/Misc/ast-dump-attr.cpp15
-rw-r--r--test/Parser/cxx0x-lambda-expressions.cpp8
3 files changed, 34 insertions, 4 deletions
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 439fb077da..f10ca6ab78 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -995,7 +995,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
ParsedAttributes Attr(AttrFactory);
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
SourceLocation EllipsisLoc;
-
if (Tok.isNot(tok::r_paren)) {
Actions.RecordParsingTemplateParameterDepth(TemplateParameterDepth);
@@ -1009,6 +1008,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
SourceLocation RParenLoc = T.getCloseLocation();
DeclEndLoc = RParenLoc;
+ // GNU-style attributes must be parsed before the mutable specifier to be
+ // compatible with GCC.
+ MaybeParseGNUAttributes(Attr, &DeclEndLoc);
+
// Parse 'mutable'[opt].
SourceLocation MutableLoc;
if (TryConsumeToken(tok::kw_mutable, MutableLoc))
@@ -1067,6 +1070,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
TrailingReturnType),
Attr, DeclEndLoc);
} else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow) ||
+ Tok.is(tok::kw___attribute) ||
(Tok.is(tok::l_square) && NextToken().is(tok::l_square))) {
// It's common to forget that one needs '()' before 'mutable', an attribute
// specifier, or the result type. Deal with this.
@@ -1074,6 +1078,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
switch (Tok.getKind()) {
case tok::kw_mutable: TokKind = 0; break;
case tok::arrow: TokKind = 1; break;
+ case tok::kw___attribute:
case tok::l_square: TokKind = 2; break;
default: llvm_unreachable("Unknown token kind");
}
@@ -1083,7 +1088,12 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
<< FixItHint::CreateInsertion(Tok.getLocation(), "() ");
SourceLocation DeclLoc = Tok.getLocation();
SourceLocation 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.
SourceLocation MutableLoc;
if (Tok.is(tok::kw_mutable)) {
@@ -1092,7 +1102,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
}
// Parse attribute-specifier[opt].
- ParsedAttributes Attr(AttrFactory);
MaybeParseCXX11Attributes(Attr, &DeclEndLoc);
// Parse the return type, if there is one.
diff --git a/test/Misc/ast-dump-attr.cpp b/test/Misc/ast-dump-attr.cpp
index bb4be5b057..dde7ba3e09 100644
--- a/test/Misc/ast-dump-attr.cpp
+++ b/test/Misc/ast-dump-attr.cpp
@@ -114,3 +114,18 @@ extern "C" int printf(const char *format, ...);
int __attribute__((cdecl)) TestOne(void), TestTwo(void);
// CHECK: FunctionDecl{{.*}}TestOne{{.*}}__attribute__((cdecl))
// CHECK: FunctionDecl{{.*}}TestTwo{{.*}}__attribute__((cdecl))
+
+void func() {
+ auto Test = []() __attribute__((no_thread_safety_analysis)) {};
+ // CHECK: CXXMethodDecl{{.*}}operator() 'void (void) const'
+ // CHECK: NoThreadSafetyAnalysisAttr
+
+ // Because GNU's noreturn applies to the function type, and this lambda does
+ // not have a capture list, the call operator and the function pointer
+ // conversion should both be noreturn, but the method should not contain a
+ // NoReturnAttr because the attribute applied to the type.
+ auto Test2 = []() __attribute__((noreturn)) { while(1); };
+ // CHECK: CXXMethodDecl{{.*}}operator() 'void (void) __attribute__((noreturn)) const'
+ // CHECK-NOT: NoReturnAttr
+ // CHECK: CXXConversionDecl{{.*}}operator void (*)() __attribute__((noreturn))
+}
diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp
index e4151dc888..9ce24cbb04 100644
--- a/test/Parser/cxx0x-lambda-expressions.cpp
+++ b/test/Parser/cxx0x-lambda-expressions.cpp
@@ -67,6 +67,7 @@ class C {
void attributes() {
[] [[]] {}; // expected-error {{lambda requires '()' before attribute specifier}}
+ [] __attribute__((noreturn)) {}; // expected-error {{lambda requires '()' before attribute specifier}}
[]() [[]]
mutable {}; // expected-error {{expected body of lambda expression}}
@@ -75,5 +76,10 @@ class C {
[]() mutable [[]] -> void {};
[]() mutable noexcept [[]] -> void {};
-}
+ // Testing GNU-style attributes on lambdas -- the attribute is specified
+ // before the mutable specifier instead of after (unlike C++11).
+ []() __attribute__((noreturn)) mutable { while(1); };
+ []() mutable
+ __attribute__((noreturn)) { while(1); }; // expected-error {{expected body of lambda expression}}
+ }
};