Disambiguation of '[[':
* In C++11, '[[' is ill-formed unless it starts an attribute-specifier. Reject array sizes and array indexes which begin with a lambda-expression. Recover by parsing the lambda as a lambda. * In Objective-C++11, either '[' could be the start of a message-send. Fully disambiguate this case: it turns out that the grammars of message-sends, lambdas and attributes do not actually overlap. Accept any occurrence of '[[' where either '[' starts a message send, but reject a lambda in an array index just like in C++11 mode. Implement a couple of changes to the attribute wording which occurred after our attributes implementation landed: * In a function-declaration, the attributes go after the exception specification, not after the right paren. * A reference type can have attributes applied. * An 'identifier' in an attribute can also be a keyword. Support for alternative tokens (iso646 keywords) in attributes to follow. And some bug fixes: * Parse attributes after declarator-ids, even if they are not simple identifiers. * Do not accept attributes after a parenthesized declarator. * Accept attributes after an array size in a new-type-id. * Partially disamiguate 'delete' followed by a lambda. More work is required here for the case where the lambda-introducer is '[]'. llvm-svn: 154369
This commit is contained in:
parent
076b3041c0
commit
7bdcc4a9da
|
@ -469,6 +469,9 @@ def err_cxx0x_attribute_forbids_arguments : Error<
|
||||||
def err_cxx0x_attribute_requires_arguments : Error<
|
def err_cxx0x_attribute_requires_arguments : Error<
|
||||||
"C++11 attribute '%0' must have an argument list">;
|
"C++11 attribute '%0' must have an argument list">;
|
||||||
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
|
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
|
||||||
|
def err_l_square_l_square_not_attribute : Error<
|
||||||
|
"C++11 only allows consecutive left square brackets when "
|
||||||
|
"introducing an attribute">;
|
||||||
def err_alignas_pack_exp_unsupported : Error<
|
def err_alignas_pack_exp_unsupported : Error<
|
||||||
"pack expansions in alignment specifiers are not supported yet">;
|
"pack expansions in alignment specifiers are not supported yet">;
|
||||||
|
|
||||||
|
|
|
@ -1864,6 +1864,16 @@ private:
|
||||||
Decl **OwnedType = 0);
|
Decl **OwnedType = 0);
|
||||||
void ParseBlockId();
|
void ParseBlockId();
|
||||||
|
|
||||||
|
// Check for the start of a C++11 attribute-specifier-seq in a context where
|
||||||
|
// an attribute is not allowed.
|
||||||
|
bool CheckProhibitedCXX11Attribute() {
|
||||||
|
assert(Tok.is(tok::l_square));
|
||||||
|
if (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))
|
||||||
|
return false;
|
||||||
|
return DiagnoseProhibitedCXX11Attribute();
|
||||||
|
}
|
||||||
|
bool DiagnoseProhibitedCXX11Attribute();
|
||||||
|
|
||||||
void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
|
void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
|
||||||
if (!attrs.Range.isValid()) return;
|
if (!attrs.Range.isValid()) return;
|
||||||
DiagnoseProhibitedAttributes(attrs);
|
DiagnoseProhibitedAttributes(attrs);
|
||||||
|
@ -1894,7 +1904,7 @@ private:
|
||||||
SourceLocation *EndLoc);
|
SourceLocation *EndLoc);
|
||||||
|
|
||||||
void MaybeParseCXX0XAttributes(Declarator &D) {
|
void MaybeParseCXX0XAttributes(Declarator &D) {
|
||||||
if (getLangOpts().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
|
if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
|
||||||
ParsedAttributesWithRange attrs(AttrFactory);
|
ParsedAttributesWithRange attrs(AttrFactory);
|
||||||
SourceLocation endLoc;
|
SourceLocation endLoc;
|
||||||
ParseCXX0XAttributes(attrs, &endLoc);
|
ParseCXX0XAttributes(attrs, &endLoc);
|
||||||
|
@ -1903,15 +1913,17 @@ private:
|
||||||
}
|
}
|
||||||
void MaybeParseCXX0XAttributes(ParsedAttributes &attrs,
|
void MaybeParseCXX0XAttributes(ParsedAttributes &attrs,
|
||||||
SourceLocation *endLoc = 0) {
|
SourceLocation *endLoc = 0) {
|
||||||
if (getLangOpts().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
|
if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
|
||||||
ParsedAttributesWithRange attrsWithRange(AttrFactory);
|
ParsedAttributesWithRange attrsWithRange(AttrFactory);
|
||||||
ParseCXX0XAttributes(attrsWithRange, endLoc);
|
ParseCXX0XAttributes(attrsWithRange, endLoc);
|
||||||
attrs.takeAllFrom(attrsWithRange);
|
attrs.takeAllFrom(attrsWithRange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void MaybeParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
|
void MaybeParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
|
||||||
SourceLocation *endLoc = 0) {
|
SourceLocation *endLoc = 0,
|
||||||
if (getLangOpts().CPlusPlus0x && isCXX0XAttributeSpecifier())
|
bool OuterMightBeMessageSend = false) {
|
||||||
|
if (getLangOpts().CPlusPlus0x &&
|
||||||
|
isCXX11AttributeSpecifier(false, OuterMightBeMessageSend))
|
||||||
ParseCXX0XAttributes(attrs, endLoc);
|
ParseCXX0XAttributes(attrs, endLoc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2029,8 +2041,19 @@ private:
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// C++ 7: Declarations [dcl.dcl]
|
// C++ 7: Declarations [dcl.dcl]
|
||||||
|
|
||||||
bool isCXX0XAttributeSpecifier(bool FullLookahead = false,
|
/// The kind of attribute specifier we have found.
|
||||||
tok::TokenKind *After = 0);
|
enum CXX11AttributeKind {
|
||||||
|
/// This is not an attribute specifier.
|
||||||
|
CAK_NotAttributeSpecifier,
|
||||||
|
/// This should be treated as an attribute-specifier.
|
||||||
|
CAK_AttributeSpecifier,
|
||||||
|
/// The next tokens are '[[', but this is not an attribute-specifier. This
|
||||||
|
/// is ill-formed by C++11 [dcl.attr.grammar]p6.
|
||||||
|
CAK_InvalidAttributeSpecifier
|
||||||
|
};
|
||||||
|
CXX11AttributeKind
|
||||||
|
isCXX11AttributeSpecifier(bool Disambiguate = false,
|
||||||
|
bool OuterMightBeMessageSend = false);
|
||||||
|
|
||||||
Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd,
|
Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd,
|
||||||
SourceLocation InlineLoc = SourceLocation());
|
SourceLocation InlineLoc = SourceLocation());
|
||||||
|
|
|
@ -906,6 +906,39 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName,
|
||||||
*EndLoc = T.getCloseLocation();
|
*EndLoc = T.getCloseLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// DiagnoseProhibitedCXX11Attribute - We have found the opening square brackets
|
||||||
|
/// of a C++11 attribute-specifier in a location where an attribute is not
|
||||||
|
/// permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. Diagnose this
|
||||||
|
/// situation.
|
||||||
|
///
|
||||||
|
/// \return \c true if we skipped an attribute-like chunk of tokens, \c false if
|
||||||
|
/// this doesn't appear to actually be an attribute-specifier, and the caller
|
||||||
|
/// should try to parse it.
|
||||||
|
bool Parser::DiagnoseProhibitedCXX11Attribute() {
|
||||||
|
assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square));
|
||||||
|
|
||||||
|
switch (isCXX11AttributeSpecifier(/*Disambiguate*/true)) {
|
||||||
|
case CAK_NotAttributeSpecifier:
|
||||||
|
// No diagnostic: we're in Obj-C++11 and this is not actually an attribute.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case CAK_InvalidAttributeSpecifier:
|
||||||
|
Diag(Tok.getLocation(), diag::err_l_square_l_square_not_attribute);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case CAK_AttributeSpecifier:
|
||||||
|
// Parse and discard the attributes.
|
||||||
|
SourceLocation BeginLoc = ConsumeBracket();
|
||||||
|
ConsumeBracket();
|
||||||
|
SkipUntil(tok::r_square, /*StopAtSemi*/ false);
|
||||||
|
assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied");
|
||||||
|
SourceLocation EndLoc = ConsumeBracket();
|
||||||
|
Diag(BeginLoc, diag::err_attributes_not_allowed)
|
||||||
|
<< SourceRange(BeginLoc, EndLoc);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
|
void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
|
||||||
Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
|
Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
|
||||||
<< attrs.Range;
|
<< attrs.Range;
|
||||||
|
@ -3454,14 +3487,11 @@ bool Parser::isConstructorDeclarator() {
|
||||||
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
|
void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
|
||||||
bool VendorAttributesAllowed,
|
bool VendorAttributesAllowed,
|
||||||
bool CXX0XAttributesAllowed) {
|
bool CXX0XAttributesAllowed) {
|
||||||
if (getLangOpts().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
|
if (getLangOpts().CPlusPlus0x && CXX0XAttributesAllowed &&
|
||||||
SourceLocation Loc = Tok.getLocation();
|
isCXX11AttributeSpecifier()) {
|
||||||
ParsedAttributesWithRange attrs(AttrFactory);
|
ParsedAttributesWithRange attrs(AttrFactory);
|
||||||
ParseCXX0XAttributes(attrs);
|
ParseCXX0XAttributes(attrs);
|
||||||
if (CXX0XAttributesAllowed)
|
|
||||||
DS.takeAttributesFrom(attrs);
|
DS.takeAttributesFrom(attrs);
|
||||||
else
|
|
||||||
Diag(Loc, diag::err_attributes_not_allowed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceLocation EndLoc;
|
SourceLocation EndLoc;
|
||||||
|
@ -3654,6 +3684,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
|
||||||
// Is a pointer.
|
// Is a pointer.
|
||||||
DeclSpec DS(AttrFactory);
|
DeclSpec DS(AttrFactory);
|
||||||
|
|
||||||
|
// FIXME: GNU attributes are not allowed here in a new-type-id.
|
||||||
ParseTypeQualifierListOpt(DS);
|
ParseTypeQualifierListOpt(DS);
|
||||||
D.ExtendWithDeclSpec(DS);
|
D.ExtendWithDeclSpec(DS);
|
||||||
|
|
||||||
|
@ -3684,16 +3715,13 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
|
||||||
diag::warn_cxx98_compat_rvalue_reference :
|
diag::warn_cxx98_compat_rvalue_reference :
|
||||||
diag::ext_rvalue_reference);
|
diag::ext_rvalue_reference);
|
||||||
|
|
||||||
|
// GNU-style and C++11 attributes are allowed here, as is restrict.
|
||||||
|
ParseTypeQualifierListOpt(DS);
|
||||||
|
D.ExtendWithDeclSpec(DS);
|
||||||
|
|
||||||
// C++ 8.3.2p1: cv-qualified references are ill-formed except when the
|
// C++ 8.3.2p1: cv-qualified references are ill-formed except when the
|
||||||
// cv-qualifiers are introduced through the use of a typedef or of a
|
// cv-qualifiers are introduced through the use of a typedef or of a
|
||||||
// template type argument, in which case the cv-qualifiers are ignored.
|
// template type argument, in which case the cv-qualifiers are ignored.
|
||||||
//
|
|
||||||
// [GNU] Retricted references are allowed.
|
|
||||||
// [GNU] Attributes on references are allowed.
|
|
||||||
// [C++0x] Attributes on references are not allowed.
|
|
||||||
ParseTypeQualifierListOpt(DS, true, false);
|
|
||||||
D.ExtendWithDeclSpec(DS);
|
|
||||||
|
|
||||||
if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
|
if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
|
||||||
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
|
if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
|
||||||
Diag(DS.getConstSpecLoc(),
|
Diag(DS.getConstSpecLoc(),
|
||||||
|
@ -3754,13 +3782,19 @@ static void diagnoseMisplacedEllipsis(Parser &P, Declarator &D,
|
||||||
/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
|
/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
|
||||||
/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
|
/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
|
||||||
/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
|
/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
|
||||||
|
/// [C++11] direct-declarator '[' constant-expression[opt] ']'
|
||||||
|
/// attribute-specifier-seq[opt]
|
||||||
/// direct-declarator '(' parameter-type-list ')'
|
/// direct-declarator '(' parameter-type-list ')'
|
||||||
/// direct-declarator '(' identifier-list[opt] ')'
|
/// direct-declarator '(' identifier-list[opt] ')'
|
||||||
/// [GNU] direct-declarator '(' parameter-forward-declarations
|
/// [GNU] direct-declarator '(' parameter-forward-declarations
|
||||||
/// parameter-type-list[opt] ')'
|
/// parameter-type-list[opt] ')'
|
||||||
/// [C++] direct-declarator '(' parameter-declaration-clause ')'
|
/// [C++] direct-declarator '(' parameter-declaration-clause ')'
|
||||||
/// cv-qualifier-seq[opt] exception-specification[opt]
|
/// cv-qualifier-seq[opt] exception-specification[opt]
|
||||||
|
/// [C++11] direct-declarator '(' parameter-declaration-clause ')'
|
||||||
|
/// attribute-specifier-seq[opt] cv-qualifier-seq[opt]
|
||||||
|
/// ref-qualifier[opt] exception-specification[opt]
|
||||||
/// [C++] declarator-id
|
/// [C++] declarator-id
|
||||||
|
/// [C++11] declarator-id attribute-specifier-seq[opt]
|
||||||
///
|
///
|
||||||
/// declarator-id: [C++ 8]
|
/// declarator-id: [C++ 8]
|
||||||
/// '...'[opt] id-expression
|
/// '...'[opt] id-expression
|
||||||
|
@ -3908,8 +3942,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
||||||
assert(D.isPastIdentifier() &&
|
assert(D.isPastIdentifier() &&
|
||||||
"Haven't past the location of the identifier yet?");
|
"Haven't past the location of the identifier yet?");
|
||||||
|
|
||||||
// Don't parse attributes unless we have an identifier.
|
// Don't parse attributes unless we have parsed an unparenthesized name.
|
||||||
if (D.getIdentifier())
|
if (D.hasName() && !D.getNumTypeObjects())
|
||||||
MaybeParseCXX0XAttributes(D);
|
MaybeParseCXX0XAttributes(D);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -4055,22 +4089,23 @@ void Parser::ParseParenDeclarator(Declarator &D) {
|
||||||
/// declarator D up to a paren, which indicates that we are parsing function
|
/// declarator D up to a paren, which indicates that we are parsing function
|
||||||
/// arguments.
|
/// arguments.
|
||||||
///
|
///
|
||||||
/// If attrs is non-null, then the caller parsed those arguments immediately
|
/// If FirstArgAttrs is non-null, then the caller parsed those arguments
|
||||||
/// after the open paren - they should be considered to be the first argument of
|
/// immediately after the open paren - they should be considered to be the
|
||||||
/// a parameter. If RequiresArg is true, then the first argument of the
|
/// first argument of a parameter.
|
||||||
/// function is required to be present and required to not be an identifier
|
|
||||||
/// list.
|
|
||||||
///
|
///
|
||||||
/// For C++, after the parameter-list, it also parses cv-qualifier-seq[opt],
|
/// If RequiresArg is true, then the first argument of the function is required
|
||||||
/// (C++0x) ref-qualifier[opt], exception-specification[opt], and
|
/// to be present and required to not be an identifier list.
|
||||||
/// (C++0x) trailing-return-type[opt].
|
|
||||||
///
|
///
|
||||||
/// [C++0x] exception-specification:
|
/// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt],
|
||||||
|
/// (C++11) ref-qualifier[opt], exception-specification[opt],
|
||||||
|
/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt].
|
||||||
|
///
|
||||||
|
/// [C++11] exception-specification:
|
||||||
/// dynamic-exception-specification
|
/// dynamic-exception-specification
|
||||||
/// noexcept-specification
|
/// noexcept-specification
|
||||||
///
|
///
|
||||||
void Parser::ParseFunctionDeclarator(Declarator &D,
|
void Parser::ParseFunctionDeclarator(Declarator &D,
|
||||||
ParsedAttributes &attrs,
|
ParsedAttributes &FirstArgAttrs,
|
||||||
BalancedDelimiterTracker &Tracker,
|
BalancedDelimiterTracker &Tracker,
|
||||||
bool RequiresArg) {
|
bool RequiresArg) {
|
||||||
assert(getCurScope()->isFunctionPrototypeScope() &&
|
assert(getCurScope()->isFunctionPrototypeScope() &&
|
||||||
|
@ -4096,6 +4131,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
||||||
SmallVector<ParsedType, 2> DynamicExceptions;
|
SmallVector<ParsedType, 2> DynamicExceptions;
|
||||||
SmallVector<SourceRange, 2> DynamicExceptionRanges;
|
SmallVector<SourceRange, 2> DynamicExceptionRanges;
|
||||||
ExprResult NoexceptExpr;
|
ExprResult NoexceptExpr;
|
||||||
|
ParsedAttributes FnAttrs(AttrFactory);
|
||||||
ParsedType TrailingReturnType;
|
ParsedType TrailingReturnType;
|
||||||
|
|
||||||
Actions.ActOnStartFunctionDeclarator();
|
Actions.ActOnStartFunctionDeclarator();
|
||||||
|
@ -4111,7 +4147,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
||||||
EndLoc = Tracker.getCloseLocation();
|
EndLoc = Tracker.getCloseLocation();
|
||||||
} else {
|
} else {
|
||||||
if (Tok.isNot(tok::r_paren))
|
if (Tok.isNot(tok::r_paren))
|
||||||
ParseParameterDeclarationClause(D, attrs, ParamInfo, EllipsisLoc);
|
ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
|
||||||
else if (RequiresArg)
|
else if (RequiresArg)
|
||||||
Diag(Tok, diag::err_argument_required_after_attribute);
|
Diag(Tok, diag::err_argument_required_after_attribute);
|
||||||
|
|
||||||
|
@ -4122,10 +4158,12 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
||||||
EndLoc = Tracker.getCloseLocation();
|
EndLoc = Tracker.getCloseLocation();
|
||||||
|
|
||||||
if (getLangOpts().CPlusPlus) {
|
if (getLangOpts().CPlusPlus) {
|
||||||
MaybeParseCXX0XAttributes(attrs);
|
// FIXME: Accept these components in any order, and produce fixits to
|
||||||
|
// correct the order if the user gets it wrong. Ideally we should deal
|
||||||
|
// with the virt-specifier-seq and pure-specifier in the same way.
|
||||||
|
|
||||||
// Parse cv-qualifier-seq[opt].
|
// Parse cv-qualifier-seq[opt].
|
||||||
ParseTypeQualifierListOpt(DS, false /*no attributes*/);
|
ParseTypeQualifierListOpt(DS, false /*no attributes*/, false);
|
||||||
if (!DS.getSourceRange().getEnd().isInvalid()) {
|
if (!DS.getSourceRange().getEnd().isInvalid()) {
|
||||||
EndLoc = DS.getSourceRange().getEnd();
|
EndLoc = DS.getSourceRange().getEnd();
|
||||||
ConstQualifierLoc = DS.getConstSpecLoc();
|
ConstQualifierLoc = DS.getConstSpecLoc();
|
||||||
|
@ -4151,6 +4189,10 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
||||||
if (ESpecType != EST_None)
|
if (ESpecType != EST_None)
|
||||||
EndLoc = ESpecRange.getEnd();
|
EndLoc = ESpecRange.getEnd();
|
||||||
|
|
||||||
|
// Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes
|
||||||
|
// after the exception-specification.
|
||||||
|
MaybeParseCXX0XAttributes(FnAttrs);
|
||||||
|
|
||||||
// Parse trailing-return-type[opt].
|
// Parse trailing-return-type[opt].
|
||||||
if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) {
|
if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) {
|
||||||
Diag(Tok, diag::warn_cxx98_compat_trailing_return_type);
|
Diag(Tok, diag::warn_cxx98_compat_trailing_return_type);
|
||||||
|
@ -4181,7 +4223,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
|
||||||
Tracker.getOpenLocation(),
|
Tracker.getOpenLocation(),
|
||||||
EndLoc, D,
|
EndLoc, D,
|
||||||
TrailingReturnType),
|
TrailingReturnType),
|
||||||
attrs, EndLoc);
|
FnAttrs, EndLoc);
|
||||||
|
|
||||||
Actions.ActOnEndFunctionDeclarator();
|
Actions.ActOnEndFunctionDeclarator();
|
||||||
}
|
}
|
||||||
|
@ -4455,7 +4497,12 @@ void Parser::ParseParameterDeclarationClause(
|
||||||
/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
|
/// [C99] direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
|
||||||
/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
|
/// [C99] direct-declarator '[' type-qual-list 'static' assignment-expr ']'
|
||||||
/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
|
/// [C99] direct-declarator '[' type-qual-list[opt] '*' ']'
|
||||||
|
/// [C++11] direct-declarator '[' constant-expression[opt] ']'
|
||||||
|
/// attribute-specifier-seq[opt]
|
||||||
void Parser::ParseBracketDeclarator(Declarator &D) {
|
void Parser::ParseBracketDeclarator(Declarator &D) {
|
||||||
|
if (CheckProhibitedCXX11Attribute())
|
||||||
|
return;
|
||||||
|
|
||||||
BalancedDelimiterTracker T(*this, tok::l_square);
|
BalancedDelimiterTracker T(*this, tok::l_square);
|
||||||
T.consumeOpen();
|
T.consumeOpen();
|
||||||
|
|
||||||
|
|
|
@ -2736,38 +2736,38 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) {
|
||||||
Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope();
|
Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ParseCXX0XAttributeSpecifier - Parse a C++0x attribute-specifier. Currently
|
/// ParseCXX0XAttributeSpecifier - Parse a C++11 attribute-specifier. Currently
|
||||||
/// only parses standard attributes.
|
/// only parses standard attributes.
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute-specifier:
|
/// [C++11] attribute-specifier:
|
||||||
/// '[' '[' attribute-list ']' ']'
|
/// '[' '[' attribute-list ']' ']'
|
||||||
/// alignment-specifier
|
/// alignment-specifier
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute-list:
|
/// [C++11] attribute-list:
|
||||||
/// attribute[opt]
|
/// attribute[opt]
|
||||||
/// attribute-list ',' attribute[opt]
|
/// attribute-list ',' attribute[opt]
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute:
|
/// [C++11] attribute:
|
||||||
/// attribute-token attribute-argument-clause[opt]
|
/// attribute-token attribute-argument-clause[opt]
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute-token:
|
/// [C++11] attribute-token:
|
||||||
/// identifier
|
/// identifier
|
||||||
/// attribute-scoped-token
|
/// attribute-scoped-token
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute-scoped-token:
|
/// [C++11] attribute-scoped-token:
|
||||||
/// attribute-namespace '::' identifier
|
/// attribute-namespace '::' identifier
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute-namespace:
|
/// [C++11] attribute-namespace:
|
||||||
/// identifier
|
/// identifier
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute-argument-clause:
|
/// [C++11] attribute-argument-clause:
|
||||||
/// '(' balanced-token-seq ')'
|
/// '(' balanced-token-seq ')'
|
||||||
///
|
///
|
||||||
/// [C++0x] balanced-token-seq:
|
/// [C++11] balanced-token-seq:
|
||||||
/// balanced-token
|
/// balanced-token
|
||||||
/// balanced-token-seq balanced-token
|
/// balanced-token-seq balanced-token
|
||||||
///
|
///
|
||||||
/// [C++0x] balanced-token:
|
/// [C++11] balanced-token:
|
||||||
/// '(' balanced-token-seq ')'
|
/// '(' balanced-token-seq ')'
|
||||||
/// '[' balanced-token-seq ']'
|
/// '[' balanced-token-seq ']'
|
||||||
/// '{' balanced-token-seq '}'
|
/// '{' balanced-token-seq '}'
|
||||||
|
@ -2781,7 +2781,7 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
|
assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
|
||||||
&& "Not a C++0x attribute list");
|
&& "Not a C++11 attribute list");
|
||||||
|
|
||||||
Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute);
|
Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute);
|
||||||
|
|
||||||
|
@ -2793,7 +2793,11 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (Tok.is(tok::identifier) || Tok.is(tok::comma)) {
|
// C++11 [dcl.attr.grammar]p3: If a keyword or an alternative token that
|
||||||
|
// satisfies the syntactic requirements of an identifier is contained in an
|
||||||
|
// attribute-token, it is considered an identifier.
|
||||||
|
// FIXME: Support alternative tokens here.
|
||||||
|
while (Tok.getIdentifierInfo() || Tok.is(tok::comma)) {
|
||||||
// attribute not present
|
// attribute not present
|
||||||
if (Tok.is(tok::comma)) {
|
if (Tok.is(tok::comma)) {
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
|
@ -2807,7 +2811,7 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
|
||||||
if (Tok.is(tok::coloncolon)) {
|
if (Tok.is(tok::coloncolon)) {
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
|
|
||||||
if (!Tok.is(tok::identifier)) {
|
if (!Tok.getIdentifierInfo()) {
|
||||||
Diag(Tok.getLocation(), diag::err_expected_ident);
|
Diag(Tok.getLocation(), diag::err_expected_ident);
|
||||||
SkipUntil(tok::r_square, tok::comma, true, true);
|
SkipUntil(tok::r_square, tok::comma, true, true);
|
||||||
continue;
|
continue;
|
||||||
|
@ -2824,8 +2828,7 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
|
||||||
// No scoped names are supported; ideally we could put all non-standard
|
// No scoped names are supported; ideally we could put all non-standard
|
||||||
// attributes into namespaces.
|
// attributes into namespaces.
|
||||||
if (!ScopeName) {
|
if (!ScopeName) {
|
||||||
switch(AttributeList::getKind(AttrName))
|
switch (AttributeList::getKind(AttrName)) {
|
||||||
{
|
|
||||||
// No arguments
|
// No arguments
|
||||||
case AttributeList::AT_carries_dependency:
|
case AttributeList::AT_carries_dependency:
|
||||||
case AttributeList::AT_noreturn: {
|
case AttributeList::AT_noreturn: {
|
||||||
|
@ -2852,6 +2855,9 @@ void Parser::ParseCXX0XAttributeSpecifier(ParsedAttributes &attrs,
|
||||||
// SkipUntil maintains the balancedness of tokens.
|
// SkipUntil maintains the balancedness of tokens.
|
||||||
SkipUntil(tok::r_paren, false);
|
SkipUntil(tok::r_paren, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Tok.is(tok::ellipsis))
|
||||||
|
ConsumeToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
|
if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
|
||||||
|
@ -2874,7 +2880,7 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ParseCXX0XAttributeSpecifier(attrs, endLoc);
|
ParseCXX0XAttributeSpecifier(attrs, endLoc);
|
||||||
} while (isCXX0XAttributeSpecifier());
|
} while (isCXX11AttributeSpecifier());
|
||||||
|
|
||||||
attrs.Range = SourceRange(StartLoc, *endLoc);
|
attrs.Range = SourceRange(StartLoc, *endLoc);
|
||||||
}
|
}
|
||||||
|
@ -2892,6 +2898,7 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs,
|
||||||
assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list");
|
assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list");
|
||||||
|
|
||||||
while (Tok.is(tok::l_square)) {
|
while (Tok.is(tok::l_square)) {
|
||||||
|
// FIXME: If this is actually a C++11 attribute, parse it as one.
|
||||||
ConsumeBracket();
|
ConsumeBracket();
|
||||||
SkipUntil(tok::r_square, true, true);
|
SkipUntil(tok::r_square, true, true);
|
||||||
if (endLoc) *endLoc = Tok.getLocation();
|
if (endLoc) *endLoc = Tok.getLocation();
|
||||||
|
|
|
@ -1288,6 +1288,11 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||||
isSimpleObjCMessageExpression())
|
isSimpleObjCMessageExpression())
|
||||||
return move(LHS);
|
return move(LHS);
|
||||||
|
|
||||||
|
// Reject array indices starting with a lambda-expression. '[[' is
|
||||||
|
// reserved for attributes.
|
||||||
|
if (CheckProhibitedCXX11Attribute())
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
BalancedDelimiterTracker T(*this, tok::l_square);
|
BalancedDelimiterTracker T(*this, tok::l_square);
|
||||||
T.consumeOpen();
|
T.consumeOpen();
|
||||||
Loc = T.getOpenLocation();
|
Loc = T.getOpenLocation();
|
||||||
|
@ -1756,6 +1761,9 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() {
|
||||||
Comps.back().LocEnd = ConsumeToken();
|
Comps.back().LocEnd = ConsumeToken();
|
||||||
|
|
||||||
} else if (Tok.is(tok::l_square)) {
|
} else if (Tok.is(tok::l_square)) {
|
||||||
|
if (CheckProhibitedCXX11Attribute())
|
||||||
|
return ExprError();
|
||||||
|
|
||||||
// offsetof-member-designator: offsetof-member-design '[' expression ']'
|
// offsetof-member-designator: offsetof-member-design '[' expression ']'
|
||||||
Comps.push_back(Sema::OffsetOfComponent());
|
Comps.push_back(Sema::OffsetOfComponent());
|
||||||
Comps.back().isBrackets = true;
|
Comps.back().isBrackets = true;
|
||||||
|
|
|
@ -1817,7 +1817,9 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
|
||||||
bool isNew = Tok.getKind() == tok::kw_new;
|
bool isNew = Tok.getKind() == tok::kw_new;
|
||||||
// Consume the 'new' or 'delete'.
|
// Consume the 'new' or 'delete'.
|
||||||
SymbolLocations[SymbolIdx++] = ConsumeToken();
|
SymbolLocations[SymbolIdx++] = ConsumeToken();
|
||||||
if (Tok.is(tok::l_square)) {
|
// Check for array new/delete.
|
||||||
|
if (Tok.is(tok::l_square) &&
|
||||||
|
(!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))) {
|
||||||
// Consume the '[' and ']'.
|
// Consume the '[' and ']'.
|
||||||
BalancedDelimiterTracker T(*this, tok::l_square);
|
BalancedDelimiterTracker T(*this, tok::l_square);
|
||||||
T.consumeOpen();
|
T.consumeOpen();
|
||||||
|
@ -2346,6 +2348,10 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
|
||||||
// Parse the array dimensions.
|
// Parse the array dimensions.
|
||||||
bool first = true;
|
bool first = true;
|
||||||
while (Tok.is(tok::l_square)) {
|
while (Tok.is(tok::l_square)) {
|
||||||
|
// An array-size expression can't start with a lambda.
|
||||||
|
if (CheckProhibitedCXX11Attribute())
|
||||||
|
continue;
|
||||||
|
|
||||||
BalancedDelimiterTracker T(*this, tok::l_square);
|
BalancedDelimiterTracker T(*this, tok::l_square);
|
||||||
T.consumeOpen();
|
T.consumeOpen();
|
||||||
|
|
||||||
|
@ -2360,13 +2366,16 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) {
|
||||||
|
|
||||||
T.consumeClose();
|
T.consumeClose();
|
||||||
|
|
||||||
ParsedAttributes attrs(AttrFactory);
|
// Attributes here appertain to the array type. C++11 [expr.new]p5.
|
||||||
|
ParsedAttributes Attrs(AttrFactory);
|
||||||
|
MaybeParseCXX0XAttributes(Attrs);
|
||||||
|
|
||||||
D.AddTypeInfo(DeclaratorChunk::getArray(0,
|
D.AddTypeInfo(DeclaratorChunk::getArray(0,
|
||||||
/*static=*/false, /*star=*/false,
|
/*static=*/false, /*star=*/false,
|
||||||
Size.release(),
|
Size.release(),
|
||||||
T.getOpenLocation(),
|
T.getOpenLocation(),
|
||||||
T.getCloseLocation()),
|
T.getCloseLocation()),
|
||||||
attrs, T.getCloseLocation());
|
Attrs, T.getCloseLocation());
|
||||||
|
|
||||||
if (T.getCloseLocation().isInvalid())
|
if (T.getCloseLocation().isInvalid())
|
||||||
return;
|
return;
|
||||||
|
@ -2418,7 +2427,11 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
|
||||||
|
|
||||||
// Array delete?
|
// Array delete?
|
||||||
bool ArrayDelete = false;
|
bool ArrayDelete = false;
|
||||||
if (Tok.is(tok::l_square)) {
|
if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) {
|
||||||
|
// FIXME: This could be the start of a lambda-expression. We should
|
||||||
|
// disambiguate this, but that will require arbitrary lookahead if
|
||||||
|
// the next token is '(':
|
||||||
|
// delete [](int*){ /* ... */
|
||||||
ArrayDelete = true;
|
ArrayDelete = true;
|
||||||
BalancedDelimiterTracker T(*this, tok::l_square);
|
BalancedDelimiterTracker T(*this, tok::l_square);
|
||||||
|
|
||||||
|
|
|
@ -211,6 +211,11 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() {
|
||||||
// [foo ... bar] -> array designator
|
// [foo ... bar] -> array designator
|
||||||
// [4][foo bar] -> obsolete GNU designation with objc message send.
|
// [4][foo bar] -> obsolete GNU designation with objc message send.
|
||||||
//
|
//
|
||||||
|
// We do not need to check for an expression starting with [[ here. If it
|
||||||
|
// contains an Objective-C message send, then it is not an ill-formed
|
||||||
|
// attribute. If it is a lambda-expression within an array-designator, then
|
||||||
|
// it will be rejected because a constant-expression cannot begin with a
|
||||||
|
// lambda-expression.
|
||||||
InMessageExpressionRAIIObject InMessage(*this, true);
|
InMessageExpressionRAIIObject InMessage(*this, true);
|
||||||
|
|
||||||
BalancedDelimiterTracker T(*this, tok::l_square);
|
BalancedDelimiterTracker T(*this, tok::l_square);
|
||||||
|
|
|
@ -84,7 +84,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement,
|
||||||
ParenBraceBracketBalancer BalancerRAIIObj(*this);
|
ParenBraceBracketBalancer BalancerRAIIObj(*this);
|
||||||
|
|
||||||
ParsedAttributesWithRange attrs(AttrFactory);
|
ParsedAttributesWithRange attrs(AttrFactory);
|
||||||
MaybeParseCXX0XAttributes(attrs);
|
MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
|
||||||
|
|
||||||
// Cases in this switch statement should fall through if the parser expects
|
// Cases in this switch statement should fall through if the parser expects
|
||||||
// the token to end in a semicolon (in which case SemiError should be set),
|
// the token to end in a semicolon (in which case SemiError should be set),
|
||||||
|
@ -789,7 +789,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
|
||||||
ConsumeToken();
|
ConsumeToken();
|
||||||
|
|
||||||
ParsedAttributesWithRange attrs(AttrFactory);
|
ParsedAttributesWithRange attrs(AttrFactory);
|
||||||
MaybeParseCXX0XAttributes(attrs);
|
MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
|
||||||
|
|
||||||
// If this is the start of a declaration, parse it as such.
|
// If this is the start of a declaration, parse it as such.
|
||||||
if (isDeclarationStatement()) {
|
if (isDeclarationStatement()) {
|
||||||
|
|
|
@ -374,91 +374,167 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
|
||||||
return TPR == TPResult::True();
|
return TPR == TPResult::True();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// isCXX0XAttributeSpecifier - returns true if this is a C++0x
|
/// \brief Returns true if this is a C++11 attribute-specifier. Per
|
||||||
/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is
|
/// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens
|
||||||
/// performed that will simply return true if a [[ is seen. Currently C++ has no
|
/// always introduce an attribute. In Objective-C++11, this rule does not
|
||||||
/// syntactical ambiguities from this check, but it may inhibit error recovery.
|
/// apply if either '[' begins a message-send.
|
||||||
/// If CheckClosing is true, a check is made for closing ]] brackets.
|
|
||||||
///
|
///
|
||||||
/// If given, After is set to the token after the attribute-specifier so that
|
/// If Disambiguate is true, we try harder to determine whether a '[[' starts
|
||||||
/// appropriate parsing decisions can be made; it is left untouched if false is
|
/// an attribute-specifier, and return CAK_InvalidAttributeSpecifier if not.
|
||||||
/// returned.
|
|
||||||
///
|
///
|
||||||
/// FIXME: If an error is in the closing ]] brackets, the program assumes
|
/// If OuterMightBeMessageSend is true, we assume the outer '[' is either an
|
||||||
/// the absence of an attribute-specifier, which can cause very yucky errors
|
/// Obj-C message send or the start of an attribute. Otherwise, we assume it
|
||||||
/// to occur.
|
/// is not an Obj-C message send.
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute-specifier:
|
/// C++11 [dcl.attr.grammar]:
|
||||||
|
///
|
||||||
|
/// attribute-specifier:
|
||||||
/// '[' '[' attribute-list ']' ']'
|
/// '[' '[' attribute-list ']' ']'
|
||||||
/// alignment-specifier
|
/// alignment-specifier
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute-list:
|
/// attribute-list:
|
||||||
/// attribute[opt]
|
/// attribute[opt]
|
||||||
/// attribute-list ',' attribute[opt]
|
/// attribute-list ',' attribute[opt]
|
||||||
|
/// attribute '...'
|
||||||
|
/// attribute-list ',' attribute '...'
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute:
|
/// attribute:
|
||||||
/// attribute-token attribute-argument-clause[opt]
|
/// attribute-token attribute-argument-clause[opt]
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute-token:
|
/// attribute-token:
|
||||||
/// identifier
|
/// identifier
|
||||||
/// attribute-scoped-token
|
/// identifier '::' identifier
|
||||||
///
|
///
|
||||||
/// [C++0x] attribute-scoped-token:
|
/// attribute-argument-clause:
|
||||||
/// attribute-namespace '::' identifier
|
|
||||||
///
|
|
||||||
/// [C++0x] attribute-namespace:
|
|
||||||
/// identifier
|
|
||||||
///
|
|
||||||
/// [C++0x] attribute-argument-clause:
|
|
||||||
/// '(' balanced-token-seq ')'
|
/// '(' balanced-token-seq ')'
|
||||||
///
|
Parser::CXX11AttributeKind
|
||||||
/// [C++0x] balanced-token-seq:
|
Parser::isCXX11AttributeSpecifier(bool Disambiguate,
|
||||||
/// balanced-token
|
bool OuterMightBeMessageSend) {
|
||||||
/// balanced-token-seq balanced-token
|
|
||||||
///
|
|
||||||
/// [C++0x] balanced-token:
|
|
||||||
/// '(' balanced-token-seq ')'
|
|
||||||
/// '[' balanced-token-seq ']'
|
|
||||||
/// '{' balanced-token-seq '}'
|
|
||||||
/// any token but '(', ')', '[', ']', '{', or '}'
|
|
||||||
bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing,
|
|
||||||
tok::TokenKind *After) {
|
|
||||||
if (Tok.is(tok::kw_alignas))
|
if (Tok.is(tok::kw_alignas))
|
||||||
return true;
|
return CAK_AttributeSpecifier;
|
||||||
|
|
||||||
if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
|
if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
|
||||||
return false;
|
return CAK_NotAttributeSpecifier;
|
||||||
|
|
||||||
// No tentative parsing if we don't need to look for ]]
|
// No tentative parsing if we don't need to look for ']]' or a lambda.
|
||||||
if (!CheckClosing && !getLangOpts().ObjC1)
|
if (!Disambiguate && !getLangOpts().ObjC1)
|
||||||
return true;
|
return CAK_AttributeSpecifier;
|
||||||
|
|
||||||
struct TentativeReverter {
|
TentativeParsingAction PA(*this);
|
||||||
TentativeParsingAction PA;
|
|
||||||
|
|
||||||
TentativeReverter (Parser& P)
|
|
||||||
: PA(P)
|
|
||||||
{}
|
|
||||||
~TentativeReverter () {
|
|
||||||
PA.Revert();
|
|
||||||
}
|
|
||||||
} R(*this);
|
|
||||||
|
|
||||||
// Opening brackets were checked for above.
|
// Opening brackets were checked for above.
|
||||||
ConsumeBracket();
|
ConsumeBracket();
|
||||||
|
|
||||||
|
// Outside Obj-C++11, treat anything with a matching ']]' as an attribute.
|
||||||
|
if (!getLangOpts().ObjC1) {
|
||||||
ConsumeBracket();
|
ConsumeBracket();
|
||||||
|
|
||||||
// SkipUntil will handle balanced tokens, which are guaranteed in attributes.
|
bool IsAttribute = SkipUntil(tok::r_square, false);
|
||||||
SkipUntil(tok::r_square, false);
|
IsAttribute &= Tok.is(tok::r_square);
|
||||||
|
|
||||||
|
PA.Revert();
|
||||||
|
|
||||||
|
return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In Obj-C++11, we need to distinguish four situations:
|
||||||
|
// 1a) int x[[attr]]; C++11 attribute.
|
||||||
|
// 1b) [[attr]]; C++11 statement attribute.
|
||||||
|
// 2) int x[[obj](){ return 1; }()]; Lambda in array size/index.
|
||||||
|
// 3a) int x[[obj get]]; Message send in array size/index.
|
||||||
|
// 3b) [[Class alloc] init]; Message send in message send.
|
||||||
|
// 4) [[obj]{ return self; }() doStuff]; Lambda in message send.
|
||||||
|
// (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted.
|
||||||
|
|
||||||
|
// If we have a lambda-introducer, then this is definitely not a message send.
|
||||||
|
// FIXME: If this disambiguation is too slow, fold the tentative lambda parse
|
||||||
|
// into the tentative attribute parse below.
|
||||||
|
LambdaIntroducer Intro;
|
||||||
|
if (!TryParseLambdaIntroducer(Intro)) {
|
||||||
|
// A lambda cannot end with ']]', and an attribute must.
|
||||||
|
bool IsAttribute = Tok.is(tok::r_square);
|
||||||
|
|
||||||
|
PA.Revert();
|
||||||
|
|
||||||
|
if (IsAttribute)
|
||||||
|
// Case 1: C++11 attribute.
|
||||||
|
return CAK_AttributeSpecifier;
|
||||||
|
|
||||||
|
if (OuterMightBeMessageSend)
|
||||||
|
// Case 4: Lambda in message send.
|
||||||
|
return CAK_NotAttributeSpecifier;
|
||||||
|
|
||||||
|
// Case 2: Lambda in array size / index.
|
||||||
|
return CAK_InvalidAttributeSpecifier;
|
||||||
|
}
|
||||||
|
|
||||||
if (Tok.isNot(tok::r_square))
|
|
||||||
return false;
|
|
||||||
ConsumeBracket();
|
ConsumeBracket();
|
||||||
|
|
||||||
if (After)
|
// If we don't have a lambda-introducer, then we have an attribute or a
|
||||||
*After = Tok.getKind();
|
// message-send.
|
||||||
|
bool IsAttribute = true;
|
||||||
|
while (Tok.isNot(tok::r_square)) {
|
||||||
|
if (Tok.is(tok::comma)) {
|
||||||
|
// Case 1: Stray commas can only occur in attributes.
|
||||||
|
PA.Revert();
|
||||||
|
return CAK_AttributeSpecifier;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
// Parse the attribute-token, if present.
|
||||||
|
// C++11 [dcl.attr.grammar]:
|
||||||
|
// If a keyword or an alternative token that satisfies the syntactic
|
||||||
|
// requirements of an identifier is contained in an attribute-token,
|
||||||
|
// it is considered an identifier.
|
||||||
|
if (!Tok.getIdentifierInfo()) {
|
||||||
|
IsAttribute = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ConsumeToken();
|
||||||
|
if (Tok.is(tok::coloncolon)) {
|
||||||
|
ConsumeToken();
|
||||||
|
if (!Tok.getIdentifierInfo()) {
|
||||||
|
IsAttribute = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ConsumeToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the attribute-argument-clause, if present.
|
||||||
|
if (Tok.is(tok::l_paren)) {
|
||||||
|
ConsumeParen();
|
||||||
|
if (!SkipUntil(tok::r_paren, false)) {
|
||||||
|
IsAttribute = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tok.is(tok::ellipsis))
|
||||||
|
ConsumeToken();
|
||||||
|
|
||||||
|
if (Tok.isNot(tok::comma))
|
||||||
|
break;
|
||||||
|
|
||||||
|
ConsumeToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
// An attribute must end ']]'.
|
||||||
|
if (IsAttribute) {
|
||||||
|
if (Tok.is(tok::r_square)) {
|
||||||
|
ConsumeBracket();
|
||||||
|
IsAttribute = Tok.is(tok::r_square);
|
||||||
|
} else {
|
||||||
|
IsAttribute = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PA.Revert();
|
||||||
|
|
||||||
|
if (IsAttribute)
|
||||||
|
// Case 1: C++11 statement attribute.
|
||||||
|
return CAK_AttributeSpecifier;
|
||||||
|
|
||||||
|
// Case 3: Message send.
|
||||||
|
return CAK_NotAttributeSpecifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// declarator:
|
/// declarator:
|
||||||
|
@ -1217,11 +1293,13 @@ bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) {
|
||||||
/// parameter-declaration-list ',' parameter-declaration
|
/// parameter-declaration-list ',' parameter-declaration
|
||||||
///
|
///
|
||||||
/// parameter-declaration:
|
/// parameter-declaration:
|
||||||
/// decl-specifier-seq declarator attributes[opt]
|
/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt]
|
||||||
/// decl-specifier-seq declarator attributes[opt] '=' assignment-expression
|
/// attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt]
|
||||||
/// decl-specifier-seq abstract-declarator[opt] attributes[opt]
|
|
||||||
/// decl-specifier-seq abstract-declarator[opt] attributes[opt]
|
|
||||||
/// '=' assignment-expression
|
/// '=' assignment-expression
|
||||||
|
/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
|
||||||
|
/// attributes[opt]
|
||||||
|
/// attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
|
||||||
|
/// attributes[opt] '=' assignment-expression
|
||||||
///
|
///
|
||||||
Parser::TPResult Parser::TryParseParameterDeclarationClause() {
|
Parser::TPResult Parser::TryParseParameterDeclarationClause() {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
// RUN: %clang_cc1 -std=c++11 -verify %s
|
||||||
|
|
||||||
|
namespace std_example {
|
||||||
|
|
||||||
|
int p[10];
|
||||||
|
void f() {
|
||||||
|
int x = 42, y[5];
|
||||||
|
// FIXME: Produce a better diagnostic for this case.
|
||||||
|
int(p[[x] { return x; }()]); // expected-error {{expected ']'}}
|
||||||
|
y[[] { return 2; }()] = 2; // expected-error {{consecutive left square brackets}}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,11 +5,17 @@
|
||||||
int [[]] between_attr;
|
int [[]] between_attr;
|
||||||
int after_attr [[]];
|
int after_attr [[]];
|
||||||
int * [[]] ptr_attr;
|
int * [[]] ptr_attr;
|
||||||
|
int & [[]] ref_attr = after_attr;
|
||||||
|
int && [[]] rref_attr = 0;
|
||||||
int array_attr [1] [[]];
|
int array_attr [1] [[]];
|
||||||
alignas(8) int aligned_attr;
|
alignas(8) int aligned_attr;
|
||||||
[[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]]
|
[[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]]
|
||||||
int garbage_attr;
|
int garbage_attr;
|
||||||
void fn_attr () [[]];
|
void fn_attr () [[]];
|
||||||
|
void noexcept_fn_attr () noexcept [[]];
|
||||||
|
struct MemberFnOrder {
|
||||||
|
virtual void f() const volatile && noexcept [[]] final = 0;
|
||||||
|
};
|
||||||
class [[]] class_attr {};
|
class [[]] class_attr {};
|
||||||
extern "C++" [[]] int extern_attr;
|
extern "C++" [[]] int extern_attr;
|
||||||
template <typename T> [[]] void template_attr ();
|
template <typename T> [[]] void template_attr ();
|
||||||
|
@ -17,10 +23,10 @@ template <typename T> [[]] void template_attr ();
|
||||||
|
|
||||||
int comma_attr [[,]]; // expected-error {{expected identifier}}
|
int comma_attr [[,]]; // expected-error {{expected identifier}}
|
||||||
int scope_attr [[foo::]]; // expected-error {{expected identifier}}
|
int scope_attr [[foo::]]; // expected-error {{expected identifier}}
|
||||||
|
int (paren_attr) [[]]; // expected-error {{an attribute list cannot appear here}}
|
||||||
unsigned [[]] int attr_in_decl_spec; // expected-error {{expected unqualified-id}}
|
unsigned [[]] int attr_in_decl_spec; // expected-error {{expected unqualified-id}}
|
||||||
int & [[]] ref_attr = after_attr; // expected-error {{an attribute list cannot appear here}}
|
|
||||||
class foo {
|
class foo {
|
||||||
void after_const_attr () const [[]]; // expected-error {{expected body of lambda expression}}
|
void const_after_attr () [[]] const; // expected-error {{expected ';'}}
|
||||||
};
|
};
|
||||||
extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
|
extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
|
||||||
[[]] template <typename T> void before_template_attr (); // expected-error {{an attribute list cannot appear here}}
|
[[]] template <typename T> void before_template_attr (); // expected-error {{an attribute list cannot appear here}}
|
||||||
|
@ -58,6 +64,9 @@ void foo () {
|
||||||
[[]] try {
|
[[]] try {
|
||||||
} [[]] catch (...) { // expected-error {{an attribute list cannot appear here}}
|
} [[]] catch (...) { // expected-error {{an attribute list cannot appear here}}
|
||||||
}
|
}
|
||||||
|
struct S { int arr[2]; } s;
|
||||||
|
(void)s.arr[ [] { return 0; }() ]; // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}}
|
||||||
|
int n = __builtin_offsetof(S, arr[ [] { return 0; }() ]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}}
|
||||||
|
|
||||||
[[]] return;
|
[[]] return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||||
|
|
||||||
|
@interface X {}
|
||||||
|
+ (X*) alloc;
|
||||||
|
- (X*) init;
|
||||||
|
- (int) getSize;
|
||||||
|
- (void) setSize: (int) size;
|
||||||
|
- (X*) getSelf;
|
||||||
|
@end
|
||||||
|
|
||||||
|
void f(X *noreturn) {
|
||||||
|
// An array size which is computed by a message send is OK.
|
||||||
|
int a[ [noreturn getSize] ];
|
||||||
|
|
||||||
|
// ... but is interpreted as an attribute where possible.
|
||||||
|
int b[ [noreturn] ]; // expected-warning {{'noreturn' only applies to function types}}
|
||||||
|
|
||||||
|
int c[ [noreturn getSize] + 1 ];
|
||||||
|
|
||||||
|
// An array size which is computed by a lambda is not OK.
|
||||||
|
int d[ [noreturn] { return 3; } () ]; // expected-error {{expected ']'}} expected-warning {{'noreturn' only applies}}
|
||||||
|
|
||||||
|
// A message send which contains a message send is OK.
|
||||||
|
[ [ X alloc ] init ];
|
||||||
|
[ [ int(), noreturn getSelf ] getSize ]; // expected-warning {{unused}}
|
||||||
|
|
||||||
|
// A message send which contains a lambda is OK.
|
||||||
|
[ [noreturn] { return noreturn; } () setSize: 4 ];
|
||||||
|
[ [bitand] { return noreturn; } () setSize: 5 ];
|
||||||
|
[[[[] { return [ X alloc ]; } () init] getSelf] getSize];
|
||||||
|
|
||||||
|
// An attribute is OK.
|
||||||
|
[[]];
|
||||||
|
[[int(), noreturn]];
|
||||||
|
[[class, test(foo 'x' bar),,,]];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename...Ts> void f(Ts ...x) {
|
||||||
|
[[test::foo(bar, baz)...]];
|
||||||
|
[[used(x)...]];
|
||||||
|
[[x...] { return [ X alloc ]; }() init];
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -std=c++11
|
||||||
|
|
||||||
|
using size_t = decltype(sizeof(0));
|
||||||
|
struct noreturn_t {} constexpr noreturn = {};
|
||||||
|
|
||||||
|
void *operator new [[noreturn]] (size_t, noreturn_t);
|
||||||
|
void operator delete [[noreturn]] (void*, noreturn_t);
|
||||||
|
|
||||||
|
void good_news()
|
||||||
|
{
|
||||||
|
auto p = new int[2][[]];
|
||||||
|
auto q = new int[[]][2];
|
||||||
|
auto r = new int*[[]][2][[]];
|
||||||
|
auto s = new (int(*[[]])[2][[]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bad_news(int *ip)
|
||||||
|
{
|
||||||
|
// attribute-specifiers can go almost anywhere in a new-type-id...
|
||||||
|
auto r = new int[[]{return 1;}()][2]; // expected-error {{expected ']'}}
|
||||||
|
auto s = new int*[[]{return 1;}()][2]; // expected-error {{expected ']'}}
|
||||||
|
// ... but not here:
|
||||||
|
auto t = new (int(*)[[]]); // expected-error {{an attribute list cannot appear here}}
|
||||||
|
auto u = new (int(*)[[]{return 1;}()][2]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}} expected-error {{variably modified type}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void good_deletes()
|
||||||
|
{
|
||||||
|
delete [&]{ return (int*)0; }();
|
||||||
|
// FIXME: This appears to be legal.
|
||||||
|
delete []{ return (int*)0; }(); // unexpected-error {{expected expression}}
|
||||||
|
}
|
|
@ -102,8 +102,7 @@ void good_deletes()
|
||||||
void bad_deletes()
|
void bad_deletes()
|
||||||
{
|
{
|
||||||
delete 0; // expected-error {{cannot delete expression of type 'int'}}
|
delete 0; // expected-error {{cannot delete expression of type 'int'}}
|
||||||
delete [0] (int*)0; // expected-error {{expected ']'}} \
|
delete [0] (int*)0; // expected-error {{expected expression}}
|
||||||
// expected-note {{to match this '['}}
|
|
||||||
delete (void*)0; // expected-warning {{cannot delete expression with pointer-to-'void' type 'void *'}}
|
delete (void*)0; // expected-warning {{cannot delete expression with pointer-to-'void' type 'void *'}}
|
||||||
delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
|
delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
|
||||||
::S::delete (int*)0; // expected-error {{expected unqualified-id}}
|
::S::delete (int*)0; // expected-error {{expected unqualified-id}}
|
||||||
|
|
Loading…
Reference in New Issue