Disambiguate between C++11 lambda expressions and C99 array
designators in the parser. In the worst case, this disambiguation requires tentative parsing just past the closing ']', but for most cases we'll be able to tell by looking ahead just one token (without going into the heavyweight tentative parsing machinery). llvm-svn: 150790
This commit is contained in:
parent
14a941380a
commit
a80cae11f6
|
@ -1473,6 +1473,7 @@ private:
|
||||||
return ParseAssignmentExpression();
|
return ParseAssignmentExpression();
|
||||||
return ParseBraceInitializer();
|
return ParseBraceInitializer();
|
||||||
}
|
}
|
||||||
|
bool MayBeDesignationStart();
|
||||||
ExprResult ParseBraceInitializer();
|
ExprResult ParseBraceInitializer();
|
||||||
ExprResult ParseInitializerWithPotentialDesignator();
|
ExprResult ParseInitializerWithPotentialDesignator();
|
||||||
|
|
||||||
|
|
|
@ -21,15 +21,86 @@
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
|
|
||||||
/// MayBeDesignationStart - Return true if this token might be the start of a
|
/// MayBeDesignationStart - Return true if the current token might be the start
|
||||||
/// designator. If we can tell it is impossible that it is a designator, return
|
/// of a designator. If we can tell it is impossible that it is a designator,
|
||||||
/// false.
|
/// return false.
|
||||||
static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) {
|
bool Parser::MayBeDesignationStart() {
|
||||||
switch (K) {
|
switch (Tok.getKind()) {
|
||||||
default: return false;
|
default:
|
||||||
|
return false;
|
||||||
|
|
||||||
case tok::period: // designator: '.' identifier
|
case tok::period: // designator: '.' identifier
|
||||||
case tok::l_square: // designator: array-designator
|
return true;
|
||||||
|
|
||||||
|
case tok::l_square: { // designator: array-designator
|
||||||
|
if (!PP.getLangOptions().CPlusPlus0x)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// C++11 lambda expressions and C99 designators can be ambiguous all the
|
||||||
|
// way through the closing ']' and to the next character. Handle the easy
|
||||||
|
// cases here, and fall back to tentative parsing if those fail.
|
||||||
|
switch (PP.LookAhead(0).getKind()) {
|
||||||
|
case tok::equal:
|
||||||
|
case tok::r_square:
|
||||||
|
// Definitely starts a lambda expression.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case tok::amp:
|
||||||
|
case tok::kw_this:
|
||||||
|
case tok::identifier:
|
||||||
|
// We have to do additional analysis, because these could be the
|
||||||
|
// start of a constant expression or a lambda capture list.
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Anything not mentioned above cannot occur following a '[' in a
|
||||||
|
// lambda expression.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse up to (at most) the token after the closing ']' to determine
|
||||||
|
// whether this is a C99 designator or a lambda.
|
||||||
|
TentativeParsingAction Tentative(*this);
|
||||||
|
ConsumeBracket();
|
||||||
|
while (true) {
|
||||||
|
switch (Tok.getKind()) {
|
||||||
|
case tok::equal:
|
||||||
|
case tok::amp:
|
||||||
|
case tok::identifier:
|
||||||
|
case tok::kw_this:
|
||||||
|
// These tokens can occur in a capture list or a constant-expression.
|
||||||
|
// Keep looking.
|
||||||
|
ConsumeToken();
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case tok::comma:
|
||||||
|
// Since a comma cannot occur in a constant-expression, this must
|
||||||
|
// be a lambda.
|
||||||
|
Tentative.Revert();
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case tok::r_square: {
|
||||||
|
// Once we hit the closing square bracket, we look at the next
|
||||||
|
// token. If it's an '=', this is a designator. Otherwise, it's a
|
||||||
|
// lambda expression. This decision favors lambdas over the older
|
||||||
|
// GNU designator syntax, which allows one to omit the '=', but is
|
||||||
|
// consistent with GCC.
|
||||||
|
ConsumeBracket();
|
||||||
|
tok::TokenKind Kind = Tok.getKind();
|
||||||
|
Tentative.Revert();
|
||||||
|
return Kind == tok::equal;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Anything else cannot occur in a lambda capture list, so it
|
||||||
|
// must be a designator.
|
||||||
|
Tentative.Revert();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
case tok::identifier: // designation: identifier ':'
|
case tok::identifier: // designation: identifier ':'
|
||||||
return PP.LookAhead(0).is(tok::colon);
|
return PP.LookAhead(0).is(tok::colon);
|
||||||
}
|
}
|
||||||
|
@ -356,7 +427,7 @@ ExprResult Parser::ParseBraceInitializer() {
|
||||||
// If we know that this cannot be a designation, just parse the nested
|
// If we know that this cannot be a designation, just parse the nested
|
||||||
// initializer directly.
|
// initializer directly.
|
||||||
ExprResult SubElt;
|
ExprResult SubElt;
|
||||||
if (MayBeDesignationStart(Tok.getKind(), PP))
|
if (MayBeDesignationStart())
|
||||||
SubElt = ParseInitializerWithPotentialDesignator();
|
SubElt = ParseInitializerWithPotentialDesignator();
|
||||||
else
|
else
|
||||||
SubElt = ParseInitializer();
|
SubElt = ParseInitializer();
|
||||||
|
@ -439,7 +510,7 @@ bool Parser::ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs,
|
||||||
// If we know that this cannot be a designation, just parse the nested
|
// If we know that this cannot be a designation, just parse the nested
|
||||||
// initializer directly.
|
// initializer directly.
|
||||||
ExprResult SubElt;
|
ExprResult SubElt;
|
||||||
if (MayBeDesignationStart(Tok.getKind(), PP))
|
if (MayBeDesignationStart())
|
||||||
SubElt = ParseInitializerWithPotentialDesignator();
|
SubElt = ParseInitializerWithPotentialDesignator();
|
||||||
else
|
else
|
||||||
SubElt = ParseInitializer();
|
SubElt = ParseInitializer();
|
||||||
|
|
|
@ -25,5 +25,16 @@ class C {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void designator_or_lambda() {
|
||||||
|
typedef int T;
|
||||||
|
const int b = 0;
|
||||||
|
const int c = 1;
|
||||||
|
int a1[1] = {[b] (T()) {}}; // expected-error{{no viable conversion from 'C::<lambda}}
|
||||||
|
int a2[1] = {[b] = 1 };
|
||||||
|
int a3[1] = {[b,c] = 1 }; // expected-error{{expected body of lambda expression}}
|
||||||
|
int a4[1] = {[&b] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const int *'}}
|
||||||
|
int a5[3] = { []{return 0;}() };
|
||||||
|
int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue