2006-11-05 15:46:30 +08:00
|
|
|
//===--- ParseExpr.cpp - Expression Parsing -------------------------------===//
|
2006-08-10 12:23:57 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2006-08-10 12:23:57 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2012-06-20 05:02:26 +08:00
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \file
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Provides the Expression parsing implementation.
|
2012-06-17 12:36:28 +08:00
|
|
|
///
|
|
|
|
/// Expressions in C99 basically consist of a bunch of binary operators with
|
|
|
|
/// unary operators and other random stuff at the leaves.
|
|
|
|
///
|
|
|
|
/// In the C99 grammar, these unary operators bind tightest and are represented
|
|
|
|
/// as the 'cast-expression' production. Everything else is either a binary
|
|
|
|
/// operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are
|
|
|
|
/// handled by ParseCastExpression, the higher level pieces are handled by
|
|
|
|
/// ParseBinaryExpression.
|
2012-06-20 05:02:26 +08:00
|
|
|
///
|
|
|
|
//===----------------------------------------------------------------------===//
|
2006-08-10 12:23:57 +08:00
|
|
|
|
2017-03-23 23:11:07 +08:00
|
|
|
#include "clang/Parse/Parser.h"
|
2014-03-04 18:05:20 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2020-01-09 21:07:51 +08:00
|
|
|
#include "clang/AST/ExprCXX.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Basic/PrettyStackTrace.h"
|
2017-03-23 23:11:07 +08:00
|
|
|
#include "clang/Parse/RAIIObjectsForParser.h"
|
2010-08-21 02:27:03 +08:00
|
|
|
#include "clang/Sema/DeclSpec.h"
|
|
|
|
#include "clang/Sema/ParsedTemplate.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Sema/Scope.h"
|
2012-01-26 04:49:08 +08:00
|
|
|
#include "clang/Sema/TypoCorrection.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2006-08-10 12:23:57 +08:00
|
|
|
using namespace clang;
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Simple precedence-based parser for binary/ternary operators.
|
2006-08-12 16:13:25 +08:00
|
|
|
///
|
2006-08-13 00:45:01 +08:00
|
|
|
/// Note: we diverge from the C99 grammar when parsing the assignment-expression
|
|
|
|
/// production. C99 specifies that the LHS of an assignment operator should be
|
|
|
|
/// parsed as a unary-expression, but consistency dictates that it be a
|
|
|
|
/// conditional-expession. In practice, the important thing here is that the
|
|
|
|
/// LHS of an assignment has to be an l-value, which productions between
|
|
|
|
/// unary-expression and conditional-expression don't produce. Because we want
|
|
|
|
/// consistency, we parse the LHS as a conditional-expression, then check for
|
|
|
|
/// l-value-ness in semantic analysis stages.
|
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2009-02-07 08:15:38 +08:00
|
|
|
/// pm-expression: [C++ 5.5]
|
|
|
|
/// cast-expression
|
|
|
|
/// pm-expression '.*' cast-expression
|
|
|
|
/// pm-expression '->*' cast-expression
|
|
|
|
///
|
2006-08-12 16:13:25 +08:00
|
|
|
/// multiplicative-expression: [C99 6.5.5]
|
2009-02-07 08:15:38 +08:00
|
|
|
/// Note: in C++, apply pm-expression instead of cast-expression
|
2006-08-12 16:13:25 +08:00
|
|
|
/// cast-expression
|
|
|
|
/// multiplicative-expression '*' cast-expression
|
|
|
|
/// multiplicative-expression '/' cast-expression
|
|
|
|
/// multiplicative-expression '%' cast-expression
|
|
|
|
///
|
|
|
|
/// additive-expression: [C99 6.5.6]
|
|
|
|
/// multiplicative-expression
|
|
|
|
/// additive-expression '+' multiplicative-expression
|
|
|
|
/// additive-expression '-' multiplicative-expression
|
|
|
|
///
|
|
|
|
/// shift-expression: [C99 6.5.7]
|
|
|
|
/// additive-expression
|
|
|
|
/// shift-expression '<<' additive-expression
|
|
|
|
/// shift-expression '>>' additive-expression
|
|
|
|
///
|
2017-12-14 23:16:18 +08:00
|
|
|
/// compare-expression: [C++20 expr.spaceship]
|
2006-08-12 16:13:25 +08:00
|
|
|
/// shift-expression
|
2017-12-14 23:16:18 +08:00
|
|
|
/// compare-expression '<=>' shift-expression
|
|
|
|
///
|
|
|
|
/// relational-expression: [C99 6.5.8]
|
|
|
|
/// compare-expression
|
|
|
|
/// relational-expression '<' compare-expression
|
|
|
|
/// relational-expression '>' compare-expression
|
|
|
|
/// relational-expression '<=' compare-expression
|
|
|
|
/// relational-expression '>=' compare-expression
|
2006-08-12 16:13:25 +08:00
|
|
|
///
|
|
|
|
/// equality-expression: [C99 6.5.9]
|
|
|
|
/// relational-expression
|
|
|
|
/// equality-expression '==' relational-expression
|
|
|
|
/// equality-expression '!=' relational-expression
|
|
|
|
///
|
|
|
|
/// AND-expression: [C99 6.5.10]
|
|
|
|
/// equality-expression
|
|
|
|
/// AND-expression '&' equality-expression
|
|
|
|
///
|
|
|
|
/// exclusive-OR-expression: [C99 6.5.11]
|
|
|
|
/// AND-expression
|
|
|
|
/// exclusive-OR-expression '^' AND-expression
|
|
|
|
///
|
|
|
|
/// inclusive-OR-expression: [C99 6.5.12]
|
|
|
|
/// exclusive-OR-expression
|
|
|
|
/// inclusive-OR-expression '|' exclusive-OR-expression
|
|
|
|
///
|
|
|
|
/// logical-AND-expression: [C99 6.5.13]
|
|
|
|
/// inclusive-OR-expression
|
|
|
|
/// logical-AND-expression '&&' inclusive-OR-expression
|
|
|
|
///
|
|
|
|
/// logical-OR-expression: [C99 6.5.14]
|
|
|
|
/// logical-AND-expression
|
|
|
|
/// logical-OR-expression '||' logical-AND-expression
|
|
|
|
///
|
|
|
|
/// conditional-expression: [C99 6.5.15]
|
|
|
|
/// logical-OR-expression
|
|
|
|
/// logical-OR-expression '?' expression ':' conditional-expression
|
|
|
|
/// [GNU] logical-OR-expression '?' ':' conditional-expression
|
2009-04-17 01:51:27 +08:00
|
|
|
/// [C++] the third operand is an assignment-expression
|
2006-08-12 16:13:25 +08:00
|
|
|
///
|
|
|
|
/// assignment-expression: [C99 6.5.16]
|
|
|
|
/// conditional-expression
|
|
|
|
/// unary-expression assignment-operator assignment-expression
|
2008-02-26 08:51:44 +08:00
|
|
|
/// [C++] throw-expression [C++ 15]
|
2006-08-12 16:13:25 +08:00
|
|
|
///
|
|
|
|
/// assignment-operator: one of
|
|
|
|
/// = *= /= %= += -= <<= >>= &= ^= |=
|
|
|
|
///
|
|
|
|
/// expression: [C99 6.5.17]
|
2011-01-04 03:31:53 +08:00
|
|
|
/// assignment-expression ...[opt]
|
|
|
|
/// expression ',' assignment-expression ...[opt]
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2012-01-26 04:49:08 +08:00
|
|
|
ExprResult Parser::ParseExpression(TypeCastState isTypeCast) {
|
|
|
|
ExprResult LHS(ParseAssignmentExpression(isTypeCast));
|
2012-08-24 05:35:17 +08:00
|
|
|
return ParseRHSOfBinaryExpression(LHS, prec::Comma);
|
2006-08-12 16:13:25 +08:00
|
|
|
}
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
/// This routine is called when the '@' is seen and consumed.
|
2007-09-20 03:14:32 +08:00
|
|
|
/// Current token is an Identifier and is not a 'try'. This
|
2012-06-15 14:52:33 +08:00
|
|
|
/// routine is necessary to disambiguate \@try-statement from,
|
|
|
|
/// for example, \@encode-expression.
|
2007-09-20 03:14:32 +08:00
|
|
|
///
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2008-12-12 06:33:27 +08:00
|
|
|
Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) {
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult LHS(ParseObjCAtExpression(AtLoc));
|
2012-08-24 05:35:17 +08:00
|
|
|
return ParseRHSOfBinaryExpression(LHS, prec::Comma);
|
2007-09-20 03:14:32 +08:00
|
|
|
}
|
|
|
|
|
2009-01-27 16:43:38 +08:00
|
|
|
/// This routine is called when a leading '__extension__' is seen and
|
|
|
|
/// consumed. This is necessary because the token gets consumed in the
|
|
|
|
/// process of disambiguating between an expression and a declaration.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2009-01-27 16:43:38 +08:00
|
|
|
Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) {
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult LHS(true);
|
2009-05-17 07:40:44 +08:00
|
|
|
{
|
|
|
|
// Silence extension warnings in the sub-expression
|
|
|
|
ExtensionRAIIObject O(Diags);
|
|
|
|
|
2020-01-09 21:07:51 +08:00
|
|
|
LHS = ParseCastExpression(AnyCastExpr);
|
2009-05-17 07:40:44 +08:00
|
|
|
}
|
2009-01-27 16:43:38 +08:00
|
|
|
|
When we run into an error parsing or type-checking the left-hand side
of a binary expression, continue on and parse the right-hand side of
the binary expression anyway, but don't call the semantic actions to
type-check. Previously, we would see the error and then, effectively,
skip tokens until the end of the statement.
The result should be more useful recovery, both in the normal case
(we'll actually see errors beyond the first one in a statement), but
it also helps code completion do a much better job, because we do
"real" code completion on the right-hand side of an invalid binary
expression rather than completing with the recovery completion. For
example, given
x = p->y
if there is no variable named "x", we can still complete after the p->
as a member expression. Along the recovery path, we would have
completed after the "->" as if we were in an expression context, which
is mostly useless.
llvm-svn: 114225
2010-09-18 06:25:06 +08:00
|
|
|
if (!LHS.isInvalid())
|
|
|
|
LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__,
|
2014-05-29 18:55:11 +08:00
|
|
|
LHS.get());
|
2009-01-27 16:43:38 +08:00
|
|
|
|
2012-08-24 05:35:17 +08:00
|
|
|
return ParseRHSOfBinaryExpression(LHS, prec::Comma);
|
2009-01-27 16:43:38 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse an expr that doesn't include (top-level) commas.
|
2012-01-26 04:49:08 +08:00
|
|
|
ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) {
|
Improve code completion by introducing patterns for the various C and
C++ grammatical constructs that show up in top-level (namespace-level)
declarations, member declarations, template declarations, statements,
expressions, conditions, etc. For example, we now provide a pattern
for
static_cast<type>(expr)
when we can have an expression, or
using namespace identifier;
when we can have a using directive.
Also, improves the results of code completion at the beginning of a
top-level declaration. Previously, we would see value names (function
names, global variables, etc.); now we see types, namespace names,
etc., but no values.
llvm-svn: 93134
2010-01-11 07:08:15 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2021-03-12 19:00:54 +08:00
|
|
|
cutOffParsing();
|
2019-02-01 04:20:32 +08:00
|
|
|
Actions.CodeCompleteExpression(getCurScope(),
|
|
|
|
PreferredType.get(Tok.getLocation()));
|
2011-09-04 11:32:15 +08:00
|
|
|
return ExprError();
|
Improve code completion by introducing patterns for the various C and
C++ grammatical constructs that show up in top-level (namespace-level)
declarations, member declarations, template declarations, statements,
expressions, conditions, etc. For example, we now provide a pattern
for
static_cast<type>(expr)
when we can have an expression, or
using namespace identifier;
when we can have a using directive.
Also, improves the results of code completion at the beginning of a
top-level declaration. Previously, we would see value names (function
names, global variables, etc.); now we see types, namespace names,
etc., but no values.
llvm-svn: 93134
2010-01-11 07:08:15 +08:00
|
|
|
}
|
|
|
|
|
2011-04-27 14:18:01 +08:00
|
|
|
if (Tok.is(tok::kw_throw))
|
2008-12-12 06:51:44 +08:00
|
|
|
return ParseThrowExpression();
|
2015-10-22 12:46:14 +08:00
|
|
|
if (Tok.is(tok::kw_co_yield))
|
|
|
|
return ParseCoyieldExpression();
|
2008-02-26 08:51:44 +08:00
|
|
|
|
2020-01-09 21:07:51 +08:00
|
|
|
ExprResult LHS = ParseCastExpression(AnyCastExpr,
|
2012-01-26 04:49:08 +08:00
|
|
|
/*isAddressOfOperand=*/false,
|
|
|
|
isTypeCast);
|
2012-08-24 05:35:17 +08:00
|
|
|
return ParseRHSOfBinaryExpression(LHS, prec::Assignment);
|
2006-08-13 01:22:40 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse an assignment expression where part of an Objective-C message
|
2012-06-17 12:36:28 +08:00
|
|
|
/// send has already been parsed.
|
|
|
|
///
|
|
|
|
/// In this case \p LBracLoc indicates the location of the '[' of the message
|
|
|
|
/// send, and either \p ReceiverName or \p ReceiverExpr is non-null indicating
|
|
|
|
/// the receiver of the message.
|
2008-06-03 05:31:07 +08:00
|
|
|
///
|
|
|
|
/// Since this handles full assignment-expression's, it handles postfix
|
|
|
|
/// expressions and other binary operators for these expressions as well.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2008-06-03 05:31:07 +08:00
|
|
|
Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
SourceLocation SuperLoc,
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType ReceiverType,
|
2010-08-24 07:25:46 +08:00
|
|
|
Expr *ReceiverExpr) {
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult R
|
2010-08-24 07:25:46 +08:00
|
|
|
= ParseObjCMessageExpressionBody(LBracLoc, SuperLoc,
|
|
|
|
ReceiverType, ReceiverExpr);
|
2010-09-18 09:28:11 +08:00
|
|
|
R = ParsePostfixExpressionSuffix(R);
|
When we run into an error parsing or type-checking the left-hand side
of a binary expression, continue on and parse the right-hand side of
the binary expression anyway, but don't call the semantic actions to
type-check. Previously, we would see the error and then, effectively,
skip tokens until the end of the statement.
The result should be more useful recovery, both in the normal case
(we'll actually see errors beyond the first one in a statement), but
it also helps code completion do a much better job, because we do
"real" code completion on the right-hand side of an invalid binary
expression rather than completing with the recovery completion. For
example, given
x = p->y
if there is no variable named "x", we can still complete after the p->
as a member expression. Along the recovery path, we would have
completed after the "->" as if we were in an expression context, which
is mostly useless.
llvm-svn: 114225
2010-09-18 06:25:06 +08:00
|
|
|
return ParseRHSOfBinaryExpression(R, prec::Assignment);
|
2008-06-03 05:31:07 +08:00
|
|
|
}
|
|
|
|
|
Fix PR25627: constant expressions being odr-used in template arguments.
This patch ensures that clang processes the expression-nodes that are generated when disambiguating between types and expressions within template arguments as constant-expressions by installing the ConstantEvaluated ExpressionEvaluationContext just before attempting the disambiguation - and then making sure that Context carries through into ParseConstantExpression (by refactoring it out into a function that does not create its own EvaluationContext: ParseConstantExpressionInExprEvalContext)
Note, prior to this patch, trunk would correctly disambiguate and identify the expression as an expression - and while it would annotate the token with the expression - it would fail to complete the odr-use processing (specifically, failing to trigger Sema::UpdateMarkingForLValueToRValue as is done for all Constant Expressions, which would remove it from being considered odr-used). By installing the ConstantExpression Evaluation Context prior to disambiguation, and making sure it carries though, we ensure correct processing of the expression-node.
For e.g:
template<int> struct X { };
void f() {
const int N = 10;
X<N> x; // should be OK.
[] { return X<N>{}; }; // Should be OK - no capture - but clang errors!
}
See a related bug: https://bugs.llvm.org//show_bug.cgi?id=25627
In summary (and reiteration), the fix is as follows:
- Remove the EnteredConstantEvaluatedContext action from ParseTemplateArgumentList (relying on ParseTemplateArgument getting it right)
- Add the EnteredConstantEvaluatedContext action just prior to undergoing the disambiguating parse, and if the parse succeeds for an expression, carry the context though into a refactored version of ParseConstantExpression that does not create its own ExpressionEvaluationContext.
See https://reviews.llvm.org/D31588 for additional context regarding some of the more fragile and complicated approaches attempted, and Richard's feedback that eventually shaped the simpler and more robust rendition that is being committed.
Thanks Richard!
llvm-svn: 303492
2017-05-21 03:58:04 +08:00
|
|
|
ExprResult
|
|
|
|
Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) {
|
|
|
|
assert(Actions.ExprEvalContexts.back().Context ==
|
|
|
|
Sema::ExpressionEvaluationContext::ConstantEvaluated &&
|
|
|
|
"Call this function only if your ExpressionEvaluationContext is "
|
|
|
|
"already ConstantEvaluated");
|
2020-01-09 21:07:51 +08:00
|
|
|
ExprResult LHS(ParseCastExpression(AnyCastExpr, false, isTypeCast));
|
Fix PR25627: constant expressions being odr-used in template arguments.
This patch ensures that clang processes the expression-nodes that are generated when disambiguating between types and expressions within template arguments as constant-expressions by installing the ConstantEvaluated ExpressionEvaluationContext just before attempting the disambiguation - and then making sure that Context carries through into ParseConstantExpression (by refactoring it out into a function that does not create its own EvaluationContext: ParseConstantExpressionInExprEvalContext)
Note, prior to this patch, trunk would correctly disambiguate and identify the expression as an expression - and while it would annotate the token with the expression - it would fail to complete the odr-use processing (specifically, failing to trigger Sema::UpdateMarkingForLValueToRValue as is done for all Constant Expressions, which would remove it from being considered odr-used). By installing the ConstantExpression Evaluation Context prior to disambiguation, and making sure it carries though, we ensure correct processing of the expression-node.
For e.g:
template<int> struct X { };
void f() {
const int N = 10;
X<N> x; // should be OK.
[] { return X<N>{}; }; // Should be OK - no capture - but clang errors!
}
See a related bug: https://bugs.llvm.org//show_bug.cgi?id=25627
In summary (and reiteration), the fix is as follows:
- Remove the EnteredConstantEvaluatedContext action from ParseTemplateArgumentList (relying on ParseTemplateArgument getting it right)
- Add the EnteredConstantEvaluatedContext action just prior to undergoing the disambiguating parse, and if the parse succeeds for an expression, carry the context though into a refactored version of ParseConstantExpression that does not create its own ExpressionEvaluationContext.
See https://reviews.llvm.org/D31588 for additional context regarding some of the more fragile and complicated approaches attempted, and Richard's feedback that eventually shaped the simpler and more robust rendition that is being committed.
Thanks Richard!
llvm-svn: 303492
2017-05-21 03:58:04 +08:00
|
|
|
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
|
|
|
|
return Actions.ActOnConstantExpression(Res);
|
|
|
|
}
|
2008-06-03 05:31:07 +08:00
|
|
|
|
2012-02-22 09:03:07 +08:00
|
|
|
ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) {
|
2011-12-20 10:08:33 +08:00
|
|
|
// C++03 [basic.def.odr]p2:
|
2009-09-09 23:08:12 +08:00
|
|
|
// An expression is potentially evaluated unless it appears where an
|
2009-06-20 07:52:42 +08:00
|
|
|
// integral constant expression is required (see 5.19) [...].
|
2011-12-20 10:08:33 +08:00
|
|
|
// C++98 and C++11 have no such rule, but this is only a defect in C++98.
|
2017-04-02 05:30:49 +08:00
|
|
|
EnterExpressionEvaluationContext ConstantEvaluated(
|
|
|
|
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
|
Fix PR25627: constant expressions being odr-used in template arguments.
This patch ensures that clang processes the expression-nodes that are generated when disambiguating between types and expressions within template arguments as constant-expressions by installing the ConstantEvaluated ExpressionEvaluationContext just before attempting the disambiguation - and then making sure that Context carries through into ParseConstantExpression (by refactoring it out into a function that does not create its own EvaluationContext: ParseConstantExpressionInExprEvalContext)
Note, prior to this patch, trunk would correctly disambiguate and identify the expression as an expression - and while it would annotate the token with the expression - it would fail to complete the odr-use processing (specifically, failing to trigger Sema::UpdateMarkingForLValueToRValue as is done for all Constant Expressions, which would remove it from being considered odr-used). By installing the ConstantExpression Evaluation Context prior to disambiguation, and making sure it carries though, we ensure correct processing of the expression-node.
For e.g:
template<int> struct X { };
void f() {
const int N = 10;
X<N> x; // should be OK.
[] { return X<N>{}; }; // Should be OK - no capture - but clang errors!
}
See a related bug: https://bugs.llvm.org//show_bug.cgi?id=25627
In summary (and reiteration), the fix is as follows:
- Remove the EnteredConstantEvaluatedContext action from ParseTemplateArgumentList (relying on ParseTemplateArgument getting it right)
- Add the EnteredConstantEvaluatedContext action just prior to undergoing the disambiguating parse, and if the parse succeeds for an expression, carry the context though into a refactored version of ParseConstantExpression that does not create its own ExpressionEvaluationContext.
See https://reviews.llvm.org/D31588 for additional context regarding some of the more fragile and complicated approaches attempted, and Richard's feedback that eventually shaped the simpler and more robust rendition that is being committed.
Thanks Richard!
llvm-svn: 303492
2017-05-21 03:58:04 +08:00
|
|
|
return ParseConstantExpressionInExprEvalContext(isTypeCast);
|
2006-08-13 08:12:11 +08:00
|
|
|
}
|
|
|
|
|
2018-07-27 02:41:30 +08:00
|
|
|
ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) {
|
|
|
|
EnterExpressionEvaluationContext ConstantEvaluated(
|
|
|
|
Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated);
|
2020-01-09 21:07:51 +08:00
|
|
|
ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast));
|
2018-07-27 02:41:30 +08:00
|
|
|
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
|
|
|
|
return Actions.ActOnCaseExpr(CaseLoc, Res);
|
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a constraint-expression.
|
2015-06-25 08:23:39 +08:00
|
|
|
///
|
|
|
|
/// \verbatim
|
2019-10-15 23:24:26 +08:00
|
|
|
/// constraint-expression: C++2a[temp.constr.decl]p1
|
2015-06-25 08:23:39 +08:00
|
|
|
/// logical-or-expression
|
|
|
|
/// \endverbatim
|
|
|
|
ExprResult Parser::ParseConstraintExpression() {
|
2019-10-15 23:24:26 +08:00
|
|
|
EnterExpressionEvaluationContext ConstantEvaluated(
|
2020-01-24 08:22:17 +08:00
|
|
|
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
|
2020-01-09 21:07:51 +08:00
|
|
|
ExprResult LHS(ParseCastExpression(AnyCastExpr));
|
2015-06-25 08:23:39 +08:00
|
|
|
ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));
|
2020-01-09 21:07:51 +08:00
|
|
|
if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) {
|
|
|
|
Actions.CorrectDelayedTyposInExpr(Res);
|
2019-10-15 23:24:26 +08:00
|
|
|
return ExprError();
|
2020-01-09 21:07:51 +08:00
|
|
|
}
|
2015-06-25 08:23:39 +08:00
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
2020-01-09 21:07:51 +08:00
|
|
|
/// \brief Parse a constraint-logical-and-expression.
|
|
|
|
///
|
|
|
|
/// \verbatim
|
|
|
|
/// C++2a[temp.constr.decl]p1
|
|
|
|
/// constraint-logical-and-expression:
|
|
|
|
/// primary-expression
|
|
|
|
/// constraint-logical-and-expression '&&' primary-expression
|
|
|
|
///
|
|
|
|
/// \endverbatim
|
|
|
|
ExprResult
|
|
|
|
Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) {
|
|
|
|
EnterExpressionEvaluationContext ConstantEvaluated(
|
2020-01-24 08:22:17 +08:00
|
|
|
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
|
2020-01-09 21:07:51 +08:00
|
|
|
bool NotPrimaryExpression = false;
|
|
|
|
auto ParsePrimary = [&] () {
|
|
|
|
ExprResult E = ParseCastExpression(PrimaryExprOnly,
|
|
|
|
/*isAddressOfOperand=*/false,
|
|
|
|
/*isTypeCast=*/NotTypeCast,
|
|
|
|
/*isVectorLiteral=*/false,
|
|
|
|
&NotPrimaryExpression);
|
|
|
|
if (E.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
auto RecoverFromNonPrimary = [&] (ExprResult E, bool Note) {
|
|
|
|
E = ParsePostfixExpressionSuffix(E);
|
|
|
|
// Use InclusiveOr, the precedence just after '&&' to not parse the
|
|
|
|
// next arguments to the logical and.
|
|
|
|
E = ParseRHSOfBinaryExpression(E, prec::InclusiveOr);
|
|
|
|
if (!E.isInvalid())
|
|
|
|
Diag(E.get()->getExprLoc(),
|
|
|
|
Note
|
|
|
|
? diag::note_unparenthesized_non_primary_expr_in_requires_clause
|
|
|
|
: diag::err_unparenthesized_non_primary_expr_in_requires_clause)
|
|
|
|
<< FixItHint::CreateInsertion(E.get()->getBeginLoc(), "(")
|
|
|
|
<< FixItHint::CreateInsertion(
|
|
|
|
PP.getLocForEndOfToken(E.get()->getEndLoc()), ")")
|
|
|
|
<< E.get()->getSourceRange();
|
|
|
|
return E;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (NotPrimaryExpression ||
|
|
|
|
// Check if the following tokens must be a part of a non-primary
|
|
|
|
// expression
|
|
|
|
getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
|
|
|
|
/*CPlusPlus11=*/true) > prec::LogicalAnd ||
|
|
|
|
// Postfix operators other than '(' (which will be checked for in
|
|
|
|
// CheckConstraintExpression).
|
|
|
|
Tok.isOneOf(tok::period, tok::plusplus, tok::minusminus) ||
|
|
|
|
(Tok.is(tok::l_square) && !NextToken().is(tok::l_square))) {
|
|
|
|
E = RecoverFromNonPrimary(E, /*Note=*/false);
|
|
|
|
if (E.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
NotPrimaryExpression = false;
|
|
|
|
}
|
|
|
|
bool PossibleNonPrimary;
|
|
|
|
bool IsConstraintExpr =
|
|
|
|
Actions.CheckConstraintExpression(E.get(), Tok, &PossibleNonPrimary,
|
|
|
|
IsTrailingRequiresClause);
|
|
|
|
if (!IsConstraintExpr || PossibleNonPrimary) {
|
|
|
|
// Atomic constraint might be an unparenthesized non-primary expression
|
|
|
|
// (such as a binary operator), in which case we might get here (e.g. in
|
|
|
|
// 'requires 0 + 1 && true' we would now be at '+', and parse and ignore
|
|
|
|
// the rest of the addition expression). Try to parse the rest of it here.
|
|
|
|
if (PossibleNonPrimary)
|
|
|
|
E = RecoverFromNonPrimary(E, /*Note=*/!IsConstraintExpr);
|
|
|
|
Actions.CorrectDelayedTyposInExpr(E);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
return E;
|
|
|
|
};
|
|
|
|
ExprResult LHS = ParsePrimary();
|
|
|
|
if (LHS.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
while (Tok.is(tok::ampamp)) {
|
|
|
|
SourceLocation LogicalAndLoc = ConsumeToken();
|
|
|
|
ExprResult RHS = ParsePrimary();
|
|
|
|
if (RHS.isInvalid()) {
|
|
|
|
Actions.CorrectDelayedTyposInExpr(LHS);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalAndLoc,
|
|
|
|
tok::ampamp, LHS.get(), RHS.get());
|
|
|
|
if (!Op.isUsable()) {
|
|
|
|
Actions.CorrectDelayedTyposInExpr(RHS);
|
|
|
|
Actions.CorrectDelayedTyposInExpr(LHS);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
LHS = Op;
|
|
|
|
}
|
|
|
|
return LHS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Parse a constraint-logical-or-expression.
|
|
|
|
///
|
|
|
|
/// \verbatim
|
|
|
|
/// C++2a[temp.constr.decl]p1
|
|
|
|
/// constraint-logical-or-expression:
|
|
|
|
/// constraint-logical-and-expression
|
|
|
|
/// constraint-logical-or-expression '||'
|
|
|
|
/// constraint-logical-and-expression
|
|
|
|
///
|
|
|
|
/// \endverbatim
|
|
|
|
ExprResult
|
|
|
|
Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause) {
|
|
|
|
ExprResult LHS(ParseConstraintLogicalAndExpression(IsTrailingRequiresClause));
|
|
|
|
if (!LHS.isUsable())
|
|
|
|
return ExprError();
|
|
|
|
while (Tok.is(tok::pipepipe)) {
|
|
|
|
SourceLocation LogicalOrLoc = ConsumeToken();
|
|
|
|
ExprResult RHS =
|
|
|
|
ParseConstraintLogicalAndExpression(IsTrailingRequiresClause);
|
|
|
|
if (!RHS.isUsable()) {
|
|
|
|
Actions.CorrectDelayedTyposInExpr(LHS);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalOrLoc,
|
|
|
|
tok::pipepipe, LHS.get(), RHS.get());
|
|
|
|
if (!Op.isUsable()) {
|
|
|
|
Actions.CorrectDelayedTyposInExpr(RHS);
|
|
|
|
Actions.CorrectDelayedTyposInExpr(LHS);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
LHS = Op;
|
|
|
|
}
|
|
|
|
return LHS;
|
|
|
|
}
|
|
|
|
|
2012-09-18 08:52:05 +08:00
|
|
|
bool Parser::isNotExpressionStart() {
|
|
|
|
tok::TokenKind K = Tok.getKind();
|
|
|
|
if (K == tok::l_brace || K == tok::r_brace ||
|
|
|
|
K == tok::kw_for || K == tok::kw_while ||
|
|
|
|
K == tok::kw_if || K == tok::kw_else ||
|
|
|
|
K == tok::kw_goto || K == tok::kw_try)
|
|
|
|
return true;
|
|
|
|
// If this is a decl-specifier, we can't be at the start of an expression.
|
|
|
|
return isKnownToBeDeclarationSpecifier();
|
|
|
|
}
|
|
|
|
|
2017-11-01 04:29:22 +08:00
|
|
|
bool Parser::isFoldOperator(prec::Level Level) const {
|
2017-12-14 23:16:18 +08:00
|
|
|
return Level > prec::Unknown && Level != prec::Conditional &&
|
|
|
|
Level != prec::Spaceship;
|
2014-11-08 13:07:16 +08:00
|
|
|
}
|
2017-11-01 04:29:22 +08:00
|
|
|
|
|
|
|
bool Parser::isFoldOperator(tok::TokenKind Kind) const {
|
|
|
|
return isFoldOperator(getBinOpPrecedence(Kind, GreaterThanIsOperator, true));
|
2014-11-08 13:07:16 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a binary expression that starts with \p LHS and has a
|
2012-06-17 12:36:28 +08:00
|
|
|
/// precedence of at least \p MinPrec.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
|
|
|
Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) {
|
2010-04-22 06:36:40 +08:00
|
|
|
prec::Level NextTokPrec = getBinOpPrecedence(Tok.getKind(),
|
|
|
|
GreaterThanIsOperator,
|
2013-01-02 19:42:31 +08:00
|
|
|
getLangOpts().CPlusPlus11);
|
2006-08-23 13:17:46 +08:00
|
|
|
SourceLocation ColonLoc;
|
|
|
|
|
2019-02-01 04:20:32 +08:00
|
|
|
auto SavedType = PreferredType;
|
2022-01-09 16:19:47 +08:00
|
|
|
while (true) {
|
2019-02-01 04:20:32 +08:00
|
|
|
// Every iteration may rely on a preferred type for the whole expression.
|
|
|
|
PreferredType = SavedType;
|
2006-08-12 16:13:25 +08:00
|
|
|
// If this token has a lower precedence than we are allowed to parse (e.g.
|
|
|
|
// because we are called recursively, or because the token is not a binop),
|
|
|
|
// then we are done!
|
2008-12-09 21:15:23 +08:00
|
|
|
if (NextTokPrec < MinPrec)
|
2012-08-24 05:35:17 +08:00
|
|
|
return LHS;
|
2006-08-12 16:13:25 +08:00
|
|
|
|
|
|
|
// Consume the operator, saving the operator token for error reporting.
|
2007-07-21 00:59:19 +08:00
|
|
|
Token OpToken = Tok;
|
2006-08-12 16:13:25 +08:00
|
|
|
ConsumeToken();
|
2009-02-07 08:15:38 +08:00
|
|
|
|
2016-02-03 23:17:14 +08:00
|
|
|
if (OpToken.is(tok::caretcaret)) {
|
|
|
|
return ExprError(Diag(Tok, diag::err_opencl_logical_exclusive_or));
|
|
|
|
}
|
2018-06-27 07:20:26 +08:00
|
|
|
|
|
|
|
// If we're potentially in a template-id, we may now be able to determine
|
|
|
|
// whether we're actually in one or not.
|
2018-06-27 09:32:04 +08:00
|
|
|
if (OpToken.isOneOf(tok::comma, tok::greater, tok::greatergreater,
|
|
|
|
tok::greatergreatergreater) &&
|
|
|
|
checkPotentialAngleBracketDelimiter(OpToken))
|
|
|
|
return ExprError();
|
2018-06-27 07:20:26 +08:00
|
|
|
|
2012-09-18 08:52:05 +08:00
|
|
|
// Bail out when encountering a comma followed by a token which can't
|
|
|
|
// possibly be the start of an expression. For instance:
|
|
|
|
// int f() { return 1, }
|
|
|
|
// We can't do this before consuming the comma, because
|
|
|
|
// isNotExpressionStart() looks at the token stream.
|
|
|
|
if (OpToken.is(tok::comma) && isNotExpressionStart()) {
|
2019-05-17 17:32:05 +08:00
|
|
|
PP.EnterToken(Tok, /*IsReinject*/true);
|
2012-09-18 08:52:05 +08:00
|
|
|
Tok = OpToken;
|
|
|
|
return LHS;
|
|
|
|
}
|
|
|
|
|
2014-11-08 13:07:16 +08:00
|
|
|
// If the next token is an ellipsis, then this is a fold-expression. Leave
|
|
|
|
// it alone so we can handle it in the paren expression.
|
|
|
|
if (isFoldOperator(NextTokPrec) && Tok.is(tok::ellipsis)) {
|
|
|
|
// FIXME: We can't check this via lookahead before we consume the token
|
|
|
|
// because that tickles a lexer bug.
|
2019-05-17 17:32:05 +08:00
|
|
|
PP.EnterToken(Tok, /*IsReinject*/true);
|
2014-11-08 13:07:16 +08:00
|
|
|
Tok = OpToken;
|
|
|
|
return LHS;
|
|
|
|
}
|
|
|
|
|
2018-08-22 00:47:04 +08:00
|
|
|
// In Objective-C++, alternative operator tokens can be used as keyword args
|
|
|
|
// in message expressions. Unconsume the token so that it can reinterpreted
|
|
|
|
// as an identifier in ParseObjCMessageExpressionBody. i.e., we support:
|
|
|
|
// [foo meth:0 and:0];
|
|
|
|
// [foo not_eq];
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC && getLangOpts().CPlusPlus &&
|
2018-08-22 00:47:04 +08:00
|
|
|
Tok.isOneOf(tok::colon, tok::r_square) &&
|
|
|
|
OpToken.getIdentifierInfo() != nullptr) {
|
2019-05-17 17:32:05 +08:00
|
|
|
PP.EnterToken(Tok, /*IsReinject*/true);
|
2018-08-22 00:47:04 +08:00
|
|
|
Tok = OpToken;
|
|
|
|
return LHS;
|
|
|
|
}
|
|
|
|
|
2006-08-13 01:13:08 +08:00
|
|
|
// Special case handling for the ternary operator.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult TernaryMiddle(true);
|
2006-08-13 01:13:08 +08:00
|
|
|
if (NextTokPrec == prec::Conditional) {
|
2018-05-25 06:02:52 +08:00
|
|
|
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
|
|
|
|
// Parse a braced-init-list here for error recovery purposes.
|
|
|
|
SourceLocation BraceLoc = Tok.getLocation();
|
|
|
|
TernaryMiddle = ParseBraceInitializer();
|
|
|
|
if (!TernaryMiddle.isInvalid()) {
|
|
|
|
Diag(BraceLoc, diag::err_init_list_bin_op)
|
|
|
|
<< /*RHS*/ 1 << PP.getSpelling(OpToken)
|
|
|
|
<< Actions.getExprRange(TernaryMiddle.get());
|
|
|
|
TernaryMiddle = ExprError();
|
|
|
|
}
|
|
|
|
} else if (Tok.isNot(tok::colon)) {
|
2009-12-10 10:02:58 +08:00
|
|
|
// Don't parse FOO:BAR as if it were a typo for FOO::BAR.
|
|
|
|
ColonProtectionRAIIObject X(*this);
|
|
|
|
|
2006-08-13 01:13:08 +08:00
|
|
|
// Handle this production specially:
|
|
|
|
// logical-OR-expression '?' expression ':' conditional-expression
|
|
|
|
// In particular, the RHS of the '?' is 'expression', not
|
|
|
|
// 'logical-OR-expression' as we might expect.
|
|
|
|
TernaryMiddle = ParseExpression();
|
|
|
|
} else {
|
|
|
|
// Special case handling of "X ? Y : Z" where Y is empty:
|
|
|
|
// logical-OR-expression '?' ':' conditional-expression [GNU]
|
2014-05-21 14:02:52 +08:00
|
|
|
TernaryMiddle = nullptr;
|
2006-08-13 01:13:08 +08:00
|
|
|
Diag(Tok, diag::ext_gnu_conditional_expr);
|
|
|
|
}
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2018-05-25 06:02:52 +08:00
|
|
|
if (TernaryMiddle.isInvalid()) {
|
|
|
|
Actions.CorrectDelayedTyposInExpr(LHS);
|
|
|
|
LHS = ExprError();
|
|
|
|
TernaryMiddle = nullptr;
|
|
|
|
}
|
|
|
|
|
2013-12-17 22:12:37 +08:00
|
|
|
if (!TryConsumeToken(tok::colon, ColonLoc)) {
|
2011-07-26 13:19:46 +08:00
|
|
|
// Otherwise, we're missing a ':'. Assume that this was a typo that
|
|
|
|
// the user forgot. If we're not in a macro expansion, we can suggest
|
|
|
|
// a fixit hint. If there were two spaces before the current token,
|
2010-05-25 06:31:37 +08:00
|
|
|
// suggest inserting the colon in between them, otherwise insert ": ".
|
|
|
|
SourceLocation FILoc = Tok.getLocation();
|
|
|
|
const char *FIText = ": ";
|
2011-06-25 01:28:29 +08:00
|
|
|
const SourceManager &SM = PP.getSourceManager();
|
2012-01-19 23:59:08 +08:00
|
|
|
if (FILoc.isFileID() || PP.isAtStartOfMacroExpansion(FILoc, &FILoc)) {
|
|
|
|
assert(FILoc.isFileID());
|
2010-05-25 06:31:37 +08:00
|
|
|
bool IsInvalid = false;
|
|
|
|
const char *SourcePtr =
|
2011-09-20 04:40:19 +08:00
|
|
|
SM.getCharacterData(FILoc.getLocWithOffset(-1), &IsInvalid);
|
2010-05-25 06:31:37 +08:00
|
|
|
if (!IsInvalid && *SourcePtr == ' ') {
|
|
|
|
SourcePtr =
|
2011-09-20 04:40:19 +08:00
|
|
|
SM.getCharacterData(FILoc.getLocWithOffset(-2), &IsInvalid);
|
2010-05-25 06:31:37 +08:00
|
|
|
if (!IsInvalid && *SourcePtr == ' ') {
|
2011-09-20 04:40:19 +08:00
|
|
|
FILoc = FILoc.getLocWithOffset(-1);
|
2010-05-25 06:31:37 +08:00
|
|
|
FIText = ":";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-31 07:29:50 +08:00
|
|
|
|
|
|
|
Diag(Tok, diag::err_expected)
|
|
|
|
<< tok::colon << FixItHint::CreateInsertion(FILoc, FIText);
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(OpToken, diag::note_matching) << tok::question;
|
2010-04-21 05:33:39 +08:00
|
|
|
ColonLoc = Tok.getLocation();
|
2006-08-13 01:13:08 +08:00
|
|
|
}
|
2006-08-12 16:13:25 +08:00
|
|
|
}
|
2017-04-21 06:23:07 +08:00
|
|
|
|
2019-02-01 04:20:32 +08:00
|
|
|
PreferredType.enterBinary(Actions, Tok.getLocation(), LHS.get(),
|
|
|
|
OpToken.getKind());
|
2006-08-13 01:13:08 +08:00
|
|
|
// Parse another leaf here for the RHS of the operator.
|
2009-04-17 01:51:27 +08:00
|
|
|
// ParseCastExpression works here because all RHS expressions in C have it
|
|
|
|
// as a prefix, at least. However, in C++, an assignment-expression could
|
|
|
|
// be a throw-expression, which is not a valid cast-expression.
|
|
|
|
// Therefore we need some special-casing here.
|
|
|
|
// Also note that the third operand of the conditional operator is
|
2012-02-27 07:40:27 +08:00
|
|
|
// an assignment-expression in C++, and in C++11, we can have a
|
2012-03-01 10:59:17 +08:00
|
|
|
// braced-init-list on the RHS of an assignment. For better diagnostics,
|
|
|
|
// parse as if we were allowed braced-init-lists everywhere, and check that
|
|
|
|
// they only appear on the RHS of assignments later.
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult RHS;
|
2012-03-01 15:10:06 +08:00
|
|
|
bool RHSIsInitList = false;
|
2013-01-02 19:42:31 +08:00
|
|
|
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
|
2012-02-27 07:40:27 +08:00
|
|
|
RHS = ParseBraceInitializer();
|
2012-03-01 15:10:06 +08:00
|
|
|
RHSIsInitList = true;
|
2012-03-11 15:00:24 +08:00
|
|
|
} else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional)
|
2009-04-17 01:51:27 +08:00
|
|
|
RHS = ParseAssignmentExpression();
|
2012-03-01 10:59:17 +08:00
|
|
|
else
|
2020-01-09 21:07:51 +08:00
|
|
|
RHS = ParseCastExpression(AnyCastExpr);
|
2006-08-12 16:13:25 +08:00
|
|
|
|
2014-11-21 06:06:40 +08:00
|
|
|
if (RHS.isInvalid()) {
|
2015-05-02 04:59:18 +08:00
|
|
|
// FIXME: Errors generated by the delayed typo correction should be
|
|
|
|
// printed before errors from parsing the RHS, not after.
|
2014-11-21 06:06:40 +08:00
|
|
|
Actions.CorrectDelayedTyposInExpr(LHS);
|
2015-05-02 04:59:18 +08:00
|
|
|
if (TernaryMiddle.isUsable())
|
|
|
|
TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle);
|
When we run into an error parsing or type-checking the left-hand side
of a binary expression, continue on and parse the right-hand side of
the binary expression anyway, but don't call the semantic actions to
type-check. Previously, we would see the error and then, effectively,
skip tokens until the end of the statement.
The result should be more useful recovery, both in the normal case
(we'll actually see errors beyond the first one in a statement), but
it also helps code completion do a much better job, because we do
"real" code completion on the right-hand side of an invalid binary
expression rather than completing with the recovery completion. For
example, given
x = p->y
if there is no variable named "x", we can still complete after the p->
as a member expression. Along the recovery path, we would have
completed after the "->" as if we were in an expression context, which
is mostly useless.
llvm-svn: 114225
2010-09-18 06:25:06 +08:00
|
|
|
LHS = ExprError();
|
2014-11-21 06:06:40 +08:00
|
|
|
}
|
|
|
|
|
2006-08-12 16:13:25 +08:00
|
|
|
// Remember the precedence of this operator and get the precedence of the
|
|
|
|
// operator immediately to the right of the RHS.
|
2010-04-22 06:36:40 +08:00
|
|
|
prec::Level ThisPrec = NextTokPrec;
|
2009-02-26 07:02:36 +08:00
|
|
|
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
|
2013-01-02 19:42:31 +08:00
|
|
|
getLangOpts().CPlusPlus11);
|
2006-08-13 01:18:19 +08:00
|
|
|
|
|
|
|
// Assignment and conditional expressions are right-associative.
|
2007-12-18 14:06:23 +08:00
|
|
|
bool isRightAssoc = ThisPrec == prec::Conditional ||
|
|
|
|
ThisPrec == prec::Assignment;
|
2006-08-12 16:13:25 +08:00
|
|
|
|
|
|
|
// Get the precedence of the operator to the right of the RHS. If it binds
|
|
|
|
// more tightly with RHS than we do, evaluate it completely first.
|
|
|
|
if (ThisPrec < NextTokPrec ||
|
|
|
|
(ThisPrec == NextTokPrec && isRightAssoc)) {
|
2012-03-01 15:10:06 +08:00
|
|
|
if (!RHS.isInvalid() && RHSIsInitList) {
|
|
|
|
Diag(Tok, diag::err_init_list_bin_op)
|
|
|
|
<< /*LHS*/0 << PP.getSpelling(Tok) << Actions.getExprRange(RHS.get());
|
|
|
|
RHS = ExprError();
|
2012-03-01 10:59:17 +08:00
|
|
|
}
|
2006-08-13 01:18:19 +08:00
|
|
|
// If this is left-associative, only parse things on the RHS that bind
|
|
|
|
// more tightly than the current operator. If it is left-associative, it
|
|
|
|
// is okay, to bind exactly as tightly. For example, compile A=B=C=D as
|
|
|
|
// A=(B=(C=D)), where each paren is a level of recursion here.
|
2008-11-26 06:21:31 +08:00
|
|
|
// The function takes ownership of the RHS.
|
2018-07-31 03:24:48 +08:00
|
|
|
RHS = ParseRHSOfBinaryExpression(RHS,
|
2010-04-22 06:36:40 +08:00
|
|
|
static_cast<prec::Level>(ThisPrec + !isRightAssoc));
|
2012-03-01 15:10:06 +08:00
|
|
|
RHSIsInitList = false;
|
When we run into an error parsing or type-checking the left-hand side
of a binary expression, continue on and parse the right-hand side of
the binary expression anyway, but don't call the semantic actions to
type-check. Previously, we would see the error and then, effectively,
skip tokens until the end of the statement.
The result should be more useful recovery, both in the normal case
(we'll actually see errors beyond the first one in a statement), but
it also helps code completion do a much better job, because we do
"real" code completion on the right-hand side of an invalid binary
expression rather than completing with the recovery completion. For
example, given
x = p->y
if there is no variable named "x", we can still complete after the p->
as a member expression. Along the recovery path, we would have
completed after the "->" as if we were in an expression context, which
is mostly useless.
llvm-svn: 114225
2010-09-18 06:25:06 +08:00
|
|
|
|
2014-11-21 06:06:40 +08:00
|
|
|
if (RHS.isInvalid()) {
|
2015-05-02 04:59:18 +08:00
|
|
|
// FIXME: Errors generated by the delayed typo correction should be
|
|
|
|
// printed before errors from ParseRHSOfBinaryExpression, not after.
|
2014-11-21 06:06:40 +08:00
|
|
|
Actions.CorrectDelayedTyposInExpr(LHS);
|
2015-05-02 04:59:18 +08:00
|
|
|
if (TernaryMiddle.isUsable())
|
|
|
|
TernaryMiddle = Actions.CorrectDelayedTyposInExpr(TernaryMiddle);
|
When we run into an error parsing or type-checking the left-hand side
of a binary expression, continue on and parse the right-hand side of
the binary expression anyway, but don't call the semantic actions to
type-check. Previously, we would see the error and then, effectively,
skip tokens until the end of the statement.
The result should be more useful recovery, both in the normal case
(we'll actually see errors beyond the first one in a statement), but
it also helps code completion do a much better job, because we do
"real" code completion on the right-hand side of an invalid binary
expression rather than completing with the recovery completion. For
example, given
x = p->y
if there is no variable named "x", we can still complete after the p->
as a member expression. Along the recovery path, we would have
completed after the "->" as if we were in an expression context, which
is mostly useless.
llvm-svn: 114225
2010-09-18 06:25:06 +08:00
|
|
|
LHS = ExprError();
|
2014-11-21 06:06:40 +08:00
|
|
|
}
|
2006-08-12 16:13:25 +08:00
|
|
|
|
2009-02-26 07:02:36 +08:00
|
|
|
NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator,
|
2013-01-02 19:42:31 +08:00
|
|
|
getLangOpts().CPlusPlus11);
|
2006-08-12 16:13:25 +08:00
|
|
|
}
|
2008-11-26 06:21:31 +08:00
|
|
|
|
2012-03-01 15:10:06 +08:00
|
|
|
if (!RHS.isInvalid() && RHSIsInitList) {
|
2012-03-01 10:59:17 +08:00
|
|
|
if (ThisPrec == prec::Assignment) {
|
|
|
|
Diag(OpToken, diag::warn_cxx98_compat_generalized_initializer_lists)
|
2012-03-01 15:10:06 +08:00
|
|
|
<< Actions.getExprRange(RHS.get());
|
2018-05-25 06:02:52 +08:00
|
|
|
} else if (ColonLoc.isValid()) {
|
|
|
|
Diag(ColonLoc, diag::err_init_list_bin_op)
|
|
|
|
<< /*RHS*/1 << ":"
|
|
|
|
<< Actions.getExprRange(RHS.get());
|
|
|
|
LHS = ExprError();
|
2012-03-01 10:59:17 +08:00
|
|
|
} else {
|
|
|
|
Diag(OpToken, diag::err_init_list_bin_op)
|
2012-03-01 15:10:06 +08:00
|
|
|
<< /*RHS*/1 << PP.getSpelling(OpToken)
|
|
|
|
<< Actions.getExprRange(RHS.get());
|
2012-03-01 10:59:17 +08:00
|
|
|
LHS = ExprError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-18 14:37:44 +08:00
|
|
|
ExprResult OrigLHS = LHS;
|
2008-12-09 21:15:23 +08:00
|
|
|
if (!LHS.isInvalid()) {
|
2007-08-31 13:01:50 +08:00
|
|
|
// Combine the LHS and RHS into the LHS (e.g. build AST).
|
Introduce code modification hints into the diagnostics system. When we
know how to recover from an error, we can attach a hint to the
diagnostic that states how to modify the code, which can be one of:
- Insert some new code (a text string) at a particular source
location
- Remove the code within a given range
- Replace the code within a given range with some new code (a text
string)
Right now, we use these hints to annotate diagnostic information. For
example, if one uses the '>>' in a template argument in C++98, as in
this code:
template<int I> class B { };
B<1000 >> 2> *b1;
we'll warn that the behavior will change in C++0x. The fix is to
insert parenthese, so we use code insertion annotations to illustrate
where the parentheses go:
test.cpp:10:10: warning: use of right-shift operator ('>>') in template
argument will require parentheses in C++0x
B<1000 >> 2> *b1;
^
( )
Use of these annotations is partially implemented for HTML
diagnostics, but it's not (yet) producing valid HTML, which may be
related to PR2386, so it has been #if 0'd out.
In this future, we could consider hooking this mechanism up to the
rewriter to actually try to fix these problems during compilation (or,
after a compilation whose only errors have fixes). For now, however, I
suggest that we use these code modification hints whenever we can, so
that we get better diagnostics now and will have better coverage when
we find better ways to use this information.
This also fixes PR3410 by placing the complaint about missing tokens
just after the previous token (rather than at the location of the next
token).
llvm-svn: 65570
2009-02-27 05:00:50 +08:00
|
|
|
if (TernaryMiddle.isInvalid()) {
|
|
|
|
// If we're using '>>' as an operator within a template
|
|
|
|
// argument list (in C++98), suggest the addition of
|
|
|
|
// parentheses so that the code remains well-formed in C++0x.
|
|
|
|
if (!GreaterThanIsOperator && OpToken.is(tok::greatergreater))
|
|
|
|
SuggestParentheses(OpToken.getLocation(),
|
2013-07-15 01:02:30 +08:00
|
|
|
diag::warn_cxx11_right_shift_in_template_arg,
|
Introduce code modification hints into the diagnostics system. When we
know how to recover from an error, we can attach a hint to the
diagnostic that states how to modify the code, which can be one of:
- Insert some new code (a text string) at a particular source
location
- Remove the code within a given range
- Replace the code within a given range with some new code (a text
string)
Right now, we use these hints to annotate diagnostic information. For
example, if one uses the '>>' in a template argument in C++98, as in
this code:
template<int I> class B { };
B<1000 >> 2> *b1;
we'll warn that the behavior will change in C++0x. The fix is to
insert parenthese, so we use code insertion annotations to illustrate
where the parentheses go:
test.cpp:10:10: warning: use of right-shift operator ('>>') in template
argument will require parentheses in C++0x
B<1000 >> 2> *b1;
^
( )
Use of these annotations is partially implemented for HTML
diagnostics, but it's not (yet) producing valid HTML, which may be
related to PR2386, so it has been #if 0'd out.
In this future, we could consider hooking this mechanism up to the
rewriter to actually try to fix these problems during compilation (or,
after a compilation whose only errors have fixes). For now, however, I
suggest that we use these code modification hints whenever we can, so
that we get better diagnostics now and will have better coverage when
we find better ways to use this information.
This also fixes PR3410 by placing the complaint about missing tokens
just after the previous token (rather than at the location of the next
token).
llvm-svn: 65570
2009-02-27 05:00:50 +08:00
|
|
|
SourceRange(Actions.getExprRange(LHS.get()).getBegin(),
|
|
|
|
Actions.getExprRange(RHS.get()).getEnd()));
|
|
|
|
|
[AST] Add RecoveryExpr to retain expressions on semantic errors
Normally clang avoids creating expressions when it encounters semantic
errors, even if the parser knows which expression to produce.
This works well for the compiler. However, this is not ideal for
source-level tools that have to deal with broken code, e.g. clangd is
not able to provide navigation features even for names that compiler
knows how to resolve.
The new RecoveryExpr aims to capture the minimal set of information
useful for the tools that need to deal with incorrect code:
source range of the expression being dropped,
subexpressions of the expression.
We aim to make constructing RecoveryExprs as simple as possible to
ensure writing code to avoid dropping expressions is easy.
Producing RecoveryExprs can result in new code paths being taken in the
frontend. In particular, clang can produce some new diagnostics now and
we aim to suppress bogus ones based on Expr::containsErrors.
We deliberately produce RecoveryExprs only in the parser for now to
minimize the code affected by this patch. Producing RecoveryExprs in
Sema potentially allows to preserve more information (e.g. type of an
expression), but also results in more code being affected. E.g.
SFINAE checks will have to take presence of RecoveryExprs into account.
Initial implementation only works in C++ mode, as it relies on compiler
postponing diagnostics on dependent expressions. C and ObjC often do not
do this, so they require more work to make sure we do not produce too
many bogus diagnostics on the new expressions.
See documentation of RecoveryExpr for more details.
original patch from Ilya
This change is based on https://reviews.llvm.org/D61722
Reviewers: sammccall, rsmith
Reviewed By: sammccall, rsmith
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 23:30:40 +08:00
|
|
|
ExprResult BinOp =
|
|
|
|
Actions.ActOnBinOp(getCurScope(), OpToken.getLocation(),
|
|
|
|
OpToken.getKind(), LHS.get(), RHS.get());
|
|
|
|
if (BinOp.isInvalid())
|
|
|
|
BinOp = Actions.CreateRecoveryExpr(LHS.get()->getBeginLoc(),
|
|
|
|
RHS.get()->getEndLoc(),
|
|
|
|
{LHS.get(), RHS.get()});
|
|
|
|
|
|
|
|
LHS = BinOp;
|
2016-02-18 14:37:44 +08:00
|
|
|
} else {
|
[AST] Add RecoveryExpr to retain expressions on semantic errors
Normally clang avoids creating expressions when it encounters semantic
errors, even if the parser knows which expression to produce.
This works well for the compiler. However, this is not ideal for
source-level tools that have to deal with broken code, e.g. clangd is
not able to provide navigation features even for names that compiler
knows how to resolve.
The new RecoveryExpr aims to capture the minimal set of information
useful for the tools that need to deal with incorrect code:
source range of the expression being dropped,
subexpressions of the expression.
We aim to make constructing RecoveryExprs as simple as possible to
ensure writing code to avoid dropping expressions is easy.
Producing RecoveryExprs can result in new code paths being taken in the
frontend. In particular, clang can produce some new diagnostics now and
we aim to suppress bogus ones based on Expr::containsErrors.
We deliberately produce RecoveryExprs only in the parser for now to
minimize the code affected by this patch. Producing RecoveryExprs in
Sema potentially allows to preserve more information (e.g. type of an
expression), but also results in more code being affected. E.g.
SFINAE checks will have to take presence of RecoveryExprs into account.
Initial implementation only works in C++ mode, as it relies on compiler
postponing diagnostics on dependent expressions. C and ObjC often do not
do this, so they require more work to make sure we do not produce too
many bogus diagnostics on the new expressions.
See documentation of RecoveryExpr for more details.
original patch from Ilya
This change is based on https://reviews.llvm.org/D61722
Reviewers: sammccall, rsmith
Reviewed By: sammccall, rsmith
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 23:30:40 +08:00
|
|
|
ExprResult CondOp = Actions.ActOnConditionalOp(
|
|
|
|
OpToken.getLocation(), ColonLoc, LHS.get(), TernaryMiddle.get(),
|
|
|
|
RHS.get());
|
|
|
|
if (CondOp.isInvalid()) {
|
|
|
|
std::vector<clang::Expr *> Args;
|
|
|
|
// TernaryMiddle can be null for the GNU conditional expr extension.
|
|
|
|
if (TernaryMiddle.get())
|
|
|
|
Args = {LHS.get(), TernaryMiddle.get(), RHS.get()};
|
|
|
|
else
|
|
|
|
Args = {LHS.get(), RHS.get()};
|
|
|
|
CondOp = Actions.CreateRecoveryExpr(LHS.get()->getBeginLoc(),
|
|
|
|
RHS.get()->getEndLoc(), Args);
|
|
|
|
}
|
|
|
|
|
|
|
|
LHS = CondOp;
|
2016-02-18 14:37:44 +08:00
|
|
|
}
|
2016-07-29 08:55:40 +08:00
|
|
|
// In this case, ActOnBinOp or ActOnConditionalOp performed the
|
|
|
|
// CorrectDelayedTyposInExpr check.
|
|
|
|
if (!getLangOpts().CPlusPlus)
|
|
|
|
continue;
|
2016-02-18 14:37:44 +08:00
|
|
|
}
|
2017-04-21 06:23:07 +08:00
|
|
|
|
2016-02-18 14:37:44 +08:00
|
|
|
// Ensure potential typos aren't left undiagnosed.
|
|
|
|
if (LHS.isInvalid()) {
|
|
|
|
Actions.CorrectDelayedTyposInExpr(OrigLHS);
|
2016-02-18 01:19:00 +08:00
|
|
|
Actions.CorrectDelayedTyposInExpr(TernaryMiddle);
|
2014-11-21 06:06:40 +08:00
|
|
|
Actions.CorrectDelayedTyposInExpr(RHS);
|
2016-02-18 01:19:00 +08:00
|
|
|
}
|
2006-08-12 16:13:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-09 21:07:51 +08:00
|
|
|
/// Parse a cast-expression, unary-expression or primary-expression, based
|
|
|
|
/// on \p ExprType.
|
2012-06-17 12:36:28 +08:00
|
|
|
///
|
|
|
|
/// \p isAddressOfOperand exists because an id-expression that is the
|
|
|
|
/// operand of address-of gets special treatment due to member pointers.
|
2006-08-11 10:02:23 +08:00
|
|
|
///
|
2020-01-09 21:07:51 +08:00
|
|
|
ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
|
2011-04-24 13:37:28 +08:00
|
|
|
bool isAddressOfOperand,
|
2017-03-29 20:09:39 +08:00
|
|
|
TypeCastState isTypeCast,
|
2020-01-09 21:07:51 +08:00
|
|
|
bool isVectorLiteral,
|
|
|
|
bool *NotPrimaryExpression) {
|
2009-05-22 18:24:42 +08:00
|
|
|
bool NotCastExpr;
|
2020-01-09 21:07:51 +08:00
|
|
|
ExprResult Res = ParseCastExpression(ParseKind,
|
When we run into an error parsing or type-checking the left-hand side
of a binary expression, continue on and parse the right-hand side of
the binary expression anyway, but don't call the semantic actions to
type-check. Previously, we would see the error and then, effectively,
skip tokens until the end of the statement.
The result should be more useful recovery, both in the normal case
(we'll actually see errors beyond the first one in a statement), but
it also helps code completion do a much better job, because we do
"real" code completion on the right-hand side of an invalid binary
expression rather than completing with the recovery completion. For
example, given
x = p->y
if there is no variable named "x", we can still complete after the p->
as a member expression. Along the recovery path, we would have
completed after the "->" as if we were in an expression context, which
is mostly useless.
llvm-svn: 114225
2010-09-18 06:25:06 +08:00
|
|
|
isAddressOfOperand,
|
|
|
|
NotCastExpr,
|
2017-03-29 20:09:39 +08:00
|
|
|
isTypeCast,
|
2020-01-09 21:07:51 +08:00
|
|
|
isVectorLiteral,
|
|
|
|
NotPrimaryExpression);
|
2009-05-22 18:24:42 +08:00
|
|
|
if (NotCastExpr)
|
|
|
|
Diag(Tok, diag::err_expected_expression);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2009-05-22 18:24:42 +08:00
|
|
|
}
|
|
|
|
|
2012-01-26 04:49:08 +08:00
|
|
|
namespace {
|
2019-03-26 01:08:51 +08:00
|
|
|
class CastExpressionIdValidator final : public CorrectionCandidateCallback {
|
2012-01-26 04:49:08 +08:00
|
|
|
public:
|
2015-01-17 06:11:04 +08:00
|
|
|
CastExpressionIdValidator(Token Next, bool AllowTypes, bool AllowNonTypes)
|
|
|
|
: NextToken(Next), AllowNonTypes(AllowNonTypes) {
|
2014-11-21 06:06:40 +08:00
|
|
|
WantTypeSpecifiers = WantFunctionLikeCasts = AllowTypes;
|
2012-01-26 04:49:08 +08:00
|
|
|
}
|
|
|
|
|
2014-03-12 13:09:18 +08:00
|
|
|
bool ValidateCandidate(const TypoCorrection &candidate) override {
|
2012-01-26 04:49:08 +08:00
|
|
|
NamedDecl *ND = candidate.getCorrectionDecl();
|
|
|
|
if (!ND)
|
|
|
|
return candidate.isKeyword();
|
|
|
|
|
|
|
|
if (isa<TypeDecl>(ND))
|
|
|
|
return WantTypeSpecifiers;
|
2015-01-17 06:11:04 +08:00
|
|
|
|
|
|
|
if (!AllowNonTypes || !CorrectionCandidateCallback::ValidateCandidate(candidate))
|
|
|
|
return false;
|
|
|
|
|
2015-06-18 18:59:26 +08:00
|
|
|
if (!NextToken.isOneOf(tok::equal, tok::arrow, tok::period))
|
2015-01-17 06:11:04 +08:00
|
|
|
return true;
|
|
|
|
|
|
|
|
for (auto *C : candidate) {
|
|
|
|
NamedDecl *ND = C->getUnderlyingDecl();
|
|
|
|
if (isa<ValueDecl>(ND) && !isa<FunctionDecl>(ND))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2012-01-26 04:49:08 +08:00
|
|
|
}
|
|
|
|
|
2019-03-26 01:08:51 +08:00
|
|
|
std::unique_ptr<CorrectionCandidateCallback> clone() override {
|
2019-08-15 07:04:18 +08:00
|
|
|
return std::make_unique<CastExpressionIdValidator>(*this);
|
2019-03-26 01:08:51 +08:00
|
|
|
}
|
|
|
|
|
2012-01-26 04:49:08 +08:00
|
|
|
private:
|
2015-01-17 06:11:04 +08:00
|
|
|
Token NextToken;
|
2012-01-26 04:49:08 +08:00
|
|
|
bool AllowNonTypes;
|
|
|
|
};
|
2015-06-23 07:07:51 +08:00
|
|
|
}
|
2012-01-26 04:49:08 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a cast-expression, or, if \pisUnaryExpression is true, parse
|
2012-06-17 12:36:28 +08:00
|
|
|
/// a unary-expression.
|
2009-05-22 18:24:42 +08:00
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \p isAddressOfOperand exists because an id-expression that is the operand
|
|
|
|
/// of address-of gets special treatment due to member pointers. NotCastExpr
|
|
|
|
/// is set to true if the token is not the start of a cast-expression, and no
|
2016-02-04 02:48:43 +08:00
|
|
|
/// diagnostic is emitted in this case and no tokens are consumed.
|
2012-06-17 12:36:28 +08:00
|
|
|
///
|
|
|
|
/// \verbatim
|
2006-08-11 07:14:52 +08:00
|
|
|
/// cast-expression: [C99 6.5.4]
|
|
|
|
/// unary-expression
|
|
|
|
/// '(' type-name ')' cast-expression
|
2006-08-11 10:13:20 +08:00
|
|
|
///
|
2006-08-11 06:57:16 +08:00
|
|
|
/// unary-expression: [C99 6.5.3]
|
|
|
|
/// postfix-expression
|
|
|
|
/// '++' unary-expression
|
|
|
|
/// '--' unary-expression
|
2015-10-22 12:46:14 +08:00
|
|
|
/// [Coro] 'co_await' cast-expression
|
2006-08-11 06:57:16 +08:00
|
|
|
/// unary-operator cast-expression
|
|
|
|
/// 'sizeof' unary-expression
|
|
|
|
/// 'sizeof' '(' type-name ')'
|
2012-03-06 11:21:47 +08:00
|
|
|
/// [C++11] 'sizeof' '...' '(' identifier ')'
|
2006-08-11 06:57:16 +08:00
|
|
|
/// [GNU] '__alignof' unary-expression
|
|
|
|
/// [GNU] '__alignof' '(' type-name ')'
|
2012-07-01 05:33:57 +08:00
|
|
|
/// [C11] '_Alignof' '(' type-name ')'
|
2012-03-06 11:21:47 +08:00
|
|
|
/// [C++11] 'alignof' '(' type-id ')'
|
2006-08-11 06:57:16 +08:00
|
|
|
/// [GNU] '&&' identifier
|
2012-03-06 11:21:47 +08:00
|
|
|
/// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7]
|
2008-11-22 03:14:01 +08:00
|
|
|
/// [C++] new-expression
|
|
|
|
/// [C++] delete-expression
|
2006-08-11 10:13:20 +08:00
|
|
|
///
|
2006-08-11 06:57:16 +08:00
|
|
|
/// unary-operator: one of
|
|
|
|
/// '&' '*' '+' '-' '~' '!'
|
|
|
|
/// [GNU] '__extension__' '__real' '__imag'
|
|
|
|
///
|
2006-08-11 04:56:00 +08:00
|
|
|
/// primary-expression: [C99 6.5.1]
|
2008-11-07 06:13:31 +08:00
|
|
|
/// [C99] identifier
|
2008-11-11 19:37:55 +08:00
|
|
|
/// [C++] id-expression
|
2006-08-11 03:06:03 +08:00
|
|
|
/// constant
|
|
|
|
/// string-literal
|
2007-02-13 09:51:42 +08:00
|
|
|
/// [C++] boolean-literal [C++ 2.13.5]
|
2012-03-06 11:21:47 +08:00
|
|
|
/// [C++11] 'nullptr' [C++11 2.14.7]
|
|
|
|
/// [C++11] user-defined-literal
|
2006-08-11 03:06:03 +08:00
|
|
|
/// '(' expression ')'
|
2011-12-24 01:00:35 +08:00
|
|
|
/// [C11] generic-selection
|
2020-01-18 15:11:43 +08:00
|
|
|
/// [C++2a] requires-expression
|
2006-08-11 04:56:00 +08:00
|
|
|
/// '__func__' [C99 6.4.2.2]
|
|
|
|
/// [GNU] '__FUNCTION__'
|
2013-11-07 07:31:56 +08:00
|
|
|
/// [MS] '__FUNCDNAME__'
|
|
|
|
/// [MS] 'L__FUNCTION__'
|
2018-07-27 07:18:44 +08:00
|
|
|
/// [MS] '__FUNCSIG__'
|
|
|
|
/// [MS] 'L__FUNCSIG__'
|
2006-08-11 04:56:00 +08:00
|
|
|
/// [GNU] '__PRETTY_FUNCTION__'
|
|
|
|
/// [GNU] '(' compound-statement ')'
|
|
|
|
/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
|
|
|
|
/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
|
|
|
|
/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
|
|
|
|
/// assign-expr ')'
|
Implement __builtin_LINE() et. al. to support source location capture.
Summary:
This patch implements the source location builtins `__builtin_LINE(), `__builtin_FUNCTION()`, `__builtin_FILE()` and `__builtin_COLUMN()`. These builtins are needed to implement [`std::experimental::source_location`](https://rawgit.com/cplusplus/fundamentals-ts/v2/main.html#reflection.src_loc.creation).
With the exception of `__builtin_COLUMN`, GCC also implements these builtins, and Clangs behavior is intended to match as closely as possible.
Reviewers: rsmith, joerg, aaron.ballman, bogner, majnemer, shafik, martong
Reviewed By: rsmith
Subscribers: rnkovacs, loskutov, riccibruno, mgorny, kunitoki, alexr, majnemer, hfinkel, cfe-commits
Differential Revision: https://reviews.llvm.org/D37035
llvm-svn: 360937
2019-05-17 05:04:15 +08:00
|
|
|
/// [GNU] '__builtin_FILE' '(' ')'
|
|
|
|
/// [GNU] '__builtin_FUNCTION' '(' ')'
|
|
|
|
/// [GNU] '__builtin_LINE' '(' ')'
|
|
|
|
/// [CLANG] '__builtin_COLUMN' '(' ')'
|
2006-08-11 04:56:00 +08:00
|
|
|
/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
|
2008-11-29 12:51:27 +08:00
|
|
|
/// [GNU] '__null'
|
2009-09-09 23:08:12 +08:00
|
|
|
/// [OBJC] '[' objc-message-expr ']'
|
2012-06-15 14:52:33 +08:00
|
|
|
/// [OBJC] '\@selector' '(' objc-selector-arg ')'
|
|
|
|
/// [OBJC] '\@protocol' '(' identifier ')'
|
|
|
|
/// [OBJC] '\@encode' '(' type-name ')'
|
2007-09-06 03:52:07 +08:00
|
|
|
/// [OBJC] objc-string-literal
|
2008-08-22 23:38:55 +08:00
|
|
|
/// [C++] simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
|
2012-03-06 11:21:47 +08:00
|
|
|
/// [C++11] simple-type-specifier braced-init-list [C++11 5.2.3]
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
/// [C++] typename-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
|
2012-03-06 11:21:47 +08:00
|
|
|
/// [C++11] typename-specifier braced-init-list [C++11 5.2.3]
|
2007-06-30 02:21:34 +08:00
|
|
|
/// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
|
|
|
/// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
|
|
|
/// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
|
|
|
/// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1]
|
2008-11-11 19:37:55 +08:00
|
|
|
/// [C++] 'typeid' '(' expression ')' [C++ 5.2p1]
|
|
|
|
/// [C++] 'typeid' '(' type-id ')' [C++ 5.2p1]
|
2008-07-16 15:23:27 +08:00
|
|
|
/// [C++] 'this' [C++ 9.3.2]
|
2009-01-06 04:52:13 +08:00
|
|
|
/// [G++] unary-type-trait '(' type-id ')'
|
|
|
|
/// [G++] binary-type-trait '(' type-id ',' type-id ')' [TODO]
|
2011-04-28 08:16:57 +08:00
|
|
|
/// [EMBT] array-type-trait '(' type-id ',' integer ')'
|
2008-08-29 03:20:44 +08:00
|
|
|
/// [clang] '^' block-literal
|
2006-08-11 04:56:00 +08:00
|
|
|
///
|
|
|
|
/// constant: [C99 6.4.4]
|
|
|
|
/// integer-constant
|
|
|
|
/// floating-constant
|
|
|
|
/// enumeration-constant -> identifier
|
|
|
|
/// character-constant
|
|
|
|
///
|
2008-11-07 06:13:31 +08:00
|
|
|
/// id-expression: [C++ 5.1]
|
|
|
|
/// unqualified-id
|
2018-07-31 03:24:48 +08:00
|
|
|
/// qualified-id
|
2008-11-07 06:13:31 +08:00
|
|
|
///
|
|
|
|
/// unqualified-id: [C++ 5.1]
|
|
|
|
/// identifier
|
|
|
|
/// operator-function-id
|
Rework the Parser-Sema interaction for Objective-C message
sends. Major changes include:
- Expanded the interface from two actions (ActOnInstanceMessage,
ActOnClassMessage), where ActOnClassMessage also handled sends to
"super" by checking whether the identifier was "super", to three
actions (ActOnInstanceMessage, ActOnClassMessage,
ActOnSuperMessage). Code completion has the same changes.
- The parser now resolves the type to which we are sending a class
message, so ActOnClassMessage now accepts a TypeTy* (rather than
an IdentifierInfo *). This opens the door to more interesting
types (for Objective-C++ support).
- Split ActOnInstanceMessage and ActOnClassMessage into parser
action functions (with their original names) and semantic
functions (BuildInstanceMessage and BuildClassMessage,
respectively). At present, this split is onyl used by
ActOnSuperMessage, which decides which kind of super message it
has and forwards to the appropriate Build*Message. In the future,
Build*Message will be used by template instantiation.
- Use getObjCMessageKind() within the disambiguation of Objective-C
message sends vs. array designators.
Two notes about substandard bits in this patch:
- There is some redundancy in the code in ParseObjCMessageExpr and
ParseInitializerWithPotentialDesignator; this will be addressed
shortly by centralizing the mapping from identifiers to type names
for the message receiver.
- There is some #if 0'd code that won't likely ever be used---it
handles the use of 'super' in methods whose class does not have a
superclass---but could be used to model GCC's behavior more
closely. This code will die in my next check-in, but I want it in
Subversion.
llvm-svn: 102021
2010-04-22 03:57:20 +08:00
|
|
|
/// conversion-function-id
|
2018-07-31 03:24:48 +08:00
|
|
|
/// '~' class-name
|
|
|
|
/// template-id
|
2008-11-09 00:45:02 +08:00
|
|
|
///
|
2008-11-22 03:14:01 +08:00
|
|
|
/// new-expression: [C++ 5.3.4]
|
|
|
|
/// '::'[opt] 'new' new-placement[opt] new-type-id
|
|
|
|
/// new-initializer[opt]
|
|
|
|
/// '::'[opt] 'new' new-placement[opt] '(' type-id ')'
|
|
|
|
/// new-initializer[opt]
|
|
|
|
///
|
|
|
|
/// delete-expression: [C++ 5.3.5]
|
|
|
|
/// '::'[opt] 'delete' cast-expression
|
|
|
|
/// '::'[opt] 'delete' '[' ']' cast-expression
|
|
|
|
///
|
2011-04-28 07:09:49 +08:00
|
|
|
/// [GNU/Embarcadero] unary-type-trait:
|
|
|
|
/// '__is_arithmetic'
|
|
|
|
/// '__is_floating_point'
|
|
|
|
/// '__is_integral'
|
|
|
|
/// '__is_lvalue_expr'
|
|
|
|
/// '__is_rvalue_expr'
|
|
|
|
/// '__is_complete_type'
|
|
|
|
/// '__is_void'
|
|
|
|
/// '__is_array'
|
|
|
|
/// '__is_function'
|
|
|
|
/// '__is_reference'
|
|
|
|
/// '__is_lvalue_reference'
|
|
|
|
/// '__is_rvalue_reference'
|
|
|
|
/// '__is_fundamental'
|
|
|
|
/// '__is_object'
|
|
|
|
/// '__is_scalar'
|
|
|
|
/// '__is_compound'
|
|
|
|
/// '__is_pointer'
|
|
|
|
/// '__is_member_object_pointer'
|
|
|
|
/// '__is_member_function_pointer'
|
|
|
|
/// '__is_member_pointer'
|
|
|
|
/// '__is_const'
|
|
|
|
/// '__is_volatile'
|
|
|
|
/// '__is_trivial'
|
|
|
|
/// '__is_standard_layout'
|
|
|
|
/// '__is_signed'
|
|
|
|
/// '__is_unsigned'
|
|
|
|
///
|
2009-01-06 04:52:13 +08:00
|
|
|
/// [GNU] unary-type-trait:
|
2010-08-31 12:59:00 +08:00
|
|
|
/// '__has_nothrow_assign'
|
|
|
|
/// '__has_nothrow_copy'
|
|
|
|
/// '__has_nothrow_constructor'
|
2009-01-06 04:52:13 +08:00
|
|
|
/// '__has_trivial_assign' [TODO]
|
|
|
|
/// '__has_trivial_copy' [TODO]
|
2009-04-16 08:08:20 +08:00
|
|
|
/// '__has_trivial_constructor'
|
2009-04-17 10:34:54 +08:00
|
|
|
/// '__has_trivial_destructor'
|
2010-09-03 07:19:42 +08:00
|
|
|
/// '__has_virtual_destructor'
|
2009-01-06 04:52:13 +08:00
|
|
|
/// '__is_abstract' [TODO]
|
|
|
|
/// '__is_class'
|
|
|
|
/// '__is_empty' [TODO]
|
|
|
|
/// '__is_enum'
|
2011-12-04 02:14:24 +08:00
|
|
|
/// '__is_final'
|
2009-01-06 04:52:13 +08:00
|
|
|
/// '__is_pod'
|
|
|
|
/// '__is_polymorphic'
|
2013-10-18 08:33:31 +08:00
|
|
|
/// '__is_sealed' [MS]
|
2011-04-23 18:47:28 +08:00
|
|
|
/// '__is_trivial'
|
2009-01-06 04:52:13 +08:00
|
|
|
/// '__is_union'
|
2017-10-25 05:31:50 +08:00
|
|
|
/// '__has_unique_object_representations'
|
2009-01-06 04:52:13 +08:00
|
|
|
///
|
2011-05-13 08:31:07 +08:00
|
|
|
/// [Clang] unary-type-trait:
|
2017-04-13 06:12:15 +08:00
|
|
|
/// '__is_aggregate'
|
2011-05-13 08:31:07 +08:00
|
|
|
/// '__trivially_copyable'
|
|
|
|
///
|
2011-01-28 04:28:01 +08:00
|
|
|
/// binary-type-trait:
|
2018-07-31 03:24:48 +08:00
|
|
|
/// [GNU] '__is_base_of'
|
2011-01-28 04:28:01 +08:00
|
|
|
/// [MS] '__is_convertible_to'
|
2011-04-28 07:09:49 +08:00
|
|
|
/// '__is_convertible'
|
|
|
|
/// '__is_same'
|
2009-01-06 04:52:13 +08:00
|
|
|
///
|
2011-04-28 08:16:57 +08:00
|
|
|
/// [Embarcadero] array-type-trait:
|
|
|
|
/// '__array_rank'
|
|
|
|
/// '__array_extent'
|
|
|
|
///
|
2011-04-25 14:54:41 +08:00
|
|
|
/// [Embarcadero] expression-trait:
|
|
|
|
/// '__is_lvalue_expr'
|
|
|
|
/// '__is_rvalue_expr'
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2011-04-25 14:54:41 +08:00
|
|
|
///
|
2020-01-09 21:07:51 +08:00
|
|
|
ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
|
2010-09-11 04:55:37 +08:00
|
|
|
bool isAddressOfOperand,
|
|
|
|
bool &NotCastExpr,
|
2017-03-29 20:09:39 +08:00
|
|
|
TypeCastState isTypeCast,
|
2020-01-09 21:07:51 +08:00
|
|
|
bool isVectorLiteral,
|
|
|
|
bool *NotPrimaryExpression) {
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Res;
|
2006-10-25 11:38:23 +08:00
|
|
|
tok::TokenKind SavedKind = Tok.getKind();
|
2019-02-01 04:20:32 +08:00
|
|
|
auto SavedType = PreferredType;
|
2009-05-22 18:24:42 +08:00
|
|
|
NotCastExpr = false;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2020-06-30 05:12:14 +08:00
|
|
|
// Are postfix-expression suffix operators permitted after this
|
|
|
|
// cast-expression? If not, and we find some, we'll parse them anyway and
|
|
|
|
// diagnose them.
|
|
|
|
bool AllowSuffix = true;
|
|
|
|
|
2006-08-11 10:13:20 +08:00
|
|
|
// This handles all of cast-expression, unary-expression, postfix-expression,
|
|
|
|
// and primary-expression. We handle them together like this for efficiency
|
|
|
|
// and to simplify handling of an expression starting with a '(' token: which
|
|
|
|
// may be one of a parenthesized expression, cast-expression, compound literal
|
|
|
|
// expression, or statement expression.
|
|
|
|
//
|
|
|
|
// If the parsed tokens consist of a primary-expression, the cases below
|
2010-08-24 07:25:46 +08:00
|
|
|
// break out of the switch; at the end we call ParsePostfixExpressionSuffix
|
|
|
|
// to handle the postfix expression suffixes. Cases that cannot be followed
|
2020-06-30 05:12:14 +08:00
|
|
|
// by postfix exprs should set AllowSuffix to false.
|
2006-10-25 11:49:28 +08:00
|
|
|
switch (SavedKind) {
|
2006-08-24 14:37:51 +08:00
|
|
|
case tok::l_paren: {
|
2020-01-09 21:07:51 +08:00
|
|
|
// If this expression is limited to being a unary-expression, the paren can
|
2006-08-11 10:13:20 +08:00
|
|
|
// not start a cast expression.
|
2020-01-09 21:07:51 +08:00
|
|
|
ParenParseOption ParenExprType;
|
|
|
|
switch (ParseKind) {
|
|
|
|
case CastParseKind::UnaryExprOnly:
|
|
|
|
if (!getLangOpts().CPlusPlus)
|
|
|
|
ParenExprType = CompoundLiteral;
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
case CastParseKind::AnyCastExpr:
|
|
|
|
ParenExprType = ParenParseOption::CastExpr;
|
|
|
|
break;
|
|
|
|
case CastParseKind::PrimaryExprOnly:
|
|
|
|
ParenExprType = FoldExpr;
|
|
|
|
break;
|
|
|
|
}
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType CastTy;
|
2006-08-24 14:37:51 +08:00
|
|
|
SourceLocation RParenLoc;
|
2014-05-15 10:43:47 +08:00
|
|
|
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
|
|
|
|
isTypeCast == IsTypeCast, CastTy, RParenLoc);
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2020-06-30 05:12:14 +08:00
|
|
|
// FIXME: What should we do if a vector literal is followed by a
|
|
|
|
// postfix-expression suffix? Usually postfix operators are permitted on
|
|
|
|
// literals.
|
2017-03-29 20:09:39 +08:00
|
|
|
if (isVectorLiteral)
|
2020-06-30 05:12:14 +08:00
|
|
|
return Res;
|
2017-03-29 20:09:39 +08:00
|
|
|
|
2006-08-11 10:13:20 +08:00
|
|
|
switch (ParenExprType) {
|
|
|
|
case SimpleExpr: break; // Nothing else to do.
|
|
|
|
case CompoundStmt: break; // Nothing else to do.
|
|
|
|
case CompoundLiteral:
|
|
|
|
// We parsed '(' type-name ')' '{' ... '}'. If any suffixes of
|
|
|
|
// postfix-expression exist, parse them now.
|
|
|
|
break;
|
|
|
|
case CastExpr:
|
2009-05-22 18:23:40 +08:00
|
|
|
// We have parsed the cast-expression and no postfix-expr pieces are
|
|
|
|
// following.
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2018-07-28 05:55:12 +08:00
|
|
|
case FoldExpr:
|
|
|
|
// We only parsed a fold-expression. There might be postfix-expr pieces
|
|
|
|
// afterwards; parse them now.
|
|
|
|
break;
|
2006-08-11 10:13:20 +08:00
|
|
|
}
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2006-08-24 14:37:51 +08:00
|
|
|
}
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2006-08-11 04:56:00 +08:00
|
|
|
// primary-expression
|
2006-08-23 13:17:46 +08:00
|
|
|
case tok::numeric_constant:
|
|
|
|
// constant: integer-constant
|
|
|
|
// constant: floating-constant
|
2008-12-12 05:36:32 +08:00
|
|
|
|
2012-03-09 16:00:36 +08:00
|
|
|
Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope());
|
2006-08-23 13:17:46 +08:00
|
|
|
ConsumeToken();
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2006-08-23 13:17:46 +08:00
|
|
|
|
2007-02-13 09:51:42 +08:00
|
|
|
case tok::kw_true:
|
|
|
|
case tok::kw_false:
|
2017-09-29 05:29:18 +08:00
|
|
|
Res = ParseCXXBoolLiteral();
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2012-03-07 04:05:56 +08:00
|
|
|
case tok::kw___objc_yes:
|
|
|
|
case tok::kw___objc_no:
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseObjCBoolLiteral();
|
|
|
|
break;
|
2007-02-13 09:51:42 +08:00
|
|
|
|
2009-05-11 02:38:11 +08:00
|
|
|
case tok::kw_nullptr:
|
2011-10-18 07:06:20 +08:00
|
|
|
Diag(Tok, diag::warn_cxx98_compat_nullptr);
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
|
|
|
|
break;
|
2009-05-11 02:38:11 +08:00
|
|
|
|
2011-04-27 14:18:01 +08:00
|
|
|
case tok::annot_primary_expr:
|
2020-07-28 08:28:06 +08:00
|
|
|
case tok::annot_overload_set:
|
2011-04-27 14:18:01 +08:00
|
|
|
Res = getExprAnnotation(Tok);
|
2020-07-28 08:28:06 +08:00
|
|
|
if (!Res.isInvalid() && Tok.getKind() == tok::annot_overload_set)
|
|
|
|
Res = Actions.ActOnNameClassifiedAsOverloadSet(getCurScope(), Res.get());
|
2017-05-19 03:21:48 +08:00
|
|
|
ConsumeAnnotationToken();
|
2018-06-27 09:32:04 +08:00
|
|
|
if (!Res.isInvalid() && Tok.is(tok::less))
|
|
|
|
checkPotentialAngleBracket(Res);
|
2011-04-27 14:18:01 +08:00
|
|
|
break;
|
2013-04-27 00:15:35 +08:00
|
|
|
|
2019-10-15 05:53:03 +08:00
|
|
|
case tok::annot_non_type:
|
|
|
|
case tok::annot_non_type_dependent:
|
|
|
|
case tok::annot_non_type_undeclared: {
|
|
|
|
CXXScopeSpec SS;
|
|
|
|
Token Replacement;
|
|
|
|
Res = tryParseCXXIdExpression(SS, isAddressOfOperand, Replacement);
|
|
|
|
assert(!Res.isUnset() &&
|
|
|
|
"should not perform typo correction on annotation token");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-09-26 08:28:20 +08:00
|
|
|
case tok::kw___super:
|
2011-12-04 13:04:18 +08:00
|
|
|
case tok::kw_decltype:
|
2013-04-27 00:15:35 +08:00
|
|
|
// Annotate the token and tail recurse.
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
|
|
|
return ExprError();
|
2014-09-26 08:28:20 +08:00
|
|
|
assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super));
|
2020-01-09 21:07:51 +08:00
|
|
|
return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast,
|
|
|
|
isVectorLiteral, NotPrimaryExpression);
|
2020-02-18 10:48:38 +08:00
|
|
|
|
2008-11-09 00:45:02 +08:00
|
|
|
case tok::identifier: { // primary-expression: identifier
|
|
|
|
// unqualified-id: identifier
|
|
|
|
// constant: enumeration-constant
|
2009-01-06 13:06:21 +08:00
|
|
|
// Turn a potentially qualified name into a annot_typename or
|
2009-01-05 06:52:14 +08:00
|
|
|
// annot_cxxscope if it would be valid. This handles things like x::y, etc.
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus) {
|
2010-01-08 03:29:58 +08:00
|
|
|
// Avoid the unnecessary parse-time lookup in the common case
|
|
|
|
// where the syntax forbids a type.
|
|
|
|
const Token &Next = NextToken();
|
2012-08-31 04:04:43 +08:00
|
|
|
|
|
|
|
// If this identifier was reverted from a token ID, and the next token
|
|
|
|
// is a parenthesis, this is likely to be a use of a type trait. Check
|
|
|
|
// those tokens.
|
2014-09-23 12:09:56 +08:00
|
|
|
if (Next.is(tok::l_paren) &&
|
|
|
|
Tok.is(tok::identifier) &&
|
|
|
|
Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
|
|
|
|
IdentifierInfo *II = Tok.getIdentifierInfo();
|
|
|
|
// Build up the mapping of revertible type traits, for future use.
|
|
|
|
if (RevertibleTypeTraits.empty()) {
|
|
|
|
#define RTT_JOIN(X,Y) X##Y
|
|
|
|
#define REVERTIBLE_TYPE_TRAIT(Name) \
|
|
|
|
RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] \
|
|
|
|
= RTT_JOIN(tok::kw_,Name)
|
|
|
|
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_abstract);
|
2017-04-13 06:12:15 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_aggregate);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_array);
|
2016-05-24 01:21:55 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_assignable);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_base_of);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_class);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_complete_type);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_compound);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_const);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_constructible);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_convertible);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_convertible_to);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_destructible);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_empty);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_enum);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_floating_point);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_final);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_function);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_fundamental);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_integral);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_interface_class);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_literal);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_object);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_pod);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_pointer);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_polymorphic);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_reference);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_same);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_scalar);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_sealed);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_signed);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_standard_layout);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_trivial);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_union);
|
2014-09-23 12:09:56 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_unsigned);
|
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_void);
|
2014-09-24 11:28:54 +08:00
|
|
|
REVERTIBLE_TYPE_TRAIT(__is_volatile);
|
2014-09-23 12:09:56 +08:00
|
|
|
#undef REVERTIBLE_TYPE_TRAIT
|
|
|
|
#undef RTT_JOIN
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we find that this is in fact the name of a type trait,
|
|
|
|
// update the token kind in place and parse again to treat it as
|
|
|
|
// the appropriate kind of type trait.
|
|
|
|
llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
|
|
|
|
= RevertibleTypeTraits.find(II);
|
|
|
|
if (Known != RevertibleTypeTraits.end()) {
|
|
|
|
Tok.setKind(Known->second);
|
2020-01-09 21:07:51 +08:00
|
|
|
return ParseCastExpression(ParseKind, isAddressOfOperand,
|
|
|
|
NotCastExpr, isTypeCast,
|
|
|
|
isVectorLiteral, NotPrimaryExpression);
|
2014-09-23 12:09:56 +08:00
|
|
|
}
|
|
|
|
}
|
2012-08-31 04:04:43 +08:00
|
|
|
|
2015-06-18 18:59:26 +08:00
|
|
|
if ((!ColonIsSacred && Next.is(tok::colon)) ||
|
|
|
|
Next.isOneOf(tok::coloncolon, tok::less, tok::l_paren,
|
|
|
|
tok::l_brace)) {
|
2010-01-08 03:29:58 +08:00
|
|
|
// If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
2010-02-26 16:45:28 +08:00
|
|
|
return ExprError();
|
|
|
|
if (!Tok.is(tok::identifier))
|
2020-01-09 21:07:51 +08:00
|
|
|
return ParseCastExpression(ParseKind, isAddressOfOperand,
|
|
|
|
NotCastExpr, isTypeCast,
|
|
|
|
isVectorLiteral,
|
|
|
|
NotPrimaryExpression);
|
2010-01-08 03:29:58 +08:00
|
|
|
}
|
2009-01-05 07:23:14 +08:00
|
|
|
}
|
2008-08-22 23:38:55 +08:00
|
|
|
|
2009-10-26 01:04:48 +08:00
|
|
|
// Consume the identifier so that we can see if it is followed by a '(' or
|
|
|
|
// '.'.
|
|
|
|
IdentifierInfo &II = *Tok.getIdentifierInfo();
|
|
|
|
SourceLocation ILoc = ConsumeToken();
|
2012-08-31 04:04:43 +08:00
|
|
|
|
2010-04-11 16:28:14 +08:00
|
|
|
// Support 'Class.property' and 'super.property' notation.
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC && Tok.is(tok::period) &&
|
2010-07-03 01:43:08 +08:00
|
|
|
(Actions.getTypeName(II, ILoc, getCurScope()) ||
|
2010-04-12 14:20:33 +08:00
|
|
|
// Allow the base to be 'super' if in an objc-method.
|
2010-07-03 01:43:08 +08:00
|
|
|
(&II == Ident_super && getCurScope()->isInObjcMethodScope()))) {
|
2011-01-18 10:00:16 +08:00
|
|
|
ConsumeToken();
|
2016-12-08 23:09:40 +08:00
|
|
|
|
|
|
|
if (Tok.is(tok::code_completion) && &II != Ident_super) {
|
2021-03-12 19:00:54 +08:00
|
|
|
cutOffParsing();
|
2016-12-08 23:09:40 +08:00
|
|
|
Actions.CodeCompleteObjCClassPropertyRefExpr(
|
|
|
|
getCurScope(), II, ILoc, ExprStatementTokLoc == ILoc);
|
|
|
|
return ExprError();
|
|
|
|
}
|
2012-02-17 02:19:22 +08:00
|
|
|
// Allow either an identifier or the keyword 'class' (in C++).
|
2018-07-31 03:24:48 +08:00
|
|
|
if (Tok.isNot(tok::identifier) &&
|
2012-03-11 15:00:24 +08:00
|
|
|
!(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) {
|
2009-10-26 01:04:48 +08:00
|
|
|
Diag(Tok, diag::err_expected_property_name);
|
2009-03-10 05:12:44 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
IdentifierInfo &PropertyName = *Tok.getIdentifierInfo();
|
|
|
|
SourceLocation PropertyLoc = ConsumeToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-10-26 01:04:48 +08:00
|
|
|
Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName,
|
|
|
|
ILoc, PropertyLoc);
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2009-03-10 05:12:44 +08:00
|
|
|
}
|
2010-08-27 17:08:28 +08:00
|
|
|
|
2010-09-15 23:09:43 +08:00
|
|
|
// In an Objective-C method, if we have "super" followed by an identifier,
|
2010-09-16 00:23:04 +08:00
|
|
|
// the token sequence is ill-formed. However, if there's a ':' or ']' after
|
2010-09-15 23:09:43 +08:00
|
|
|
// that identifier, this is probably a message send with a missing open
|
2018-07-31 03:24:48 +08:00
|
|
|
// bracket. Treat it as such.
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC && &II == Ident_super && !InMessageExpression &&
|
2010-09-15 23:09:43 +08:00
|
|
|
getCurScope()->isInObjcMethodScope() &&
|
2010-09-16 00:23:04 +08:00
|
|
|
((Tok.is(tok::identifier) &&
|
|
|
|
(NextToken().is(tok::colon) || NextToken().is(tok::r_square))) ||
|
|
|
|
Tok.is(tok::code_completion))) {
|
2016-01-16 07:43:34 +08:00
|
|
|
Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, nullptr,
|
2014-05-21 14:02:52 +08:00
|
|
|
nullptr);
|
2010-09-15 23:09:43 +08:00
|
|
|
break;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-02-16 03:17:31 +08:00
|
|
|
// If we have an Objective-C class name followed by an identifier
|
|
|
|
// and either ':' or ']', this is an Objective-C class message
|
|
|
|
// send that's missing the opening '['. Recovery
|
|
|
|
// appropriately. Also take this path if we're performing code
|
|
|
|
// completion after an Objective-C class name.
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC &&
|
2018-07-31 03:24:48 +08:00
|
|
|
((Tok.is(tok::identifier) && !InMessageExpression) ||
|
2011-02-16 03:17:31 +08:00
|
|
|
Tok.is(tok::code_completion))) {
|
2010-09-16 09:51:54 +08:00
|
|
|
const Token& Next = NextToken();
|
2018-07-31 03:24:48 +08:00
|
|
|
if (Tok.is(tok::code_completion) ||
|
2011-02-16 03:17:31 +08:00
|
|
|
Next.is(tok::colon) || Next.is(tok::r_square))
|
2010-09-17 18:21:45 +08:00
|
|
|
if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope()))
|
|
|
|
if (Typ.get()->isObjCObjectOrInterfaceType()) {
|
2010-09-16 09:51:54 +08:00
|
|
|
// Fake up a Declarator to use with ActOnTypeName.
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2010-09-16 09:51:54 +08:00
|
|
|
DS.SetRangeStart(ILoc);
|
|
|
|
DS.SetRangeEnd(ILoc);
|
2014-05-21 14:02:52 +08:00
|
|
|
const char *PrevSpec = nullptr;
|
2010-09-16 09:51:54 +08:00
|
|
|
unsigned DiagID;
|
2018-01-02 02:23:28 +08:00
|
|
|
DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ,
|
2014-01-15 17:15:43 +08:00
|
|
|
Actions.getASTContext().getPrintingPolicy());
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2020-11-11 13:40:12 +08:00
|
|
|
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
2018-07-31 03:24:48 +08:00
|
|
|
TypeResult Ty = Actions.ActOnTypeName(getCurScope(),
|
2010-09-16 09:51:54 +08:00
|
|
|
DeclaratorInfo);
|
|
|
|
if (Ty.isInvalid())
|
|
|
|
break;
|
2014-05-21 14:02:52 +08:00
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
Res = ParseObjCMessageExpressionBody(SourceLocation(),
|
|
|
|
SourceLocation(),
|
2014-05-21 14:02:52 +08:00
|
|
|
Ty.get(), nullptr);
|
2010-09-16 09:51:54 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-08-27 17:08:28 +08:00
|
|
|
// Make sure to pass down the right value for isAddressOfOperand.
|
|
|
|
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
|
|
|
|
isAddressOfOperand = false;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2006-11-20 14:49:47 +08:00
|
|
|
// Function designators are allowed to be undeclared (C99 6.5.1p2), so we
|
|
|
|
// need to know whether or not this identifier is a function designator or
|
|
|
|
// not.
|
2009-11-04 00:56:39 +08:00
|
|
|
UnqualifiedId Name;
|
|
|
|
CXXScopeSpec ScopeSpec;
|
2012-01-27 17:46:47 +08:00
|
|
|
SourceLocation TemplateKWLoc;
|
2014-11-21 06:06:40 +08:00
|
|
|
Token Replacement;
|
2019-03-26 01:08:51 +08:00
|
|
|
CastExpressionIdValidator Validator(
|
|
|
|
/*Next=*/Tok,
|
|
|
|
/*AllowTypes=*/isTypeCast != NotTypeCast,
|
|
|
|
/*AllowNonTypes=*/isTypeCast != IsTypeCast);
|
|
|
|
Validator.IsAddressOfOperand = isAddressOfOperand;
|
2015-06-18 18:59:26 +08:00
|
|
|
if (Tok.isOneOf(tok::periodstar, tok::arrowstar)) {
|
2019-03-26 01:08:51 +08:00
|
|
|
Validator.WantExpressionKeywords = false;
|
|
|
|
Validator.WantRemainingKeywords = false;
|
2015-05-06 03:17:03 +08:00
|
|
|
} else {
|
2019-03-26 01:08:51 +08:00
|
|
|
Validator.WantRemainingKeywords = Tok.isNot(tok::r_paren);
|
2015-05-06 03:17:03 +08:00
|
|
|
}
|
2009-11-04 00:56:39 +08:00
|
|
|
Name.setIdentifier(&II, ILoc);
|
2014-11-21 06:06:40 +08:00
|
|
|
Res = Actions.ActOnIdExpression(
|
|
|
|
getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren),
|
2019-03-26 01:08:51 +08:00
|
|
|
isAddressOfOperand, &Validator,
|
2015-04-11 03:16:46 +08:00
|
|
|
/*IsInlineAsmIdentifier=*/false,
|
|
|
|
Tok.is(tok::r_paren) ? nullptr : &Replacement);
|
2018-06-27 09:32:04 +08:00
|
|
|
if (!Res.isInvalid() && Res.isUnset()) {
|
2014-11-21 06:06:40 +08:00
|
|
|
UnconsumeToken(Replacement);
|
2020-01-09 21:07:51 +08:00
|
|
|
return ParseCastExpression(ParseKind, isAddressOfOperand,
|
|
|
|
NotCastExpr, isTypeCast,
|
|
|
|
/*isVectorLiteral=*/false,
|
|
|
|
NotPrimaryExpression);
|
2014-11-21 06:06:40 +08:00
|
|
|
}
|
2018-06-27 09:32:04 +08:00
|
|
|
if (!Res.isInvalid() && Tok.is(tok::less))
|
|
|
|
checkPotentialAngleBracket(Res);
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2006-11-20 14:49:47 +08:00
|
|
|
}
|
2006-08-11 04:56:00 +08:00
|
|
|
case tok::char_constant: // constant: character-constant
|
2011-07-27 13:40:30 +08:00
|
|
|
case tok::wide_char_constant:
|
2014-11-08 14:08:42 +08:00
|
|
|
case tok::utf8_char_constant:
|
2011-07-27 13:40:30 +08:00
|
|
|
case tok::utf16_char_constant:
|
|
|
|
case tok::utf32_char_constant:
|
2012-03-09 16:00:36 +08:00
|
|
|
Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope());
|
2007-04-27 04:39:23 +08:00
|
|
|
ConsumeToken();
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2006-08-11 04:56:00 +08:00
|
|
|
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
|
|
|
|
case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
|
2013-11-07 07:31:56 +08:00
|
|
|
case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS]
|
2014-04-09 02:13:24 +08:00
|
|
|
case tok::kw___FUNCSIG__: // primary-expression: __FUNCSIG__ [MS]
|
2012-06-23 10:07:59 +08:00
|
|
|
case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS]
|
2018-07-27 07:18:44 +08:00
|
|
|
case tok::kw_L__FUNCSIG__: // primary-expression: L__FUNCSIG__ [MS]
|
2006-08-11 04:56:00 +08:00
|
|
|
case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
|
2008-08-10 09:53:14 +08:00
|
|
|
Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);
|
2006-08-11 04:56:00 +08:00
|
|
|
ConsumeToken();
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2006-08-11 04:56:00 +08:00
|
|
|
case tok::string_literal: // primary-expression: string-literal
|
2006-10-06 13:22:26 +08:00
|
|
|
case tok::wide_string_literal:
|
2011-07-27 13:40:30 +08:00
|
|
|
case tok::utf8_string_literal:
|
|
|
|
case tok::utf16_string_literal:
|
|
|
|
case tok::utf32_string_literal:
|
2012-03-06 11:21:47 +08:00
|
|
|
Res = ParseStringLiteralExpression(true);
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2011-12-24 01:00:35 +08:00
|
|
|
case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1]
|
2011-04-15 08:35:48 +08:00
|
|
|
Res = ParseGenericSelectionExpression();
|
|
|
|
break;
|
2016-07-16 08:35:23 +08:00
|
|
|
case tok::kw___builtin_available:
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseAvailabilityCheckExpr(Tok.getLocation());
|
|
|
|
break;
|
2006-08-11 06:01:51 +08:00
|
|
|
case tok::kw___builtin_va_arg:
|
|
|
|
case tok::kw___builtin_offsetof:
|
|
|
|
case tok::kw___builtin_choose_expr:
|
2011-06-04 08:47:47 +08:00
|
|
|
case tok::kw___builtin_astype: // primary-expression: [OCL] as_type()
|
2013-09-18 11:29:45 +08:00
|
|
|
case tok::kw___builtin_convertvector:
|
Implement __builtin_LINE() et. al. to support source location capture.
Summary:
This patch implements the source location builtins `__builtin_LINE(), `__builtin_FUNCTION()`, `__builtin_FILE()` and `__builtin_COLUMN()`. These builtins are needed to implement [`std::experimental::source_location`](https://rawgit.com/cplusplus/fundamentals-ts/v2/main.html#reflection.src_loc.creation).
With the exception of `__builtin_COLUMN`, GCC also implements these builtins, and Clangs behavior is intended to match as closely as possible.
Reviewers: rsmith, joerg, aaron.ballman, bogner, majnemer, shafik, martong
Reviewed By: rsmith
Subscribers: rnkovacs, loskutov, riccibruno, mgorny, kunitoki, alexr, majnemer, hfinkel, cfe-commits
Differential Revision: https://reviews.llvm.org/D37035
llvm-svn: 360937
2019-05-17 05:04:15 +08:00
|
|
|
case tok::kw___builtin_COLUMN:
|
|
|
|
case tok::kw___builtin_FILE:
|
|
|
|
case tok::kw___builtin_FUNCTION:
|
|
|
|
case tok::kw___builtin_LINE:
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2020-06-30 05:12:14 +08:00
|
|
|
// This parses the complete suffix; we can return early.
|
2008-12-12 06:33:27 +08:00
|
|
|
return ParseBuiltinPrimaryExpression();
|
2008-11-29 12:51:27 +08:00
|
|
|
case tok::kw___null:
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = Actions.ActOnGNUNullExpr(ConsumeToken());
|
|
|
|
break;
|
2011-07-08 12:59:44 +08:00
|
|
|
|
2010-08-06 22:50:36 +08:00
|
|
|
case tok::plusplus: // unary-expression: '++' unary-expression [C99]
|
|
|
|
case tok::minusminus: { // unary-expression: '--' unary-expression [C99]
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2010-08-06 22:50:36 +08:00
|
|
|
// C++ [expr.unary] has:
|
|
|
|
// unary-expression:
|
|
|
|
// ++ cast-expression
|
|
|
|
// -- cast-expression
|
2016-02-03 10:58:20 +08:00
|
|
|
Token SavedTok = Tok;
|
|
|
|
ConsumeToken();
|
2019-02-01 04:20:32 +08:00
|
|
|
|
|
|
|
PreferredType.enterUnary(Actions, Tok.getLocation(), SavedTok.getKind(),
|
|
|
|
SavedTok.getLocation());
|
2014-07-15 08:11:48 +08:00
|
|
|
// One special case is implicitly handled here: if the preceding tokens are
|
|
|
|
// an ambiguous cast expression, such as "(T())++", then we recurse to
|
|
|
|
// determine whether the '++' is prefix or postfix.
|
2020-01-09 21:07:51 +08:00
|
|
|
Res = ParseCastExpression(getLangOpts().CPlusPlus ?
|
|
|
|
UnaryExprOnly : AnyCastExpr,
|
2014-07-15 08:11:48 +08:00
|
|
|
/*isAddressOfOperand*/false, NotCastExpr,
|
2016-02-04 02:48:43 +08:00
|
|
|
NotTypeCast);
|
2016-02-03 10:58:20 +08:00
|
|
|
if (NotCastExpr) {
|
|
|
|
// If we return with NotCastExpr = true, we must not consume any tokens,
|
|
|
|
// so put the token back where we found it.
|
|
|
|
assert(Res.isInvalid());
|
|
|
|
UnconsumeToken(SavedTok);
|
|
|
|
return ExprError();
|
|
|
|
}
|
[AST] Add RecoveryExpr to retain expressions on semantic errors
Normally clang avoids creating expressions when it encounters semantic
errors, even if the parser knows which expression to produce.
This works well for the compiler. However, this is not ideal for
source-level tools that have to deal with broken code, e.g. clangd is
not able to provide navigation features even for names that compiler
knows how to resolve.
The new RecoveryExpr aims to capture the minimal set of information
useful for the tools that need to deal with incorrect code:
source range of the expression being dropped,
subexpressions of the expression.
We aim to make constructing RecoveryExprs as simple as possible to
ensure writing code to avoid dropping expressions is easy.
Producing RecoveryExprs can result in new code paths being taken in the
frontend. In particular, clang can produce some new diagnostics now and
we aim to suppress bogus ones based on Expr::containsErrors.
We deliberately produce RecoveryExprs only in the parser for now to
minimize the code affected by this patch. Producing RecoveryExprs in
Sema potentially allows to preserve more information (e.g. type of an
expression), but also results in more code being affected. E.g.
SFINAE checks will have to take presence of RecoveryExprs into account.
Initial implementation only works in C++ mode, as it relies on compiler
postponing diagnostics on dependent expressions. C and ObjC often do not
do this, so they require more work to make sure we do not produce too
many bogus diagnostics on the new expressions.
See documentation of RecoveryExpr for more details.
original patch from Ilya
This change is based on https://reviews.llvm.org/D61722
Reviewers: sammccall, rsmith
Reviewed By: sammccall, rsmith
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 23:30:40 +08:00
|
|
|
if (!Res.isInvalid()) {
|
|
|
|
Expr *Arg = Res.get();
|
2016-02-03 10:58:20 +08:00
|
|
|
Res = Actions.ActOnUnaryOp(getCurScope(), SavedTok.getLocation(),
|
[AST] Add RecoveryExpr to retain expressions on semantic errors
Normally clang avoids creating expressions when it encounters semantic
errors, even if the parser knows which expression to produce.
This works well for the compiler. However, this is not ideal for
source-level tools that have to deal with broken code, e.g. clangd is
not able to provide navigation features even for names that compiler
knows how to resolve.
The new RecoveryExpr aims to capture the minimal set of information
useful for the tools that need to deal with incorrect code:
source range of the expression being dropped,
subexpressions of the expression.
We aim to make constructing RecoveryExprs as simple as possible to
ensure writing code to avoid dropping expressions is easy.
Producing RecoveryExprs can result in new code paths being taken in the
frontend. In particular, clang can produce some new diagnostics now and
we aim to suppress bogus ones based on Expr::containsErrors.
We deliberately produce RecoveryExprs only in the parser for now to
minimize the code affected by this patch. Producing RecoveryExprs in
Sema potentially allows to preserve more information (e.g. type of an
expression), but also results in more code being affected. E.g.
SFINAE checks will have to take presence of RecoveryExprs into account.
Initial implementation only works in C++ mode, as it relies on compiler
postponing diagnostics on dependent expressions. C and ObjC often do not
do this, so they require more work to make sure we do not produce too
many bogus diagnostics on the new expressions.
See documentation of RecoveryExpr for more details.
original patch from Ilya
This change is based on https://reviews.llvm.org/D61722
Reviewers: sammccall, rsmith
Reviewed By: sammccall, rsmith
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 23:30:40 +08:00
|
|
|
SavedKind, Arg);
|
|
|
|
if (Res.isInvalid())
|
|
|
|
Res = Actions.CreateRecoveryExpr(SavedTok.getLocation(),
|
|
|
|
Arg->getEndLoc(), Arg);
|
|
|
|
}
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2006-10-25 11:38:23 +08:00
|
|
|
}
|
2009-02-04 04:19:35 +08:00
|
|
|
case tok::amp: { // unary-expression: '&' cast-expression
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2009-02-04 04:19:35 +08:00
|
|
|
// Special treatment because of member pointers
|
|
|
|
SourceLocation SavedLoc = ConsumeToken();
|
2019-02-01 04:20:32 +08:00
|
|
|
PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc);
|
2020-01-09 21:07:51 +08:00
|
|
|
Res = ParseCastExpression(AnyCastExpr, true);
|
[AST] Add RecoveryExpr to retain expressions on semantic errors
Normally clang avoids creating expressions when it encounters semantic
errors, even if the parser knows which expression to produce.
This works well for the compiler. However, this is not ideal for
source-level tools that have to deal with broken code, e.g. clangd is
not able to provide navigation features even for names that compiler
knows how to resolve.
The new RecoveryExpr aims to capture the minimal set of information
useful for the tools that need to deal with incorrect code:
source range of the expression being dropped,
subexpressions of the expression.
We aim to make constructing RecoveryExprs as simple as possible to
ensure writing code to avoid dropping expressions is easy.
Producing RecoveryExprs can result in new code paths being taken in the
frontend. In particular, clang can produce some new diagnostics now and
we aim to suppress bogus ones based on Expr::containsErrors.
We deliberately produce RecoveryExprs only in the parser for now to
minimize the code affected by this patch. Producing RecoveryExprs in
Sema potentially allows to preserve more information (e.g. type of an
expression), but also results in more code being affected. E.g.
SFINAE checks will have to take presence of RecoveryExprs into account.
Initial implementation only works in C++ mode, as it relies on compiler
postponing diagnostics on dependent expressions. C and ObjC often do not
do this, so they require more work to make sure we do not produce too
many bogus diagnostics on the new expressions.
See documentation of RecoveryExpr for more details.
original patch from Ilya
This change is based on https://reviews.llvm.org/D61722
Reviewers: sammccall, rsmith
Reviewed By: sammccall, rsmith
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 23:30:40 +08:00
|
|
|
if (!Res.isInvalid()) {
|
|
|
|
Expr *Arg = Res.get();
|
|
|
|
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Arg);
|
|
|
|
if (Res.isInvalid())
|
|
|
|
Res = Actions.CreateRecoveryExpr(Tok.getLocation(), Arg->getEndLoc(),
|
|
|
|
Arg);
|
|
|
|
}
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2009-02-04 04:19:35 +08:00
|
|
|
}
|
|
|
|
|
2006-08-11 10:13:20 +08:00
|
|
|
case tok::star: // unary-expression: '*' cast-expression
|
|
|
|
case tok::plus: // unary-expression: '+' cast-expression
|
|
|
|
case tok::minus: // unary-expression: '-' cast-expression
|
|
|
|
case tok::tilde: // unary-expression: '~' cast-expression
|
|
|
|
case tok::exclaim: // unary-expression: '!' cast-expression
|
|
|
|
case tok::kw___real: // unary-expression: '__real' cast-expression [GNU]
|
2008-02-03 04:20:10 +08:00
|
|
|
case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU]
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2008-02-03 04:20:10 +08:00
|
|
|
SourceLocation SavedLoc = ConsumeToken();
|
2019-02-01 04:20:32 +08:00
|
|
|
PreferredType.enterUnary(Actions, Tok.getLocation(), SavedKind, SavedLoc);
|
2020-01-09 21:07:51 +08:00
|
|
|
Res = ParseCastExpression(AnyCastExpr);
|
[AST] Add RecoveryExpr to retain expressions on semantic errors
Normally clang avoids creating expressions when it encounters semantic
errors, even if the parser knows which expression to produce.
This works well for the compiler. However, this is not ideal for
source-level tools that have to deal with broken code, e.g. clangd is
not able to provide navigation features even for names that compiler
knows how to resolve.
The new RecoveryExpr aims to capture the minimal set of information
useful for the tools that need to deal with incorrect code:
source range of the expression being dropped,
subexpressions of the expression.
We aim to make constructing RecoveryExprs as simple as possible to
ensure writing code to avoid dropping expressions is easy.
Producing RecoveryExprs can result in new code paths being taken in the
frontend. In particular, clang can produce some new diagnostics now and
we aim to suppress bogus ones based on Expr::containsErrors.
We deliberately produce RecoveryExprs only in the parser for now to
minimize the code affected by this patch. Producing RecoveryExprs in
Sema potentially allows to preserve more information (e.g. type of an
expression), but also results in more code being affected. E.g.
SFINAE checks will have to take presence of RecoveryExprs into account.
Initial implementation only works in C++ mode, as it relies on compiler
postponing diagnostics on dependent expressions. C and ObjC often do not
do this, so they require more work to make sure we do not produce too
many bogus diagnostics on the new expressions.
See documentation of RecoveryExpr for more details.
original patch from Ilya
This change is based on https://reviews.llvm.org/D61722
Reviewers: sammccall, rsmith
Reviewed By: sammccall, rsmith
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 23:30:40 +08:00
|
|
|
if (!Res.isInvalid()) {
|
|
|
|
Expr *Arg = Res.get();
|
|
|
|
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Arg);
|
|
|
|
if (Res.isInvalid())
|
|
|
|
Res = Actions.CreateRecoveryExpr(SavedLoc, Arg->getEndLoc(), Arg);
|
|
|
|
}
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2008-12-09 21:15:23 +08:00
|
|
|
}
|
|
|
|
|
2015-10-22 12:46:14 +08:00
|
|
|
case tok::kw_co_await: { // unary-expression: 'co_await' cast-expression
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2015-10-22 14:13:50 +08:00
|
|
|
SourceLocation CoawaitLoc = ConsumeToken();
|
2020-01-09 21:07:51 +08:00
|
|
|
Res = ParseCastExpression(AnyCastExpr);
|
2015-10-22 14:13:50 +08:00
|
|
|
if (!Res.isInvalid())
|
2015-10-27 14:02:45 +08:00
|
|
|
Res = Actions.ActOnCoawaitExpr(getCurScope(), CoawaitLoc, Res.get());
|
2015-10-22 12:46:14 +08:00
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
2006-10-25 11:38:23 +08:00
|
|
|
case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU]
|
2008-02-03 04:20:10 +08:00
|
|
|
// __extension__ silences extension warnings in the subexpression.
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2008-10-20 14:45:43 +08:00
|
|
|
ExtensionRAIIObject O(Diags); // Use RAII to do this.
|
2006-10-25 11:38:23 +08:00
|
|
|
SourceLocation SavedLoc = ConsumeToken();
|
2020-01-09 21:07:51 +08:00
|
|
|
Res = ParseCastExpression(AnyCastExpr);
|
2008-12-09 21:15:23 +08:00
|
|
|
if (!Res.isInvalid())
|
2010-08-24 07:25:46 +08:00
|
|
|
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2006-10-25 11:38:23 +08:00
|
|
|
}
|
2012-07-01 05:33:57 +08:00
|
|
|
case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')'
|
|
|
|
if (!getLangOpts().C11)
|
2019-08-27 03:44:07 +08:00
|
|
|
Diag(Tok, diag::ext_c11_feature) << Tok.getName();
|
Fix clang -Wimplicit-fallthrough warnings across llvm, NFC
This patch should not introduce any behavior changes. It consists of
mostly one of two changes:
1. Replacing fall through comments with the LLVM_FALLTHROUGH macro
2. Inserting 'break' before falling through into a case block consisting
of only 'break'.
We were already using this warning with GCC, but its warning behaves
slightly differently. In this patch, the following differences are
relevant:
1. GCC recognizes comments that say "fall through" as annotations, clang
doesn't
2. GCC doesn't warn on "case N: foo(); default: break;", clang does
3. GCC doesn't warn when the case contains a switch, but falls through
the outer case.
I will enable the warning separately in a follow-up patch so that it can
be cleanly reverted if necessary.
Reviewers: alexfh, rsmith, lattner, rtrieu, EricWF, bollu
Differential Revision: https://reviews.llvm.org/D53950
llvm-svn: 345882
2018-11-02 03:54:45 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2012-07-01 05:33:57 +08:00
|
|
|
case tok::kw_alignof: // unary-expression: 'alignof' '(' type-id ')'
|
2006-08-11 10:13:20 +08:00
|
|
|
case tok::kw___alignof: // unary-expression: '__alignof' unary-expression
|
|
|
|
// unary-expression: '__alignof' '(' type-name ')'
|
2012-07-01 05:33:57 +08:00
|
|
|
case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression
|
|
|
|
// unary-expression: 'sizeof' '(' type-name ')'
|
2011-03-12 03:24:49 +08:00
|
|
|
case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression
|
2015-07-02 11:40:19 +08:00
|
|
|
// unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')'
|
|
|
|
case tok::kw___builtin_omp_required_simd_align:
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2020-06-30 05:12:14 +08:00
|
|
|
AllowSuffix = false;
|
|
|
|
Res = ParseUnaryExprOrTypeTraitExpression();
|
|
|
|
break;
|
2006-10-25 11:38:23 +08:00
|
|
|
case tok::ampamp: { // unary-expression: '&&' identifier
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2007-05-28 14:56:27 +08:00
|
|
|
SourceLocation AmpAmpLoc = ConsumeToken();
|
2008-12-12 05:36:32 +08:00
|
|
|
if (Tok.isNot(tok::identifier))
|
2013-12-24 17:48:30 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
|
2008-12-10 08:02:53 +08:00
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
if (getCurScope()->getFnParent() == nullptr)
|
2011-02-19 05:16:39 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_address_of_label_outside_fn));
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-05-28 14:56:27 +08:00
|
|
|
Diag(AmpAmpLoc, diag::ext_gnu_address_of_label);
|
2011-02-18 09:27:55 +08:00
|
|
|
LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(),
|
|
|
|
Tok.getLocation());
|
|
|
|
Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD);
|
2006-10-16 06:33:58 +08:00
|
|
|
ConsumeToken();
|
2020-06-30 05:12:14 +08:00
|
|
|
AllowSuffix = false;
|
|
|
|
break;
|
2006-10-25 11:38:23 +08:00
|
|
|
}
|
2006-12-05 02:06:35 +08:00
|
|
|
case tok::kw_const_cast:
|
|
|
|
case tok::kw_dynamic_cast:
|
|
|
|
case tok::kw_reinterpret_cast:
|
|
|
|
case tok::kw_static_cast:
|
2020-05-18 18:02:01 +08:00
|
|
|
case tok::kw_addrspace_cast:
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2008-08-17 03:45:32 +08:00
|
|
|
Res = ParseCXXCasts();
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2019-07-03 02:28:13 +08:00
|
|
|
case tok::kw___builtin_bit_cast:
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2019-07-03 02:28:13 +08:00
|
|
|
Res = ParseBuiltinBitCast();
|
|
|
|
break;
|
2008-11-11 19:37:55 +08:00
|
|
|
case tok::kw_typeid:
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2008-11-11 19:37:55 +08:00
|
|
|
Res = ParseCXXTypeid();
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2010-09-08 20:20:18 +08:00
|
|
|
case tok::kw___uuidof:
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2010-09-08 20:20:18 +08:00
|
|
|
Res = ParseCXXUuidof();
|
|
|
|
break;
|
2008-06-25 06:12:16 +08:00
|
|
|
case tok::kw_this:
|
2008-08-17 03:34:46 +08:00
|
|
|
Res = ParseCXXThis();
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2021-04-23 23:22:35 +08:00
|
|
|
case tok::kw___builtin_sycl_unique_stable_name:
|
|
|
|
Res = ParseSYCLUniqueStableNameExpression();
|
|
|
|
break;
|
2020-10-12 13:09:25 +08:00
|
|
|
|
2010-09-16 09:51:54 +08:00
|
|
|
case tok::annot_typename:
|
|
|
|
if (isStartOfObjCClassMessageMissingOpenBracket()) {
|
2020-03-31 08:19:30 +08:00
|
|
|
TypeResult Type = getTypeAnnotation(Tok);
|
2013-02-02 02:28:04 +08:00
|
|
|
|
2010-09-16 09:51:54 +08:00
|
|
|
// Fake up a Declarator to use with ActOnTypeName.
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2010-09-16 09:51:54 +08:00
|
|
|
DS.SetRangeStart(Tok.getLocation());
|
|
|
|
DS.SetRangeEnd(Tok.getLastLoc());
|
|
|
|
|
2014-05-21 14:02:52 +08:00
|
|
|
const char *PrevSpec = nullptr;
|
2010-09-16 09:51:54 +08:00
|
|
|
unsigned DiagID;
|
2018-01-02 02:23:28 +08:00
|
|
|
DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(),
|
|
|
|
PrevSpec, DiagID, Type,
|
2014-01-15 17:15:43 +08:00
|
|
|
Actions.getASTContext().getPrintingPolicy());
|
2013-02-02 02:28:04 +08:00
|
|
|
|
2020-11-11 13:40:12 +08:00
|
|
|
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
2010-09-16 09:51:54 +08:00
|
|
|
TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
|
|
|
if (Ty.isInvalid())
|
|
|
|
break;
|
|
|
|
|
2017-05-19 03:21:48 +08:00
|
|
|
ConsumeAnnotationToken();
|
2010-09-16 09:51:54 +08:00
|
|
|
Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
|
2014-05-21 14:02:52 +08:00
|
|
|
Ty.get(), nullptr);
|
2010-09-16 09:51:54 +08:00
|
|
|
break;
|
|
|
|
}
|
Fix clang -Wimplicit-fallthrough warnings across llvm, NFC
This patch should not introduce any behavior changes. It consists of
mostly one of two changes:
1. Replacing fall through comments with the LLVM_FALLTHROUGH macro
2. Inserting 'break' before falling through into a case block consisting
of only 'break'.
We were already using this warning with GCC, but its warning behaves
slightly differently. In this patch, the following differences are
relevant:
1. GCC recognizes comments that say "fall through" as annotations, clang
doesn't
2. GCC doesn't warn on "case N: foo(); default: break;", clang does
3. GCC doesn't warn when the case contains a switch, but falls through
the outer case.
I will enable the warning separately in a follow-up patch so that it can
be cleanly reverted if necessary.
Reviewers: alexfh, rsmith, lattner, rtrieu, EricWF, bollu
Differential Revision: https://reviews.llvm.org/D53950
llvm-svn: 345882
2018-11-02 03:54:45 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2013-02-02 02:28:04 +08:00
|
|
|
|
2012-01-24 13:47:35 +08:00
|
|
|
case tok::annot_decltype:
|
2008-08-22 23:38:55 +08:00
|
|
|
case tok::kw_char:
|
|
|
|
case tok::kw_wchar_t:
|
2018-05-01 13:02:45 +08:00
|
|
|
case tok::kw_char8_t:
|
2009-07-14 14:30:34 +08:00
|
|
|
case tok::kw_char16_t:
|
|
|
|
case tok::kw_char32_t:
|
2008-08-22 23:38:55 +08:00
|
|
|
case tok::kw_bool:
|
|
|
|
case tok::kw_short:
|
|
|
|
case tok::kw_int:
|
|
|
|
case tok::kw_long:
|
2011-04-28 09:59:37 +08:00
|
|
|
case tok::kw___int64:
|
2012-04-04 14:24:32 +08:00
|
|
|
case tok::kw___int128:
|
2020-04-18 01:44:19 +08:00
|
|
|
case tok::kw__ExtInt:
|
2021-12-07 01:46:54 +08:00
|
|
|
case tok::kw__BitInt:
|
2008-08-22 23:38:55 +08:00
|
|
|
case tok::kw_signed:
|
|
|
|
case tok::kw_unsigned:
|
2011-10-15 07:23:15 +08:00
|
|
|
case tok::kw_half:
|
2008-08-22 23:38:55 +08:00
|
|
|
case tok::kw_float:
|
|
|
|
case tok::kw_double:
|
[ARM] Add __bf16 as new Bfloat16 C Type
Summary:
This patch upstreams support for a new storage only bfloat16 C type.
This type is used to implement primitive support for bfloat16 data, in
line with the Bfloat16 extension of the Armv8.6-a architecture, as
detailed here:
https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/arm-architecture-developments-armv8-6-a
The bfloat type, and its properties are specified in the Arm Architecture
Reference Manual:
https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile
In detail this patch:
- introduces an opaque, storage-only C-type __bf16, which introduces a new bfloat IR type.
This is part of a patch series, starting with command-line and Bfloat16
assembly support. The subsequent patches will upstream intrinsics
support for BFloat16, followed by Matrix Multiplication and the
remaining Virtualization features of the armv8.6-a architecture.
The following people contributed to this patch:
- Luke Cheeseman
- Momchil Velikov
- Alexandros Lamprineas
- Luke Geeson
- Simon Tatham
- Ties Stuij
Reviewers: SjoerdMeijer, rjmccall, rsmith, liutianle, RKSimon, craig.topper, jfb, LukeGeeson, fpetrogalli
Reviewed By: SjoerdMeijer
Subscribers: labrinea, majnemer, asmith, dexonsmith, kristof.beyls, arphaman, danielkiss, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D76077
2020-06-05 07:20:02 +08:00
|
|
|
case tok::kw___bf16:
|
2017-09-08 23:15:00 +08:00
|
|
|
case tok::kw__Float16:
|
2016-05-09 16:52:33 +08:00
|
|
|
case tok::kw___float128:
|
2021-09-06 17:49:23 +08:00
|
|
|
case tok::kw___ibm128:
|
2008-08-22 23:38:55 +08:00
|
|
|
case tok::kw_void:
|
2009-03-28 07:10:48 +08:00
|
|
|
case tok::kw_typename:
|
2009-01-05 06:28:21 +08:00
|
|
|
case tok::kw_typeof:
|
2016-04-08 21:40:33 +08:00
|
|
|
case tok::kw___vector:
|
|
|
|
#define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t:
|
2016-04-13 16:33:41 +08:00
|
|
|
#include "clang/Basic/OpenCLImageTypes.def"
|
2016-04-08 21:40:33 +08:00
|
|
|
{
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().CPlusPlus) {
|
2009-01-05 06:28:21 +08:00
|
|
|
Diag(Tok, diag::err_expected_expression);
|
|
|
|
return ExprError();
|
|
|
|
}
|
2009-06-11 08:33:41 +08:00
|
|
|
|
2020-01-09 21:07:51 +08:00
|
|
|
// Everything henceforth is a postfix-expression.
|
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
|
|
|
|
2009-06-11 08:33:41 +08:00
|
|
|
if (SavedKind == tok::kw_typename) {
|
|
|
|
// postfix-expression: typename-specifier '(' expression-list[opt] ')'
|
2011-06-05 20:23:16 +08:00
|
|
|
// typename-specifier braced-init-list
|
2010-02-26 16:45:28 +08:00
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
2009-06-11 08:33:41 +08:00
|
|
|
return ExprError();
|
2013-09-22 11:30:01 +08:00
|
|
|
|
|
|
|
if (!Actions.isSimpleTypeSpecifier(Tok.getKind()))
|
|
|
|
// We are trying to parse a simple-type-specifier but might not get such
|
|
|
|
// a token after error recovery.
|
|
|
|
return ExprError();
|
2009-06-11 08:33:41 +08:00
|
|
|
}
|
|
|
|
|
2008-08-22 23:38:55 +08:00
|
|
|
// postfix-expression: simple-type-specifier '(' expression-list[opt] ')'
|
2011-06-05 20:23:16 +08:00
|
|
|
// simple-type-specifier braced-init-list
|
2008-08-22 23:38:55 +08:00
|
|
|
//
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2013-09-22 09:24:26 +08:00
|
|
|
|
2008-08-22 23:38:55 +08:00
|
|
|
ParseCXXSimpleTypeSpecifier(DS);
|
2011-06-05 20:23:16 +08:00
|
|
|
if (Tok.isNot(tok::l_paren) &&
|
2013-01-02 19:42:31 +08:00
|
|
|
(!getLangOpts().CPlusPlus11 || Tok.isNot(tok::l_brace)))
|
2008-12-12 05:36:32 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
|
|
|
|
<< DS.getSourceRange());
|
2008-08-22 23:38:55 +08:00
|
|
|
|
2011-10-15 13:09:34 +08:00
|
|
|
if (Tok.is(tok::l_brace))
|
|
|
|
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
|
|
|
|
|
2008-08-22 23:38:55 +08:00
|
|
|
Res = ParseCXXTypeConstructExpression(DS);
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2008-08-22 23:38:55 +08:00
|
|
|
}
|
|
|
|
|
2010-02-06 03:11:37 +08:00
|
|
|
case tok::annot_cxxscope: { // [C++] id-expression: qualified-id
|
2010-04-23 10:08:13 +08:00
|
|
|
// If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
|
|
|
|
// (We can end up in this situation after tentative parsing.)
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
|
|
|
return ExprError();
|
|
|
|
if (!Tok.is(tok::annot_cxxscope))
|
2020-01-09 21:07:51 +08:00
|
|
|
return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,
|
|
|
|
isTypeCast, isVectorLiteral,
|
|
|
|
NotPrimaryExpression);
|
2010-04-23 10:08:13 +08:00
|
|
|
|
2010-02-06 03:11:37 +08:00
|
|
|
Token Next = NextToken();
|
|
|
|
if (Next.is(tok::annot_template_id)) {
|
2011-06-22 14:09:49 +08:00
|
|
|
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
|
2010-02-06 03:11:37 +08:00
|
|
|
if (TemplateId->Kind == TNK_Type_template) {
|
|
|
|
// We have a qualified template-id that we know refers to a
|
|
|
|
// type, translate it into a type and continue parsing as a
|
|
|
|
// cast expression.
|
|
|
|
CXXScopeSpec SS;
|
2020-03-19 16:12:29 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr,
|
2022-01-09 16:19:49 +08:00
|
|
|
/*ObjectHasErrors=*/false,
|
2011-11-08 01:33:42 +08:00
|
|
|
/*EnteringContext=*/false);
|
2020-01-18 07:42:11 +08:00
|
|
|
AnnotateTemplateIdTokenAsType(SS);
|
2020-01-09 21:07:51 +08:00
|
|
|
return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr,
|
|
|
|
isTypeCast, isVectorLiteral,
|
|
|
|
NotPrimaryExpression);
|
2010-02-06 03:11:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse as an id-expression.
|
|
|
|
Res = ParseCXXIdExpression(isAddressOfOperand);
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2010-02-06 03:11:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case tok::annot_template_id: { // [C++] template-id
|
2011-06-22 14:09:49 +08:00
|
|
|
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
|
2010-02-06 03:11:37 +08:00
|
|
|
if (TemplateId->Kind == TNK_Type_template) {
|
|
|
|
// We have a template-id that we know refers to a type,
|
|
|
|
// translate it into a type and continue parsing as a cast
|
|
|
|
// expression.
|
2020-01-18 07:42:11 +08:00
|
|
|
CXXScopeSpec SS;
|
|
|
|
AnnotateTemplateIdTokenAsType(SS);
|
2020-01-09 21:07:51 +08:00
|
|
|
return ParseCastExpression(ParseKind, isAddressOfOperand,
|
|
|
|
NotCastExpr, isTypeCast, isVectorLiteral,
|
|
|
|
NotPrimaryExpression);
|
2010-02-06 03:11:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fall through to treat the template-id as an id-expression.
|
2017-06-02 05:21:49 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2010-02-06 03:11:37 +08:00
|
|
|
}
|
|
|
|
|
2008-11-09 00:45:02 +08:00
|
|
|
case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
|
2009-02-04 04:19:35 +08:00
|
|
|
Res = ParseCXXIdExpression(isAddressOfOperand);
|
2010-08-24 07:25:46 +08:00
|
|
|
break;
|
2008-11-07 06:13:31 +08:00
|
|
|
|
2009-01-05 06:52:14 +08:00
|
|
|
case tok::coloncolon: {
|
2009-01-05 11:55:46 +08:00
|
|
|
// ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken
|
|
|
|
// annotates the token, tail recurse.
|
|
|
|
if (TryAnnotateTypeOrScopeToken())
|
2010-02-26 16:45:28 +08:00
|
|
|
return ExprError();
|
|
|
|
if (!Tok.is(tok::coloncolon))
|
2020-01-09 21:07:51 +08:00
|
|
|
return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast,
|
|
|
|
isVectorLiteral, NotPrimaryExpression);
|
2009-02-04 04:19:35 +08:00
|
|
|
|
2009-01-05 06:52:14 +08:00
|
|
|
// ::new -> [C++] new-expression
|
|
|
|
// ::delete -> [C++] delete-expression
|
2009-01-05 11:55:46 +08:00
|
|
|
SourceLocation CCLoc = ConsumeToken();
|
2020-01-09 21:07:51 +08:00
|
|
|
if (Tok.is(tok::kw_new)) {
|
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseCXXNewExpression(true, CCLoc);
|
|
|
|
AllowSuffix = false;
|
|
|
|
break;
|
2020-01-09 21:07:51 +08:00
|
|
|
}
|
|
|
|
if (Tok.is(tok::kw_delete)) {
|
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseCXXDeleteExpression(true, CCLoc);
|
|
|
|
AllowSuffix = false;
|
|
|
|
break;
|
2020-01-09 21:07:51 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-01-05 07:23:14 +08:00
|
|
|
// This is not a type name or scope specifier, it is an invalid expression.
|
2009-01-05 11:55:46 +08:00
|
|
|
Diag(CCLoc, diag::err_expected_expression);
|
2009-01-05 07:23:14 +08:00
|
|
|
return ExprError();
|
2009-01-05 05:25:24 +08:00
|
|
|
}
|
2008-12-03 00:35:44 +08:00
|
|
|
|
2008-11-22 03:14:01 +08:00
|
|
|
case tok::kw_new: // [C++] new-expression
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseCXXNewExpression(false, Tok.getLocation());
|
|
|
|
AllowSuffix = false;
|
|
|
|
break;
|
2008-11-22 03:14:01 +08:00
|
|
|
|
|
|
|
case tok::kw_delete: // [C++] delete-expression
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseCXXDeleteExpression(false, Tok.getLocation());
|
|
|
|
AllowSuffix = false;
|
|
|
|
break;
|
2008-11-22 03:14:01 +08:00
|
|
|
|
2020-01-18 15:11:43 +08:00
|
|
|
case tok::kw_requires: // [C++2a] requires-expression
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseRequiresExpression();
|
|
|
|
AllowSuffix = false;
|
|
|
|
break;
|
2020-01-18 15:11:43 +08:00
|
|
|
|
2010-09-11 04:55:37 +08:00
|
|
|
case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')'
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2011-10-18 07:06:20 +08:00
|
|
|
Diag(Tok, diag::warn_cxx98_compat_noexcept_expr);
|
2010-09-11 04:55:37 +08:00
|
|
|
SourceLocation KeyLoc = ConsumeToken();
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
|
|
|
|
if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept"))
|
2010-09-11 04:55:37 +08:00
|
|
|
return ExprError();
|
2011-12-20 10:08:33 +08:00
|
|
|
// C++11 [expr.unary.noexcept]p1:
|
2010-09-11 05:57:27 +08:00
|
|
|
// The noexcept operator determines whether the evaluation of its operand,
|
|
|
|
// which is an unevaluated operand, can throw an exception.
|
2017-04-02 05:30:49 +08:00
|
|
|
EnterExpressionEvaluationContext Unevaluated(
|
|
|
|
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseExpression();
|
2011-10-13 00:37:45 +08:00
|
|
|
|
|
|
|
T.consumeClose();
|
|
|
|
|
2020-06-30 05:12:14 +08:00
|
|
|
if (!Res.isInvalid())
|
|
|
|
Res = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(), Res.get(),
|
|
|
|
T.getCloseLocation());
|
|
|
|
AllowSuffix = false;
|
|
|
|
break;
|
2010-09-11 04:55:37 +08:00
|
|
|
}
|
|
|
|
|
2013-12-13 05:23:03 +08:00
|
|
|
#define TYPE_TRAIT(N,Spelling,K) \
|
|
|
|
case tok::kw_##Spelling:
|
|
|
|
#include "clang/Basic/TokenKinds.def"
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseTypeTrait();
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-04-28 08:16:57 +08:00
|
|
|
case tok::kw___array_rank:
|
|
|
|
case tok::kw___array_extent:
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseArrayTypeTrait();
|
|
|
|
break;
|
2011-04-28 08:16:57 +08:00
|
|
|
|
2011-04-25 14:54:41 +08:00
|
|
|
case tok::kw___is_lvalue_expr:
|
|
|
|
case tok::kw___is_rvalue_expr:
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2020-06-30 05:12:14 +08:00
|
|
|
Res = ParseExpressionTrait();
|
|
|
|
break;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2007-10-04 06:03:06 +08:00
|
|
|
case tok::at: {
|
2020-01-09 21:07:51 +08:00
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2007-10-04 06:03:06 +08:00
|
|
|
SourceLocation AtLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
return ParseObjCAtExpression(AtLoc);
|
2007-10-04 06:03:06 +08:00
|
|
|
}
|
2008-08-29 03:20:44 +08:00
|
|
|
case tok::caret:
|
2011-07-08 12:28:55 +08:00
|
|
|
Res = ParseBlockLiteralExpression();
|
|
|
|
break;
|
|
|
|
case tok::code_completion: {
|
2021-03-12 19:00:54 +08:00
|
|
|
cutOffParsing();
|
2019-02-01 04:20:32 +08:00
|
|
|
Actions.CodeCompleteExpression(getCurScope(),
|
|
|
|
PreferredType.get(Tok.getLocation()));
|
2011-09-04 11:32:15 +08:00
|
|
|
return ExprError();
|
2011-07-08 12:28:55 +08:00
|
|
|
}
|
2008-12-13 03:20:14 +08:00
|
|
|
case tok::l_square:
|
2013-01-02 19:42:31 +08:00
|
|
|
if (getLangOpts().CPlusPlus11) {
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC) {
|
2012-01-04 10:40:39 +08:00
|
|
|
// C++11 lambda expressions and Objective-C message sends both start with a
|
|
|
|
// square bracket. There are three possibilities here:
|
|
|
|
// we have a valid lambda expression, we have an invalid lambda
|
|
|
|
// expression, or we have something that doesn't appear to be a lambda.
|
|
|
|
// If we're in the last case, we fall back to ParseObjCMessageExpression.
|
2011-08-04 23:30:47 +08:00
|
|
|
Res = TryParseLambdaExpression();
|
2020-01-09 21:07:51 +08:00
|
|
|
if (!Res.isInvalid() && !Res.get()) {
|
|
|
|
// We assume Objective-C++ message expressions are not
|
|
|
|
// primary-expressions.
|
|
|
|
if (NotPrimaryExpression)
|
|
|
|
*NotPrimaryExpression = true;
|
2011-08-04 23:30:47 +08:00
|
|
|
Res = ParseObjCMessageExpression();
|
2020-01-09 21:07:51 +08:00
|
|
|
}
|
2011-08-04 23:30:47 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
Res = ParseLambdaExpression();
|
|
|
|
break;
|
|
|
|
}
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC) {
|
2011-07-08 12:28:55 +08:00
|
|
|
Res = ParseObjCMessageExpression();
|
|
|
|
break;
|
|
|
|
}
|
Fix clang -Wimplicit-fallthrough warnings across llvm, NFC
This patch should not introduce any behavior changes. It consists of
mostly one of two changes:
1. Replacing fall through comments with the LLVM_FALLTHROUGH macro
2. Inserting 'break' before falling through into a case block consisting
of only 'break'.
We were already using this warning with GCC, but its warning behaves
slightly differently. In this patch, the following differences are
relevant:
1. GCC recognizes comments that say "fall through" as annotations, clang
doesn't
2. GCC doesn't warn on "case N: foo(); default: break;", clang does
3. GCC doesn't warn when the case contains a switch, but falls through
the outer case.
I will enable the warning separately in a follow-up patch so that it can
be cleanly reverted if necessary.
Reviewers: alexfh, rsmith, lattner, rtrieu, EricWF, bollu
Differential Revision: https://reviews.llvm.org/D53950
llvm-svn: 345882
2018-11-02 03:54:45 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
2006-08-11 04:56:00 +08:00
|
|
|
default:
|
2009-05-22 18:24:42 +08:00
|
|
|
NotCastExpr = true;
|
2008-12-12 05:36:32 +08:00
|
|
|
return ExprError();
|
2006-08-11 06:01:51 +08:00
|
|
|
}
|
2008-12-12 05:36:32 +08:00
|
|
|
|
2016-01-05 22:39:27 +08:00
|
|
|
// Check to see whether Res is a function designator only. If it is and we
|
|
|
|
// are compiling for OpenCL, we need to return an error as this implies
|
|
|
|
// that the address of the function is being taken, which is illegal in CL.
|
|
|
|
|
2020-01-09 21:07:51 +08:00
|
|
|
if (ParseKind == PrimaryExprOnly)
|
|
|
|
// This is strictly a primary-expression - no postfix-expr pieces should be
|
|
|
|
// parsed.
|
|
|
|
return Res;
|
|
|
|
|
2020-06-30 05:12:14 +08:00
|
|
|
if (!AllowSuffix) {
|
|
|
|
// FIXME: Don't parse a primary-expression suffix if we encountered a parse
|
|
|
|
// error already.
|
|
|
|
if (Res.isInvalid())
|
|
|
|
return Res;
|
|
|
|
|
|
|
|
switch (Tok.getKind()) {
|
|
|
|
case tok::l_square:
|
|
|
|
case tok::l_paren:
|
|
|
|
case tok::plusplus:
|
|
|
|
case tok::minusminus:
|
|
|
|
// "expected ';'" or similar is probably the right diagnostic here. Let
|
|
|
|
// the caller decide what to do.
|
|
|
|
if (Tok.isAtStartOfLine())
|
|
|
|
return Res;
|
|
|
|
|
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
case tok::period:
|
|
|
|
case tok::arrow:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return Res;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This was a unary-expression for which a postfix-expression suffix is
|
|
|
|
// not permitted by the grammar (eg, a sizeof expression or
|
|
|
|
// new-expression or similar). Diagnose but parse the suffix anyway.
|
|
|
|
Diag(Tok.getLocation(), diag::err_postfix_after_unary_requires_parens)
|
|
|
|
<< Tok.getKind() << Res.get()->getSourceRange()
|
|
|
|
<< FixItHint::CreateInsertion(Res.get()->getBeginLoc(), "(")
|
|
|
|
<< FixItHint::CreateInsertion(PP.getLocForEndOfToken(PrevTokLocation),
|
|
|
|
")");
|
|
|
|
}
|
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
// These can be followed by postfix-expr pieces.
|
2019-02-01 04:20:32 +08:00
|
|
|
PreferredType = SavedType;
|
2016-01-05 22:39:27 +08:00
|
|
|
Res = ParsePostfixExpressionSuffix(Res);
|
2021-03-05 21:23:49 +08:00
|
|
|
if (getLangOpts().OpenCL &&
|
|
|
|
!getActions().getOpenCLOptions().isAvailableOption(
|
|
|
|
"__cl_clang_function_pointers", getLangOpts()))
|
2016-01-05 22:39:27 +08:00
|
|
|
if (Expr *PostfixExpr = Res.get()) {
|
|
|
|
QualType Ty = PostfixExpr->getType();
|
|
|
|
if (!Ty.isNull() && Ty->isFunctionType()) {
|
|
|
|
Diag(PostfixExpr->getExprLoc(),
|
|
|
|
diag::err_opencl_taking_function_address_parser);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Res;
|
2006-08-13 01:40:43 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Once the leading part of a postfix-expression is parsed, this
|
2012-06-17 12:36:28 +08:00
|
|
|
/// method parses any suffixes that apply.
|
2006-08-13 01:40:43 +08:00
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2006-08-13 01:40:43 +08:00
|
|
|
/// postfix-expression: [C99 6.5.2]
|
|
|
|
/// primary-expression
|
|
|
|
/// postfix-expression '[' expression ']'
|
2011-06-05 20:23:16 +08:00
|
|
|
/// postfix-expression '[' braced-init-list ']'
|
2022-02-09 01:09:03 +08:00
|
|
|
/// postfix-expression '[' expression-list [opt] ']' [C++2b 12.4.5]
|
2006-08-13 01:40:43 +08:00
|
|
|
/// postfix-expression '(' argument-expression-list[opt] ')'
|
|
|
|
/// postfix-expression '.' identifier
|
|
|
|
/// postfix-expression '->' identifier
|
|
|
|
/// postfix-expression '++'
|
|
|
|
/// postfix-expression '--'
|
|
|
|
/// '(' type-name ')' '{' initializer-list '}'
|
|
|
|
/// '(' type-name ')' '{' initializer-list ',' '}'
|
|
|
|
///
|
|
|
|
/// argument-expression-list: [C99 6.5.2]
|
2011-01-04 03:31:53 +08:00
|
|
|
/// argument-expression ...[opt]
|
|
|
|
/// argument-expression-list ',' assignment-expression ...[opt]
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
|
|
|
Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
2006-08-11 06:01:51 +08:00
|
|
|
// Now that the primary-expression piece of the postfix-expression has been
|
|
|
|
// parsed, see if there are any postfix-expression pieces here.
|
|
|
|
SourceLocation Loc;
|
2019-02-01 04:20:32 +08:00
|
|
|
auto SavedType = PreferredType;
|
2022-01-09 16:19:47 +08:00
|
|
|
while (true) {
|
2019-02-01 04:20:32 +08:00
|
|
|
// Each iteration relies on preferred type for the whole expression.
|
|
|
|
PreferredType = SavedType;
|
2006-08-11 06:01:51 +08:00
|
|
|
switch (Tok.getKind()) {
|
2010-09-16 00:23:04 +08:00
|
|
|
case tok::code_completion:
|
|
|
|
if (InMessageExpression)
|
2012-08-24 05:35:17 +08:00
|
|
|
return LHS;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2021-03-12 19:00:54 +08:00
|
|
|
cutOffParsing();
|
2019-02-01 04:20:32 +08:00
|
|
|
Actions.CodeCompletePostfixExpression(
|
|
|
|
getCurScope(), LHS, PreferredType.get(Tok.getLocation()));
|
2011-09-04 11:32:15 +08:00
|
|
|
return ExprError();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2010-09-15 22:51:05 +08:00
|
|
|
case tok::identifier:
|
|
|
|
// If we see identifier: after an expression, and we're not already in a
|
|
|
|
// message send, then this is probably a message send with a missing
|
|
|
|
// opening bracket '['.
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC && !InMessageExpression &&
|
2010-09-15 22:54:45 +08:00
|
|
|
(NextToken().is(tok::colon) || NextToken().is(tok::r_square))) {
|
2010-09-15 22:51:05 +08:00
|
|
|
LHS = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
|
2016-01-16 07:43:34 +08:00
|
|
|
nullptr, LHS.get());
|
2010-09-15 22:51:05 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Fall through; this isn't a message send.
|
2017-06-02 05:21:49 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
|
2006-08-13 01:40:43 +08:00
|
|
|
default: // Not a postfix-expression suffix.
|
2012-08-24 05:35:17 +08:00
|
|
|
return LHS;
|
2006-08-24 11:51:22 +08:00
|
|
|
case tok::l_square: { // postfix-expression: p-e '[' expression ']'
|
2010-06-01 02:18:22 +08:00
|
|
|
// If we have a array postfix expression that starts on a new line and
|
|
|
|
// Objective-C is enabled, it is highly likely that the user forgot a
|
|
|
|
// semicolon after the base expression and that the array postfix-expr is
|
|
|
|
// actually another message send. In this case, do some look-ahead to see
|
|
|
|
// if the contents of the square brackets are obviously not a valid
|
|
|
|
// expression and recover by pretending there is no suffix.
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC && Tok.isAtStartOfLine() &&
|
2010-06-01 02:18:22 +08:00
|
|
|
isSimpleObjCMessageExpression())
|
2012-08-24 05:35:17 +08:00
|
|
|
return LHS;
|
2012-04-10 09:32:12 +08:00
|
|
|
|
|
|
|
// Reject array indices starting with a lambda-expression. '[[' is
|
|
|
|
// reserved for attributes.
|
2016-02-19 15:15:33 +08:00
|
|
|
if (CheckProhibitedCXX11Attribute()) {
|
|
|
|
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
2012-04-10 09:32:12 +08:00
|
|
|
return ExprError();
|
2016-02-19 15:15:33 +08:00
|
|
|
}
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_square);
|
|
|
|
T.consumeOpen();
|
|
|
|
Loc = T.getOpenLocation();
|
2022-02-09 01:09:03 +08:00
|
|
|
ExprResult Length, Stride;
|
2020-07-10 02:27:32 +08:00
|
|
|
SourceLocation ColonLocFirst, ColonLocSecond;
|
2022-02-09 01:09:03 +08:00
|
|
|
ExprVector ArgExprs;
|
|
|
|
bool HasError = false;
|
2019-02-01 04:20:32 +08:00
|
|
|
PreferredType.enterSubscript(Actions, Tok.getLocation(), LHS.get());
|
2022-02-09 01:09:03 +08:00
|
|
|
|
|
|
|
// We try to parse a list of indexes in all language mode first
|
|
|
|
// and, in we find 0 or one index, we try to parse an OpenMP array
|
|
|
|
// section. This allow us to support C++2b multi dimensional subscript and
|
|
|
|
// OpenMp sections in the same language mode.
|
|
|
|
if (!getLangOpts().OpenMP || Tok.isNot(tok::colon)) {
|
|
|
|
if (!getLangOpts().CPlusPlus2b) {
|
|
|
|
ExprResult Idx;
|
|
|
|
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
|
|
|
|
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
|
|
|
|
Idx = ParseBraceInitializer();
|
|
|
|
} else {
|
|
|
|
Idx = ParseExpression(); // May be a comma expression
|
|
|
|
}
|
|
|
|
LHS = Actions.CorrectDelayedTyposInExpr(LHS);
|
|
|
|
Idx = Actions.CorrectDelayedTyposInExpr(Idx);
|
|
|
|
if (Idx.isInvalid()) {
|
|
|
|
HasError = true;
|
|
|
|
} else {
|
|
|
|
ArgExprs.push_back(Idx.get());
|
|
|
|
}
|
|
|
|
} else if (Tok.isNot(tok::r_square)) {
|
|
|
|
CommaLocsTy CommaLocs;
|
|
|
|
if (ParseExpressionList(ArgExprs, CommaLocs)) {
|
|
|
|
LHS = Actions.CorrectDelayedTyposInExpr(LHS);
|
|
|
|
HasError = true;
|
|
|
|
}
|
|
|
|
assert(
|
|
|
|
(ArgExprs.empty() || ArgExprs.size() == CommaLocs.size() + 1) &&
|
|
|
|
"Unexpected number of commas!");
|
2015-08-25 22:24:04 +08:00
|
|
|
}
|
2022-02-09 01:09:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ArgExprs.size() <= 1 && getLangOpts().OpenMP) {
|
|
|
|
ColonProtectionRAIIObject RAII(*this);
|
2015-08-25 22:24:04 +08:00
|
|
|
if (Tok.is(tok::colon)) {
|
|
|
|
// Consume ':'
|
2020-07-10 02:27:32 +08:00
|
|
|
ColonLocFirst = ConsumeToken();
|
|
|
|
if (Tok.isNot(tok::r_square) &&
|
|
|
|
(getLangOpts().OpenMP < 50 ||
|
2022-02-09 01:09:03 +08:00
|
|
|
((Tok.isNot(tok::colon) && getLangOpts().OpenMP >= 50)))) {
|
2015-08-25 22:24:04 +08:00
|
|
|
Length = ParseExpression();
|
2022-02-09 01:09:03 +08:00
|
|
|
Length = Actions.CorrectDelayedTyposInExpr(Length);
|
|
|
|
}
|
2015-08-25 22:24:04 +08:00
|
|
|
}
|
2020-07-10 02:27:32 +08:00
|
|
|
if (getLangOpts().OpenMP >= 50 &&
|
|
|
|
(OMPClauseKind == llvm::omp::Clause::OMPC_to ||
|
|
|
|
OMPClauseKind == llvm::omp::Clause::OMPC_from) &&
|
|
|
|
Tok.is(tok::colon)) {
|
|
|
|
// Consume ':'
|
|
|
|
ColonLocSecond = ConsumeToken();
|
|
|
|
if (Tok.isNot(tok::r_square)) {
|
|
|
|
Stride = ParseExpression();
|
|
|
|
}
|
|
|
|
}
|
2022-02-09 01:09:03 +08:00
|
|
|
}
|
2008-11-26 06:21:31 +08:00
|
|
|
|
2006-08-24 11:51:22 +08:00
|
|
|
SourceLocation RLoc = Tok.getLocation();
|
[Parser] Avoid correcting delayed typos in array subscript multiple times.
We correct some typos in `ActOnArraySubscriptExpr` and
`ActOnOMPArraySectionExpr`, so when their result is `ExprError`, we can
end up correcting delayed typos in the same expressions again. In
general it is OK but when `NumTypos` is incorrect, we can hit the
assertion
> Assertion failed: (Entry != DelayedTypos.end() && "Failed to get the state for a TypoExpr!"), function getTypoExprState, file clang/lib/Sema/SemaLookup.cpp, line 5219.
Fix by replacing some subscript `ExprResult` with typo-corrected expressions
instead of keeping the original expressions. Thus if original expressions
contained `TypoExpr`, we'll use corrected expressions instead of trying to
correct them again.
rdar://problem/47403222
Reviewers: rsmith, erik.pilkington, majnemer
Reviewed By: erik.pilkington
Subscribers: jkorous, dexonsmith, cfe-commits
Differential Revision: https://reviews.llvm.org/D60848
llvm-svn: 359713
2019-05-02 03:24:50 +08:00
|
|
|
LHS = Actions.CorrectDelayedTyposInExpr(LHS);
|
2022-02-09 01:09:03 +08:00
|
|
|
|
|
|
|
if (!LHS.isInvalid() && !HasError && !Length.isInvalid() &&
|
2020-07-10 02:27:32 +08:00
|
|
|
!Stride.isInvalid() && Tok.is(tok::r_square)) {
|
|
|
|
if (ColonLocFirst.isValid() || ColonLocSecond.isValid()) {
|
|
|
|
LHS = Actions.ActOnOMPArraySectionExpr(
|
2022-02-09 01:09:03 +08:00
|
|
|
LHS.get(), Loc, ArgExprs.empty() ? nullptr : ArgExprs[0],
|
|
|
|
ColonLocFirst, ColonLocSecond, Length.get(), Stride.get(), RLoc);
|
2015-08-25 22:24:04 +08:00
|
|
|
} else {
|
|
|
|
LHS = Actions.ActOnArraySubscriptExpr(getCurScope(), LHS.get(), Loc,
|
2022-02-09 01:09:03 +08:00
|
|
|
ArgExprs, RLoc);
|
2015-08-25 22:24:04 +08:00
|
|
|
}
|
2014-12-03 06:05:35 +08:00
|
|
|
} else {
|
2016-02-19 15:15:33 +08:00
|
|
|
LHS = ExprError();
|
2014-12-03 06:05:35 +08:00
|
|
|
}
|
2006-08-24 11:51:22 +08:00
|
|
|
|
2006-08-11 14:41:18 +08:00
|
|
|
// Match the ']'.
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2006-08-11 14:41:18 +08:00
|
|
|
break;
|
2006-08-24 11:51:22 +08:00
|
|
|
}
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2011-02-10 05:12:02 +08:00
|
|
|
case tok::l_paren: // p-e: p-e '(' argument-expression-list[opt] ')'
|
|
|
|
case tok::lesslessless: { // p-e: p-e '<<<' argument-expression-list '>>>'
|
|
|
|
// '(' argument-expression-list[opt] ')'
|
|
|
|
tok::TokenKind OpKind = Tok.getKind();
|
2010-09-15 22:51:05 +08:00
|
|
|
InMessageExpressionRAIIObject InMessage(*this, false);
|
2014-05-21 14:02:52 +08:00
|
|
|
|
|
|
|
Expr *ExecConfig = nullptr;
|
2011-02-10 05:12:02 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker PT(*this, tok::l_paren);
|
|
|
|
|
2011-02-10 05:12:02 +08:00
|
|
|
if (OpKind == tok::lesslessless) {
|
2012-08-24 06:51:59 +08:00
|
|
|
ExprVector ExecConfigExprs;
|
2011-02-10 05:12:02 +08:00
|
|
|
CommaLocsTy ExecConfigCommaLocs;
|
2012-03-08 09:00:17 +08:00
|
|
|
SourceLocation OpenLoc = ConsumeToken();
|
2011-02-10 05:12:02 +08:00
|
|
|
|
2013-08-14 07:38:34 +08:00
|
|
|
if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) {
|
2014-12-03 13:30:54 +08:00
|
|
|
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
2011-02-10 05:12:02 +08:00
|
|
|
LHS = ExprError();
|
|
|
|
}
|
|
|
|
|
2013-12-17 22:12:37 +08:00
|
|
|
SourceLocation CloseLoc;
|
|
|
|
if (TryConsumeToken(tok::greatergreatergreater, CloseLoc)) {
|
2012-03-08 09:00:17 +08:00
|
|
|
} else if (LHS.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::greatergreatergreater, StopAtSemi);
|
2012-03-08 09:00:17 +08:00
|
|
|
} else {
|
2011-10-13 00:37:45 +08:00
|
|
|
// There was an error closing the brackets
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::greatergreatergreater;
|
|
|
|
Diag(OpenLoc, diag::note_matching) << tok::lesslessless;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::greatergreatergreater, StopAtSemi);
|
2011-02-10 05:12:02 +08:00
|
|
|
LHS = ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!LHS.isInvalid()) {
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::l_paren))
|
2011-02-10 05:12:02 +08:00
|
|
|
LHS = ExprError();
|
|
|
|
else
|
|
|
|
Loc = PrevTokLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!LHS.isInvalid()) {
|
|
|
|
ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(),
|
2018-07-31 03:24:48 +08:00
|
|
|
OpenLoc,
|
|
|
|
ExecConfigExprs,
|
2012-03-08 09:00:17 +08:00
|
|
|
CloseLoc);
|
2011-02-10 05:12:02 +08:00
|
|
|
if (ECResult.isInvalid())
|
|
|
|
LHS = ExprError();
|
|
|
|
else
|
|
|
|
ExecConfig = ECResult.get();
|
|
|
|
}
|
|
|
|
} else {
|
2011-10-13 00:37:45 +08:00
|
|
|
PT.consumeOpen();
|
|
|
|
Loc = PT.getOpenLocation();
|
2011-02-10 05:12:02 +08:00
|
|
|
}
|
|
|
|
|
2012-08-24 06:51:59 +08:00
|
|
|
ExprVector ArgExprs;
|
2008-08-17 04:03:01 +08:00
|
|
|
CommaLocsTy CommaLocs;
|
2019-02-26 19:01:50 +08:00
|
|
|
auto RunSignatureHelp = [&]() -> QualType {
|
2018-09-07 22:04:39 +08:00
|
|
|
QualType PreferredType = Actions.ProduceCallSignatureHelp(
|
2022-01-04 19:36:08 +08:00
|
|
|
LHS.get(), ArgExprs, PT.getOpenLocation());
|
2018-09-10 21:46:28 +08:00
|
|
|
CalledSignatureHelp = true;
|
2019-02-26 19:01:50 +08:00
|
|
|
return PreferredType;
|
|
|
|
};
|
2011-02-10 05:12:02 +08:00
|
|
|
if (OpKind == tok::l_paren || !LHS.isInvalid()) {
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2015-01-22 00:24:11 +08:00
|
|
|
if (ParseExpressionList(ArgExprs, CommaLocs, [&] {
|
2019-02-26 19:01:50 +08:00
|
|
|
PreferredType.enterFunctionArgument(Tok.getLocation(),
|
|
|
|
RunSignatureHelp);
|
2018-08-30 21:08:03 +08:00
|
|
|
})) {
|
2014-12-03 13:30:54 +08:00
|
|
|
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
2018-09-10 21:46:28 +08:00
|
|
|
// If we got an error when parsing expression list, we don't call
|
|
|
|
// the CodeCompleteCall handler inside the parser. So call it here
|
|
|
|
// to make sure we get overload suggestions even when we are in the
|
|
|
|
// middle of a parameter.
|
2019-02-26 19:01:50 +08:00
|
|
|
if (PP.isCodeCompletionReached() && !CalledSignatureHelp)
|
|
|
|
RunSignatureHelp();
|
2011-02-10 05:12:02 +08:00
|
|
|
LHS = ExprError();
|
2015-03-27 09:44:47 +08:00
|
|
|
} else if (LHS.isInvalid()) {
|
|
|
|
for (auto &E : ArgExprs)
|
|
|
|
Actions.CorrectDelayedTyposInExpr(E);
|
2011-02-10 05:12:02 +08:00
|
|
|
}
|
2006-08-13 02:12:45 +08:00
|
|
|
}
|
2006-08-11 14:41:18 +08:00
|
|
|
}
|
2008-12-12 05:36:32 +08:00
|
|
|
|
2006-08-11 14:41:18 +08:00
|
|
|
// Match the ')'.
|
2010-09-18 09:28:11 +08:00
|
|
|
if (LHS.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2010-09-18 09:28:11 +08:00
|
|
|
} else if (Tok.isNot(tok::r_paren)) {
|
2015-05-02 08:49:18 +08:00
|
|
|
bool HadDelayedTypo = false;
|
|
|
|
if (Actions.CorrectDelayedTyposInExpr(LHS).get() != LHS.get())
|
|
|
|
HadDelayedTypo = true;
|
|
|
|
for (auto &E : ArgExprs)
|
|
|
|
if (Actions.CorrectDelayedTyposInExpr(E).get() != E)
|
|
|
|
HadDelayedTypo = true;
|
|
|
|
// If there were delayed typos in the LHS or ArgExprs, call SkipUntil
|
|
|
|
// instead of PT.consumeClose() to avoid emitting extra diagnostics for
|
|
|
|
// the unmatched l_paren.
|
|
|
|
if (HadDelayedTypo)
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
|
|
|
else
|
|
|
|
PT.consumeClose();
|
2010-09-18 09:28:11 +08:00
|
|
|
LHS = ExprError();
|
|
|
|
} else {
|
[AST] Add RecoveryExpr to retain expressions on semantic errors
Normally clang avoids creating expressions when it encounters semantic
errors, even if the parser knows which expression to produce.
This works well for the compiler. However, this is not ideal for
source-level tools that have to deal with broken code, e.g. clangd is
not able to provide navigation features even for names that compiler
knows how to resolve.
The new RecoveryExpr aims to capture the minimal set of information
useful for the tools that need to deal with incorrect code:
source range of the expression being dropped,
subexpressions of the expression.
We aim to make constructing RecoveryExprs as simple as possible to
ensure writing code to avoid dropping expressions is easy.
Producing RecoveryExprs can result in new code paths being taken in the
frontend. In particular, clang can produce some new diagnostics now and
we aim to suppress bogus ones based on Expr::containsErrors.
We deliberately produce RecoveryExprs only in the parser for now to
minimize the code affected by this patch. Producing RecoveryExprs in
Sema potentially allows to preserve more information (e.g. type of an
expression), but also results in more code being affected. E.g.
SFINAE checks will have to take presence of RecoveryExprs into account.
Initial implementation only works in C++ mode, as it relies on compiler
postponing diagnostics on dependent expressions. C and ObjC often do not
do this, so they require more work to make sure we do not produce too
many bogus diagnostics on the new expressions.
See documentation of RecoveryExpr for more details.
original patch from Ilya
This change is based on https://reviews.llvm.org/D61722
Reviewers: sammccall, rsmith
Reviewed By: sammccall, rsmith
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 23:30:40 +08:00
|
|
|
assert(
|
|
|
|
(ArgExprs.size() == 0 || ArgExprs.size() - 1 == CommaLocs.size()) &&
|
|
|
|
"Unexpected number of commas!");
|
|
|
|
Expr *Fn = LHS.get();
|
|
|
|
SourceLocation RParLoc = Tok.getLocation();
|
|
|
|
LHS = Actions.ActOnCallExpr(getCurScope(), Fn, Loc, ArgExprs, RParLoc,
|
2011-02-10 05:12:02 +08:00
|
|
|
ExecConfig);
|
[AST] Add RecoveryExpr to retain expressions on semantic errors
Normally clang avoids creating expressions when it encounters semantic
errors, even if the parser knows which expression to produce.
This works well for the compiler. However, this is not ideal for
source-level tools that have to deal with broken code, e.g. clangd is
not able to provide navigation features even for names that compiler
knows how to resolve.
The new RecoveryExpr aims to capture the minimal set of information
useful for the tools that need to deal with incorrect code:
source range of the expression being dropped,
subexpressions of the expression.
We aim to make constructing RecoveryExprs as simple as possible to
ensure writing code to avoid dropping expressions is easy.
Producing RecoveryExprs can result in new code paths being taken in the
frontend. In particular, clang can produce some new diagnostics now and
we aim to suppress bogus ones based on Expr::containsErrors.
We deliberately produce RecoveryExprs only in the parser for now to
minimize the code affected by this patch. Producing RecoveryExprs in
Sema potentially allows to preserve more information (e.g. type of an
expression), but also results in more code being affected. E.g.
SFINAE checks will have to take presence of RecoveryExprs into account.
Initial implementation only works in C++ mode, as it relies on compiler
postponing diagnostics on dependent expressions. C and ObjC often do not
do this, so they require more work to make sure we do not produce too
many bogus diagnostics on the new expressions.
See documentation of RecoveryExpr for more details.
original patch from Ilya
This change is based on https://reviews.llvm.org/D61722
Reviewers: sammccall, rsmith
Reviewed By: sammccall, rsmith
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 23:30:40 +08:00
|
|
|
if (LHS.isInvalid()) {
|
|
|
|
ArgExprs.insert(ArgExprs.begin(), Fn);
|
|
|
|
LHS =
|
|
|
|
Actions.CreateRecoveryExpr(Fn->getBeginLoc(), RParLoc, ArgExprs);
|
|
|
|
}
|
2011-10-13 00:37:45 +08:00
|
|
|
PT.consumeClose();
|
2006-08-24 12:40:38 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-08-11 14:41:18 +08:00
|
|
|
break;
|
2006-08-24 11:51:22 +08:00
|
|
|
}
|
2009-09-09 08:23:06 +08:00
|
|
|
case tok::arrow:
|
|
|
|
case tok::period: {
|
|
|
|
// postfix-expression: p-e '->' template[opt] id-expression
|
|
|
|
// postfix-expression: p-e '.' template[opt] id-expression
|
2006-08-24 11:51:22 +08:00
|
|
|
tok::TokenKind OpKind = Tok.getKind();
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token.
|
2008-12-12 05:36:32 +08:00
|
|
|
|
2009-08-06 11:17:00 +08:00
|
|
|
CXXScopeSpec SS;
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType ObjectType;
|
Rework parsing of pseudo-destructor expressions and explicit
destructor calls, e.g.,
p->T::~T
We now detect when the member access that we've parsed, e.g.,
p-> or x.
may be a pseudo-destructor expression, either because the type of p or
x is a scalar or because it is dependent (and, therefore, may become a
scalar at template instantiation time).
We then parse the pseudo-destructor grammar specifically:
::[opt] nested-name-specifier[opt] type-name :: ∼ type-name
and hand those results to a new action, ActOnPseudoDestructorExpr,
which will cope with both dependent member accesses of destructors and
with pseudo-destructor expressions.
This commit affects the parsing of pseudo-destructors, only; the
semantic actions still go through the semantic actions for member
access expressions. That will change soon.
llvm-svn: 97045
2010-02-25 02:44:31 +08:00
|
|
|
bool MayBePseudoDestructor = false;
|
2018-05-25 20:56:26 +08:00
|
|
|
Expr* OrigLHS = !LHS.isInvalid() ? LHS.get() : nullptr;
|
|
|
|
|
2019-02-01 04:20:32 +08:00
|
|
|
PreferredType.enterMemAccess(Actions, Tok.getLocation(), OrigLHS);
|
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus && !LHS.isInvalid()) {
|
2018-05-25 20:56:26 +08:00
|
|
|
Expr *Base = OrigLHS;
|
2013-07-13 05:43:02 +08:00
|
|
|
const Type* BaseType = Base->getType().getTypePtrOrNull();
|
|
|
|
if (BaseType && Tok.is(tok::l_paren) &&
|
|
|
|
(BaseType->isFunctionType() ||
|
2013-10-10 20:24:40 +08:00
|
|
|
BaseType->isSpecificPlaceholderType(BuiltinType::BoundMember))) {
|
2013-07-13 05:43:02 +08:00
|
|
|
Diag(OpLoc, diag::err_function_is_not_record)
|
2014-01-06 19:30:41 +08:00
|
|
|
<< OpKind << Base->getSourceRange()
|
|
|
|
<< FixItHint::CreateRemoval(OpLoc);
|
2013-07-13 05:43:02 +08:00
|
|
|
return ParsePostfixExpressionSuffix(Base);
|
|
|
|
}
|
|
|
|
|
2020-04-07 01:13:08 +08:00
|
|
|
LHS = Actions.ActOnStartCXXMemberReference(getCurScope(), Base, OpLoc,
|
|
|
|
OpKind, ObjectType,
|
Rework parsing of pseudo-destructor expressions and explicit
destructor calls, e.g.,
p->T::~T
We now detect when the member access that we've parsed, e.g.,
p-> or x.
may be a pseudo-destructor expression, either because the type of p or
x is a scalar or because it is dependent (and, therefore, may become a
scalar at template instantiation time).
We then parse the pseudo-destructor grammar specifically:
::[opt] nested-name-specifier[opt] type-name :: ∼ type-name
and hand those results to a new action, ActOnPseudoDestructorExpr,
which will cope with both dependent member accesses of destructors and
with pseudo-destructor expressions.
This commit affects the parsing of pseudo-destructors, only; the
semantic actions still go through the semantic actions for member
access expressions. That will change soon.
llvm-svn: 97045
2010-02-25 02:44:31 +08:00
|
|
|
MayBePseudoDestructor);
|
2020-04-07 01:13:08 +08:00
|
|
|
if (LHS.isInvalid()) {
|
|
|
|
// Clang will try to perform expression based completion as a
|
|
|
|
// fallback, which is confusing in case of member references. So we
|
|
|
|
// stop here without any completions.
|
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
cutOffParsing();
|
|
|
|
return ExprError();
|
|
|
|
}
|
2009-08-06 11:17:00 +08:00
|
|
|
break;
|
2020-04-07 01:13:08 +08:00
|
|
|
}
|
2020-03-19 16:12:29 +08:00
|
|
|
ParseOptionalCXXScopeSpecifier(
|
|
|
|
SS, ObjectType, LHS.get() && LHS.get()->containsErrors(),
|
|
|
|
/*EnteringContext=*/false, &MayBePseudoDestructor);
|
2010-05-27 23:25:59 +08:00
|
|
|
if (SS.isNotEmpty())
|
2016-01-16 07:43:34 +08:00
|
|
|
ObjectType = nullptr;
|
2009-08-06 11:17:00 +08:00
|
|
|
}
|
|
|
|
|
Initial implementation of a code-completion interface in Clang. In
essence, code completion is triggered by a magic "code completion"
token produced by the lexer [*], which the parser recognizes at
certain points in the grammar. The parser then calls into the Action
object with the appropriate CodeCompletionXXX action.
Sema implements the CodeCompletionXXX callbacks by performing minimal
translation, then forwarding them to a CodeCompletionConsumer
subclass, which uses the results of semantic analysis to provide
code-completion results. At present, only a single, "printing" code
completion consumer is available, for regression testing and
debugging. However, the design is meant to permit other
code-completion consumers.
This initial commit contains two code-completion actions: one for
member access, e.g., "x." or "p->", and one for
nested-name-specifiers, e.g., "std::". More code-completion actions
will follow, along with improved gathering of code-completion results
for the various contexts.
[*] In the current -code-completion-dump testing/debugging mode, the
file is truncated at the completion point and EOF is translated into
"code completion".
llvm-svn: 82166
2009-09-18 05:32:03 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2018-05-25 20:56:26 +08:00
|
|
|
tok::TokenKind CorrectedOpKind =
|
|
|
|
OpKind == tok::arrow ? tok::period : tok::arrow;
|
2019-07-16 12:46:31 +08:00
|
|
|
ExprResult CorrectedLHS(/*Invalid=*/true);
|
2018-05-25 20:56:26 +08:00
|
|
|
if (getLangOpts().CPlusPlus && OrigLHS) {
|
2019-08-17 03:53:22 +08:00
|
|
|
// FIXME: Creating a TentativeAnalysisScope from outside Sema is a
|
|
|
|
// hack.
|
|
|
|
Sema::TentativeAnalysisScope Trap(Actions);
|
2018-05-25 20:56:26 +08:00
|
|
|
CorrectedLHS = Actions.ActOnStartCXXMemberReference(
|
|
|
|
getCurScope(), OrigLHS, OpLoc, CorrectedOpKind, ObjectType,
|
|
|
|
MayBePseudoDestructor);
|
|
|
|
}
|
|
|
|
|
|
|
|
Expr *Base = LHS.get();
|
|
|
|
Expr *CorrectedBase = CorrectedLHS.get();
|
2018-09-21 19:23:22 +08:00
|
|
|
if (!CorrectedBase && !getLangOpts().CPlusPlus)
|
|
|
|
CorrectedBase = Base;
|
2018-05-25 20:56:26 +08:00
|
|
|
|
Initial implementation of a code-completion interface in Clang. In
essence, code completion is triggered by a magic "code completion"
token produced by the lexer [*], which the parser recognizes at
certain points in the grammar. The parser then calls into the Action
object with the appropriate CodeCompletionXXX action.
Sema implements the CodeCompletionXXX callbacks by performing minimal
translation, then forwarding them to a CodeCompletionConsumer
subclass, which uses the results of semantic analysis to provide
code-completion results. At present, only a single, "printing" code
completion consumer is available, for regression testing and
debugging. However, the design is meant to permit other
code-completion consumers.
This initial commit contains two code-completion actions: one for
member access, e.g., "x." or "p->", and one for
nested-name-specifiers, e.g., "std::". More code-completion actions
will follow, along with improved gathering of code-completion results
for the various contexts.
[*] In the current -code-completion-dump testing/debugging mode, the
file is truncated at the completion point and EOF is translated into
"code completion".
llvm-svn: 82166
2009-09-18 05:32:03 +08:00
|
|
|
// Code completion for a member access expression.
|
2021-03-12 19:00:54 +08:00
|
|
|
cutOffParsing();
|
2018-05-25 20:56:26 +08:00
|
|
|
Actions.CodeCompleteMemberReferenceExpr(
|
|
|
|
getCurScope(), Base, CorrectedBase, OpLoc, OpKind == tok::arrow,
|
2019-02-01 04:20:32 +08:00
|
|
|
Base && ExprStatementTokLoc == Base->getBeginLoc(),
|
|
|
|
PreferredType.get(Tok.getLocation()));
|
2016-10-18 18:55:01 +08:00
|
|
|
|
2011-09-04 11:32:15 +08:00
|
|
|
return ExprError();
|
Initial implementation of a code-completion interface in Clang. In
essence, code completion is triggered by a magic "code completion"
token produced by the lexer [*], which the parser recognizes at
certain points in the grammar. The parser then calls into the Action
object with the appropriate CodeCompletionXXX action.
Sema implements the CodeCompletionXXX callbacks by performing minimal
translation, then forwarding them to a CodeCompletionConsumer
subclass, which uses the results of semantic analysis to provide
code-completion results. At present, only a single, "printing" code
completion consumer is available, for regression testing and
debugging. However, the design is meant to permit other
code-completion consumers.
This initial commit contains two code-completion actions: one for
member access, e.g., "x." or "p->", and one for
nested-name-specifiers, e.g., "std::". More code-completion actions
will follow, along with improved gathering of code-completion results
for the various contexts.
[*] In the current -code-completion-dump testing/debugging mode, the
file is truncated at the completion point and EOF is translated into
"code completion".
llvm-svn: 82166
2009-09-18 05:32:03 +08:00
|
|
|
}
|
2015-02-17 05:21:12 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
if (MayBePseudoDestructor && !LHS.isInvalid()) {
|
2018-07-31 03:24:48 +08:00
|
|
|
LHS = ParseCXXPseudoDestructor(LHS.get(), OpLoc, OpKind, SS,
|
Rework parsing of pseudo-destructor expressions and explicit
destructor calls, e.g.,
p->T::~T
We now detect when the member access that we've parsed, e.g.,
p-> or x.
may be a pseudo-destructor expression, either because the type of p or
x is a scalar or because it is dependent (and, therefore, may become a
scalar at template instantiation time).
We then parse the pseudo-destructor grammar specifically:
::[opt] nested-name-specifier[opt] type-name :: ∼ type-name
and hand those results to a new action, ActOnPseudoDestructorExpr,
which will cope with both dependent member accesses of destructors and
with pseudo-destructor expressions.
This commit affects the parsing of pseudo-destructors, only; the
semantic actions still go through the semantic actions for member
access expressions. That will change soon.
llvm-svn: 97045
2010-02-25 02:44:31 +08:00
|
|
|
ObjectType);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-02-17 05:21:12 +08:00
|
|
|
// Either the action has told us that this cannot be a
|
Rework parsing of pseudo-destructor expressions and explicit
destructor calls, e.g.,
p->T::~T
We now detect when the member access that we've parsed, e.g.,
p-> or x.
may be a pseudo-destructor expression, either because the type of p or
x is a scalar or because it is dependent (and, therefore, may become a
scalar at template instantiation time).
We then parse the pseudo-destructor grammar specifically:
::[opt] nested-name-specifier[opt] type-name :: ∼ type-name
and hand those results to a new action, ActOnPseudoDestructorExpr,
which will cope with both dependent member accesses of destructors and
with pseudo-destructor expressions.
This commit affects the parsing of pseudo-destructors, only; the
semantic actions still go through the semantic actions for member
access expressions. That will change soon.
llvm-svn: 97045
2010-02-25 02:44:31 +08:00
|
|
|
// pseudo-destructor expression (based on the type of base
|
|
|
|
// expression), or we didn't see a '~' in the right place. We
|
|
|
|
// can still parse a destructor name here, but in that case it
|
|
|
|
// names a real destructor.
|
2011-01-18 13:04:39 +08:00
|
|
|
// Allow explicit constructor calls in Microsoft mode.
|
|
|
|
// FIXME: Add support for explicit call of template constructor.
|
2012-01-27 17:46:47 +08:00
|
|
|
SourceLocation TemplateKWLoc;
|
2009-11-04 03:44:04 +08:00
|
|
|
UnqualifiedId Name;
|
2018-10-31 04:31:30 +08:00
|
|
|
if (getLangOpts().ObjC && OpKind == tok::period &&
|
2015-02-02 13:38:59 +08:00
|
|
|
Tok.is(tok::kw_class)) {
|
2012-02-17 02:19:22 +08:00
|
|
|
// Objective-C++:
|
|
|
|
// After a '.' in a member access expression, treat the keyword
|
|
|
|
// 'class' as if it were an identifier.
|
|
|
|
//
|
|
|
|
// This hack allows property access to the 'class' method because it is
|
2018-07-31 03:24:48 +08:00
|
|
|
// such a common method name. For other C++ keywords that are
|
2012-02-17 02:19:22 +08:00
|
|
|
// Objective-C method names, one must use the message send syntax.
|
|
|
|
IdentifierInfo *Id = Tok.getIdentifierInfo();
|
|
|
|
SourceLocation Loc = ConsumeToken();
|
|
|
|
Name.setIdentifier(Id, Loc);
|
2020-03-19 16:12:29 +08:00
|
|
|
} else if (ParseUnqualifiedId(
|
|
|
|
SS, ObjectType, LHS.get() && LHS.get()->containsErrors(),
|
|
|
|
/*EnteringContext=*/false,
|
|
|
|
/*AllowDestructorName=*/true,
|
|
|
|
/*AllowConstructorName=*/
|
|
|
|
getLangOpts().MicrosoftExt && SS.isNotEmpty(),
|
|
|
|
/*AllowDeductionGuide=*/false, &TemplateKWLoc, Name)) {
|
2014-12-03 06:05:35 +08:00
|
|
|
(void)Actions.CorrectDelayedTyposInExpr(LHS);
|
2010-09-18 09:28:11 +08:00
|
|
|
LHS = ExprError();
|
2014-12-03 06:05:35 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-11-04 03:44:04 +08:00
|
|
|
if (!LHS.isInvalid())
|
2018-07-31 03:24:48 +08:00
|
|
|
LHS = Actions.ActOnMemberAccessExpr(getCurScope(), LHS.get(), OpLoc,
|
2012-01-27 17:46:47 +08:00
|
|
|
OpKind, SS, TemplateKWLoc, Name,
|
2014-05-21 14:02:52 +08:00
|
|
|
CurParsedObjCImpl ? CurParsedObjCImpl->Dcl
|
2015-02-26 01:36:15 +08:00
|
|
|
: nullptr);
|
2020-03-25 19:43:53 +08:00
|
|
|
if (!LHS.isInvalid()) {
|
|
|
|
if (Tok.is(tok::less))
|
|
|
|
checkPotentialAngleBracket(LHS);
|
|
|
|
} else if (OrigLHS && Name.isValid()) {
|
|
|
|
// Preserve the LHS if the RHS is an invalid member.
|
|
|
|
LHS = Actions.CreateRecoveryExpr(OrigLHS->getBeginLoc(),
|
|
|
|
Name.getEndLoc(), {OrigLHS});
|
|
|
|
}
|
2006-08-11 14:41:18 +08:00
|
|
|
break;
|
2006-08-24 11:51:22 +08:00
|
|
|
}
|
2006-08-11 14:41:18 +08:00
|
|
|
case tok::plusplus: // postfix-expression: postfix-expression '++'
|
|
|
|
case tok::minusminus: // postfix-expression: postfix-expression '--'
|
2008-12-09 21:15:23 +08:00
|
|
|
if (!LHS.isInvalid()) {
|
[AST] Add RecoveryExpr to retain expressions on semantic errors
Normally clang avoids creating expressions when it encounters semantic
errors, even if the parser knows which expression to produce.
This works well for the compiler. However, this is not ideal for
source-level tools that have to deal with broken code, e.g. clangd is
not able to provide navigation features even for names that compiler
knows how to resolve.
The new RecoveryExpr aims to capture the minimal set of information
useful for the tools that need to deal with incorrect code:
source range of the expression being dropped,
subexpressions of the expression.
We aim to make constructing RecoveryExprs as simple as possible to
ensure writing code to avoid dropping expressions is easy.
Producing RecoveryExprs can result in new code paths being taken in the
frontend. In particular, clang can produce some new diagnostics now and
we aim to suppress bogus ones based on Expr::containsErrors.
We deliberately produce RecoveryExprs only in the parser for now to
minimize the code affected by this patch. Producing RecoveryExprs in
Sema potentially allows to preserve more information (e.g. type of an
expression), but also results in more code being affected. E.g.
SFINAE checks will have to take presence of RecoveryExprs into account.
Initial implementation only works in C++ mode, as it relies on compiler
postponing diagnostics on dependent expressions. C and ObjC often do not
do this, so they require more work to make sure we do not produce too
many bogus diagnostics on the new expressions.
See documentation of RecoveryExpr for more details.
original patch from Ilya
This change is based on https://reviews.llvm.org/D61722
Reviewers: sammccall, rsmith
Reviewed By: sammccall, rsmith
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 23:30:40 +08:00
|
|
|
Expr *Arg = LHS.get();
|
2010-07-03 01:43:08 +08:00
|
|
|
LHS = Actions.ActOnPostfixUnaryOp(getCurScope(), Tok.getLocation(),
|
[AST] Add RecoveryExpr to retain expressions on semantic errors
Normally clang avoids creating expressions when it encounters semantic
errors, even if the parser knows which expression to produce.
This works well for the compiler. However, this is not ideal for
source-level tools that have to deal with broken code, e.g. clangd is
not able to provide navigation features even for names that compiler
knows how to resolve.
The new RecoveryExpr aims to capture the minimal set of information
useful for the tools that need to deal with incorrect code:
source range of the expression being dropped,
subexpressions of the expression.
We aim to make constructing RecoveryExprs as simple as possible to
ensure writing code to avoid dropping expressions is easy.
Producing RecoveryExprs can result in new code paths being taken in the
frontend. In particular, clang can produce some new diagnostics now and
we aim to suppress bogus ones based on Expr::containsErrors.
We deliberately produce RecoveryExprs only in the parser for now to
minimize the code affected by this patch. Producing RecoveryExprs in
Sema potentially allows to preserve more information (e.g. type of an
expression), but also results in more code being affected. E.g.
SFINAE checks will have to take presence of RecoveryExprs into account.
Initial implementation only works in C++ mode, as it relies on compiler
postponing diagnostics on dependent expressions. C and ObjC often do not
do this, so they require more work to make sure we do not produce too
many bogus diagnostics on the new expressions.
See documentation of RecoveryExpr for more details.
original patch from Ilya
This change is based on https://reviews.llvm.org/D61722
Reviewers: sammccall, rsmith
Reviewed By: sammccall, rsmith
Tags: #clang
Differential Revision: https://reviews.llvm.org/D69330
2020-03-19 23:30:40 +08:00
|
|
|
Tok.getKind(), Arg);
|
|
|
|
if (LHS.isInvalid())
|
|
|
|
LHS = Actions.CreateRecoveryExpr(Arg->getBeginLoc(),
|
|
|
|
Tok.getLocation(), Arg);
|
2008-11-26 06:21:31 +08:00
|
|
|
}
|
2006-08-11 14:41:18 +08:00
|
|
|
ConsumeToken();
|
|
|
|
break;
|
2006-08-11 06:01:51 +08:00
|
|
|
}
|
|
|
|
}
|
2006-08-11 04:56:00 +08:00
|
|
|
}
|
|
|
|
|
2011-03-12 03:24:49 +08:00
|
|
|
/// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/
|
|
|
|
/// vec_step and we are at the start of an expression or a parenthesized
|
|
|
|
/// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the
|
|
|
|
/// expression (isCastExpr == false) or the type (isCastExpr == true).
|
2009-05-22 18:22:50 +08:00
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2006-08-11 10:13:20 +08:00
|
|
|
/// unary-expression: [C99 6.5.3]
|
|
|
|
/// 'sizeof' unary-expression
|
|
|
|
/// 'sizeof' '(' type-name ')'
|
|
|
|
/// [GNU] '__alignof' unary-expression
|
|
|
|
/// [GNU] '__alignof' '(' type-name ')'
|
2012-07-01 05:33:57 +08:00
|
|
|
/// [C11] '_Alignof' '(' type-name ')'
|
2008-11-06 23:17:27 +08:00
|
|
|
/// [C++0x] 'alignof' '(' type-id ')'
|
2009-05-22 18:22:50 +08:00
|
|
|
///
|
|
|
|
/// [GNU] typeof-specifier:
|
|
|
|
/// typeof ( expressions )
|
|
|
|
/// typeof ( type-name )
|
|
|
|
/// [GNU/C++] typeof unary-expression
|
|
|
|
///
|
2011-03-12 03:24:49 +08:00
|
|
|
/// [OpenCL 1.1 6.11.12] vec_step built-in function:
|
|
|
|
/// vec_step ( expressions )
|
|
|
|
/// vec_step ( type-name )
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2011-03-12 03:24:49 +08:00
|
|
|
Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
|
|
|
|
bool &isCastExpr,
|
|
|
|
ParsedType &CastTy,
|
|
|
|
SourceRange &CastRange) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2015-07-02 11:40:19 +08:00
|
|
|
assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_sizeof, tok::kw___alignof,
|
|
|
|
tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step,
|
|
|
|
tok::kw___builtin_omp_required_simd_align) &&
|
2015-06-18 18:59:26 +08:00
|
|
|
"Not a typeof/sizeof/alignof/vec_step expression!");
|
2009-05-22 18:22:50 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Operand;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-22 18:22:50 +08:00
|
|
|
// If the operand doesn't start with an '(', it must be an expression.
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::l_paren)) {
|
2013-10-09 00:56:30 +08:00
|
|
|
// If construct allows a form without parenthesis, user may forget to put
|
|
|
|
// pathenthesis around type name.
|
2015-06-18 18:59:26 +08:00
|
|
|
if (OpTok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof,
|
|
|
|
tok::kw__Alignof)) {
|
2014-01-15 09:53:39 +08:00
|
|
|
if (isTypeIdUnambiguously()) {
|
2013-10-09 00:56:30 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
|
|
|
ParseSpecifierQualifierList(DS);
|
2020-11-11 13:40:12 +08:00
|
|
|
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
2013-10-09 00:56:30 +08:00
|
|
|
ParseDeclarator(DeclaratorInfo);
|
|
|
|
|
|
|
|
SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation());
|
|
|
|
SourceLocation RParenLoc = PP.getLocForEndOfToken(PrevTokLocation);
|
2020-12-17 04:01:54 +08:00
|
|
|
if (LParenLoc.isInvalid() || RParenLoc.isInvalid()) {
|
|
|
|
Diag(OpTok.getLocation(),
|
|
|
|
diag::err_expected_parentheses_around_typename)
|
|
|
|
<< OpTok.getName();
|
|
|
|
} else {
|
|
|
|
Diag(LParenLoc, diag::err_expected_parentheses_around_typename)
|
|
|
|
<< OpTok.getName() << FixItHint::CreateInsertion(LParenLoc, "(")
|
|
|
|
<< FixItHint::CreateInsertion(RParenLoc, ")");
|
|
|
|
}
|
2013-10-09 00:56:30 +08:00
|
|
|
isCastExpr = true;
|
|
|
|
return ExprEmpty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-22 18:22:50 +08:00
|
|
|
isCastExpr = false;
|
2012-03-11 15:00:24 +08:00
|
|
|
if (OpTok.is(tok::kw_typeof) && !getLangOpts().CPlusPlus) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected_after) << OpTok.getIdentifierInfo()
|
|
|
|
<< tok::l_paren;
|
2009-05-22 18:22:50 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2020-01-09 21:07:51 +08:00
|
|
|
Operand = ParseCastExpression(UnaryExprOnly);
|
2006-08-24 14:10:04 +08:00
|
|
|
} else {
|
|
|
|
// If it starts with a '(', we know that it is either a parenthesized
|
|
|
|
// type-name, or it is a unary-expression that starts with a compound
|
|
|
|
// literal, or starts with a primary-expression that is a parenthesized
|
|
|
|
// expression.
|
|
|
|
ParenParseOption ExprType = CastExpr;
|
2006-08-24 14:49:19 +08:00
|
|
|
SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
|
2011-07-02 06:22:59 +08:00
|
|
|
false, CastTy, RParenLoc);
|
2009-05-22 18:22:50 +08:00
|
|
|
CastRange = SourceRange(LParenLoc, RParenLoc);
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2009-05-22 18:22:50 +08:00
|
|
|
// If ParseParenExpression parsed a '(typename)' sequence only, then this is
|
|
|
|
// a type.
|
|
|
|
if (ExprType == CastExpr) {
|
|
|
|
isCastExpr = true;
|
|
|
|
return ExprEmpty();
|
|
|
|
}
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2012-03-11 15:00:24 +08:00
|
|
|
if (getLangOpts().CPlusPlus || OpTok.isNot(tok::kw_typeof)) {
|
2010-07-29 02:22:12 +08:00
|
|
|
// GNU typeof in C requires the expression to be parenthesized. Not so for
|
|
|
|
// sizeof/alignof or in C++. Therefore, the parenthesized expression is
|
2018-07-31 03:24:48 +08:00
|
|
|
// the start of a unary-expression, but doesn't include any postfix
|
2010-07-29 02:22:12 +08:00
|
|
|
// pieces. Parse these now if present.
|
2010-08-25 07:41:43 +08:00
|
|
|
if (!Operand.isInvalid())
|
|
|
|
Operand = ParsePostfixExpressionSuffix(Operand.get());
|
2010-07-29 02:22:12 +08:00
|
|
|
}
|
2006-08-24 14:10:04 +08:00
|
|
|
}
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2017-07-02 14:12:49 +08:00
|
|
|
// If we get here, the operand to the typeof/sizeof/alignof was an expression.
|
2009-05-22 18:22:50 +08:00
|
|
|
isCastExpr = false;
|
2012-08-24 05:35:17 +08:00
|
|
|
return Operand;
|
2009-05-22 18:22:50 +08:00
|
|
|
}
|
|
|
|
|
2021-04-23 23:22:35 +08:00
|
|
|
/// Parse a __builtin_sycl_unique_stable_name expression. Accepts a type-id as
|
|
|
|
/// a parameter.
|
|
|
|
ExprResult Parser::ParseSYCLUniqueStableNameExpression() {
|
|
|
|
assert(Tok.is(tok::kw___builtin_sycl_unique_stable_name) &&
|
2021-08-18 17:42:12 +08:00
|
|
|
"Not __builtin_sycl_unique_stable_name");
|
2021-04-23 23:22:35 +08:00
|
|
|
|
|
|
|
SourceLocation OpLoc = ConsumeToken();
|
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
|
|
|
|
// __builtin_sycl_unique_stable_name expressions are always parenthesized.
|
|
|
|
if (T.expectAndConsume(diag::err_expected_lparen_after,
|
|
|
|
"__builtin_sycl_unique_stable_name"))
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
TypeResult Ty = ParseTypeName();
|
|
|
|
|
|
|
|
if (Ty.isInvalid()) {
|
|
|
|
T.skipToEnd();
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (T.consumeClose())
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
return Actions.ActOnSYCLUniqueStableNameExpr(OpLoc, T.getOpenLocation(),
|
|
|
|
T.getCloseLocation(), Ty.get());
|
|
|
|
}
|
2009-05-22 18:22:50 +08:00
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse a sizeof or alignof expression.
|
2012-06-17 12:36:28 +08:00
|
|
|
///
|
|
|
|
/// \verbatim
|
2009-05-22 18:22:50 +08:00
|
|
|
/// unary-expression: [C99 6.5.3]
|
|
|
|
/// 'sizeof' unary-expression
|
|
|
|
/// 'sizeof' '(' type-name ')'
|
2013-01-29 18:18:18 +08:00
|
|
|
/// [C++11] 'sizeof' '...' '(' identifier ')'
|
2009-05-22 18:22:50 +08:00
|
|
|
/// [GNU] '__alignof' unary-expression
|
|
|
|
/// [GNU] '__alignof' '(' type-name ')'
|
2012-07-01 05:33:57 +08:00
|
|
|
/// [C11] '_Alignof' '(' type-name ')'
|
2013-01-29 18:18:18 +08:00
|
|
|
/// [C++11] 'alignof' '(' type-id ')'
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2011-03-12 03:24:49 +08:00
|
|
|
ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
|
2015-06-18 18:59:26 +08:00
|
|
|
assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof,
|
2015-07-02 11:40:19 +08:00
|
|
|
tok::kw__Alignof, tok::kw_vec_step,
|
|
|
|
tok::kw___builtin_omp_required_simd_align) &&
|
2011-03-12 03:24:49 +08:00
|
|
|
"Not a sizeof/alignof/vec_step expression!");
|
2009-05-22 18:22:50 +08:00
|
|
|
Token OpTok = Tok;
|
|
|
|
ConsumeToken();
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2013-01-29 18:18:18 +08:00
|
|
|
// [C++11] 'sizeof' '...' '(' identifier ')'
|
2011-01-05 01:33:58 +08:00
|
|
|
if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) {
|
|
|
|
SourceLocation EllipsisLoc = ConsumeToken();
|
|
|
|
SourceLocation LParenLoc, RParenLoc;
|
2014-05-21 14:02:52 +08:00
|
|
|
IdentifierInfo *Name = nullptr;
|
2011-01-05 01:33:58 +08:00
|
|
|
SourceLocation NameLoc;
|
|
|
|
if (Tok.is(tok::l_paren)) {
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
T.consumeOpen();
|
|
|
|
LParenLoc = T.getOpenLocation();
|
2011-01-05 01:33:58 +08:00
|
|
|
if (Tok.is(tok::identifier)) {
|
|
|
|
Name = Tok.getIdentifierInfo();
|
|
|
|
NameLoc = ConsumeToken();
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
|
|
|
RParenLoc = T.getCloseLocation();
|
2011-01-05 01:33:58 +08:00
|
|
|
if (RParenLoc.isInvalid())
|
|
|
|
RParenLoc = PP.getLocForEndOfToken(NameLoc);
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_expected_parameter_pack);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-01-05 01:33:58 +08:00
|
|
|
}
|
|
|
|
} else if (Tok.is(tok::identifier)) {
|
|
|
|
Name = Tok.getIdentifierInfo();
|
|
|
|
NameLoc = ConsumeToken();
|
|
|
|
LParenLoc = PP.getLocForEndOfToken(EllipsisLoc);
|
|
|
|
RParenLoc = PP.getLocForEndOfToken(NameLoc);
|
|
|
|
Diag(LParenLoc, diag::err_paren_sizeof_parameter_pack)
|
|
|
|
<< Name
|
|
|
|
<< FixItHint::CreateInsertion(LParenLoc, "(")
|
|
|
|
<< FixItHint::CreateInsertion(RParenLoc, ")");
|
|
|
|
} else {
|
|
|
|
Diag(Tok, diag::err_sizeof_parameter_pack);
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-01-05 01:33:58 +08:00
|
|
|
if (!Name)
|
|
|
|
return ExprError();
|
2017-04-02 05:30:49 +08:00
|
|
|
|
|
|
|
EnterExpressionEvaluationContext Unevaluated(
|
|
|
|
Actions, Sema::ExpressionEvaluationContext::Unevaluated,
|
|
|
|
Sema::ReuseLambdaContextDecl);
|
2013-10-31 23:58:51 +08:00
|
|
|
|
2011-01-05 01:33:58 +08:00
|
|
|
return Actions.ActOnSizeofParameterPackExpr(getCurScope(),
|
2018-07-31 03:24:48 +08:00
|
|
|
OpTok.getLocation(),
|
2011-01-05 01:33:58 +08:00
|
|
|
*Name, NameLoc,
|
|
|
|
RParenLoc);
|
|
|
|
}
|
2011-10-18 07:06:20 +08:00
|
|
|
|
2015-06-18 18:59:26 +08:00
|
|
|
if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
|
2011-10-18 07:06:20 +08:00
|
|
|
Diag(OpTok, diag::warn_cxx98_compat_alignof);
|
|
|
|
|
2017-04-02 05:30:49 +08:00
|
|
|
EnterExpressionEvaluationContext Unevaluated(
|
|
|
|
Actions, Sema::ExpressionEvaluationContext::Unevaluated,
|
|
|
|
Sema::ReuseLambdaContextDecl);
|
2012-01-21 09:01:51 +08:00
|
|
|
|
2009-05-22 18:22:50 +08:00
|
|
|
bool isCastExpr;
|
2010-08-24 13:47:05 +08:00
|
|
|
ParsedType CastTy;
|
2009-05-22 18:22:50 +08:00
|
|
|
SourceRange CastRange;
|
2011-03-12 03:24:49 +08:00
|
|
|
ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok,
|
|
|
|
isCastExpr,
|
|
|
|
CastTy,
|
|
|
|
CastRange);
|
|
|
|
|
|
|
|
UnaryExprOrTypeTrait ExprKind = UETT_SizeOf;
|
2018-10-27 03:26:45 +08:00
|
|
|
if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
|
2011-03-12 03:24:49 +08:00
|
|
|
ExprKind = UETT_AlignOf;
|
2018-10-27 03:26:45 +08:00
|
|
|
else if (OpTok.is(tok::kw___alignof))
|
|
|
|
ExprKind = UETT_PreferredAlignOf;
|
2011-03-12 03:24:49 +08:00
|
|
|
else if (OpTok.is(tok::kw_vec_step))
|
|
|
|
ExprKind = UETT_VecStep;
|
2015-07-02 11:40:19 +08:00
|
|
|
else if (OpTok.is(tok::kw___builtin_omp_required_simd_align))
|
|
|
|
ExprKind = UETT_OpenMPRequiredSimdAlign;
|
2009-05-22 18:22:50 +08:00
|
|
|
|
|
|
|
if (isCastExpr)
|
2011-03-12 03:24:49 +08:00
|
|
|
return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
|
|
|
|
ExprKind,
|
2019-07-16 12:46:31 +08:00
|
|
|
/*IsType=*/true,
|
2011-03-12 03:24:49 +08:00
|
|
|
CastTy.getAsOpaquePtr(),
|
|
|
|
CastRange);
|
2009-05-22 18:22:50 +08:00
|
|
|
|
2015-06-18 18:59:26 +08:00
|
|
|
if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof))
|
2013-01-29 18:18:18 +08:00
|
|
|
Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo();
|
|
|
|
|
2017-07-02 14:12:49 +08:00
|
|
|
// If we get here, the operand to the sizeof/alignof was an expression.
|
2008-12-09 21:15:23 +08:00
|
|
|
if (!Operand.isInvalid())
|
2011-03-12 03:24:49 +08:00
|
|
|
Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),
|
|
|
|
ExprKind,
|
2019-07-16 12:46:31 +08:00
|
|
|
/*IsType=*/false,
|
2014-05-29 18:55:11 +08:00
|
|
|
Operand.get(),
|
2011-03-12 03:24:49 +08:00
|
|
|
CastRange);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Operand;
|
2006-08-11 10:13:20 +08:00
|
|
|
}
|
|
|
|
|
2006-08-13 03:16:08 +08:00
|
|
|
/// ParseBuiltinPrimaryExpression
|
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2006-08-13 03:16:08 +08:00
|
|
|
/// primary-expression: [C99 6.5.1]
|
|
|
|
/// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')'
|
|
|
|
/// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')'
|
|
|
|
/// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ','
|
|
|
|
/// assign-expr ')'
|
|
|
|
/// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')'
|
Implement __builtin_LINE() et. al. to support source location capture.
Summary:
This patch implements the source location builtins `__builtin_LINE(), `__builtin_FUNCTION()`, `__builtin_FILE()` and `__builtin_COLUMN()`. These builtins are needed to implement [`std::experimental::source_location`](https://rawgit.com/cplusplus/fundamentals-ts/v2/main.html#reflection.src_loc.creation).
With the exception of `__builtin_COLUMN`, GCC also implements these builtins, and Clangs behavior is intended to match as closely as possible.
Reviewers: rsmith, joerg, aaron.ballman, bogner, majnemer, shafik, martong
Reviewed By: rsmith
Subscribers: rnkovacs, loskutov, riccibruno, mgorny, kunitoki, alexr, majnemer, hfinkel, cfe-commits
Differential Revision: https://reviews.llvm.org/D37035
llvm-svn: 360937
2019-05-17 05:04:15 +08:00
|
|
|
/// [GNU] '__builtin_FILE' '(' ')'
|
|
|
|
/// [GNU] '__builtin_FUNCTION' '(' ')'
|
|
|
|
/// [GNU] '__builtin_LINE' '(' ')'
|
|
|
|
/// [CLANG] '__builtin_COLUMN' '(' ')'
|
2011-11-05 11:47:48 +08:00
|
|
|
/// [OCL] '__builtin_astype' '(' assignment-expression ',' type-name ')'
|
2009-09-09 23:08:12 +08:00
|
|
|
///
|
2006-08-13 03:16:08 +08:00
|
|
|
/// [GNU] offsetof-member-designator:
|
|
|
|
/// [GNU] identifier
|
|
|
|
/// [GNU] offsetof-member-designator '.' identifier
|
|
|
|
/// [GNU] offsetof-member-designator '[' expression ']'
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Parser::ParseBuiltinPrimaryExpression() {
|
|
|
|
ExprResult Res;
|
2006-08-13 03:16:08 +08:00
|
|
|
const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo();
|
|
|
|
|
|
|
|
tok::TokenKind T = Tok.getKind();
|
2006-10-16 14:06:51 +08:00
|
|
|
SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier.
|
2006-08-13 03:16:08 +08:00
|
|
|
|
|
|
|
// All of these start with an open paren.
|
2008-12-12 06:33:27 +08:00
|
|
|
if (Tok.isNot(tok::l_paren))
|
2013-12-24 17:48:30 +08:00
|
|
|
return ExprError(Diag(Tok, diag::err_expected_after) << BuiltinII
|
|
|
|
<< tok::l_paren);
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker PT(*this, tok::l_paren);
|
|
|
|
PT.consumeOpen();
|
|
|
|
|
2006-08-24 11:51:22 +08:00
|
|
|
// TODO: Build AST.
|
|
|
|
|
2006-08-13 03:16:08 +08:00
|
|
|
switch (T) {
|
2011-09-23 13:06:16 +08:00
|
|
|
default: llvm_unreachable("Not a builtin primary expression!");
|
2007-10-16 04:28:48 +08:00
|
|
|
case tok::kw___builtin_va_arg: {
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Expr(ParseAssignmentExpression());
|
2006-08-13 03:30:51 +08:00
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::comma)) {
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2010-09-18 09:28:11 +08:00
|
|
|
Expr = ExprError();
|
2014-01-01 11:08:43 +08:00
|
|
|
}
|
2006-08-13 03:30:51 +08:00
|
|
|
|
2009-02-19 01:45:20 +08:00
|
|
|
TypeResult Ty = ParseTypeName();
|
2008-12-09 21:15:23 +08:00
|
|
|
|
2007-10-16 04:28:48 +08:00
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::r_paren;
|
2010-09-18 09:28:11 +08:00
|
|
|
Expr = ExprError();
|
2007-10-16 04:28:48 +08:00
|
|
|
}
|
2010-09-18 09:28:11 +08:00
|
|
|
|
|
|
|
if (Expr.isInvalid() || Ty.isInvalid())
|
2009-02-19 01:45:20 +08:00
|
|
|
Res = ExprError();
|
|
|
|
else
|
2014-05-29 18:55:11 +08:00
|
|
|
Res = Actions.ActOnVAArg(StartLoc, Expr.get(), Ty.get(), ConsumeParen());
|
2006-08-13 03:16:08 +08:00
|
|
|
break;
|
2007-10-16 04:28:48 +08:00
|
|
|
}
|
2007-08-30 23:51:11 +08:00
|
|
|
case tok::kw___builtin_offsetof: {
|
2007-08-31 01:08:45 +08:00
|
|
|
SourceLocation TypeLoc = Tok.getLocation();
|
2009-02-19 01:45:20 +08:00
|
|
|
TypeResult Ty = ParseTypeName();
|
2009-03-25 01:21:43 +08:00
|
|
|
if (Ty.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2009-03-25 01:21:43 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::comma)) {
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-12-12 06:33:27 +08:00
|
|
|
return ExprError();
|
2014-01-01 11:08:43 +08:00
|
|
|
}
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2006-08-13 03:16:08 +08:00
|
|
|
// We must have at least one identifier here.
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::identifier;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-12-12 06:33:27 +08:00
|
|
|
return ExprError();
|
2007-08-30 23:51:11 +08:00
|
|
|
}
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2007-08-30 23:51:11 +08:00
|
|
|
// Keep track of the various subcomponents we see.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Sema::OffsetOfComponent, 4> Comps;
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2010-08-27 07:41:50 +08:00
|
|
|
Comps.push_back(Sema::OffsetOfComponent());
|
2007-08-30 23:51:11 +08:00
|
|
|
Comps.back().isBrackets = false;
|
|
|
|
Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
|
|
|
|
Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken();
|
2006-08-13 03:26:13 +08:00
|
|
|
|
2008-11-26 06:21:31 +08:00
|
|
|
// FIXME: This loop leaks the index expressions on error.
|
2022-01-09 16:19:47 +08:00
|
|
|
while (true) {
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.is(tok::period)) {
|
2006-08-13 03:16:08 +08:00
|
|
|
// offsetof-member-designator: offsetof-member-designator '.' identifier
|
2010-08-27 07:41:50 +08:00
|
|
|
Comps.push_back(Sema::OffsetOfComponent());
|
2007-08-30 23:51:11 +08:00
|
|
|
Comps.back().isBrackets = false;
|
|
|
|
Comps.back().LocStart = ConsumeToken();
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::identifier;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-12-12 06:33:27 +08:00
|
|
|
return ExprError();
|
2007-08-30 23:51:11 +08:00
|
|
|
}
|
|
|
|
Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
|
|
|
|
Comps.back().LocEnd = ConsumeToken();
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2007-10-10 01:41:39 +08:00
|
|
|
} else if (Tok.is(tok::l_square)) {
|
2012-04-10 09:32:12 +08:00
|
|
|
if (CheckProhibitedCXX11Attribute())
|
|
|
|
return ExprError();
|
|
|
|
|
2006-08-13 03:16:08 +08:00
|
|
|
// offsetof-member-designator: offsetof-member-design '[' expression ']'
|
2010-08-27 07:41:50 +08:00
|
|
|
Comps.push_back(Sema::OffsetOfComponent());
|
2007-08-30 23:51:11 +08:00
|
|
|
Comps.back().isBrackets = true;
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker ST(*this, tok::l_square);
|
|
|
|
ST.consumeOpen();
|
|
|
|
Comps.back().LocStart = ST.getOpenLocation();
|
2006-08-13 03:16:08 +08:00
|
|
|
Res = ParseExpression();
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Res.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Res;
|
2006-08-13 03:16:08 +08:00
|
|
|
}
|
2014-05-29 18:55:11 +08:00
|
|
|
Comps.back().U.E = Res.get();
|
2006-08-13 03:16:08 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
ST.consumeClose();
|
|
|
|
Comps.back().LocEnd = ST.getCloseLocation();
|
2009-06-28 04:38:33 +08:00
|
|
|
} else {
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2011-10-13 00:37:45 +08:00
|
|
|
PT.consumeClose();
|
2009-06-28 04:38:33 +08:00
|
|
|
Res = ExprError();
|
|
|
|
} else if (Ty.isInvalid()) {
|
2009-02-19 01:45:20 +08:00
|
|
|
Res = ExprError();
|
2009-06-28 04:38:33 +08:00
|
|
|
} else {
|
2011-10-13 00:37:45 +08:00
|
|
|
PT.consumeClose();
|
2010-07-03 01:43:08 +08:00
|
|
|
Res = Actions.ActOnBuiltinOffsetOf(getCurScope(), StartLoc, TypeLoc,
|
2015-10-22 12:59:59 +08:00
|
|
|
Ty.get(), Comps,
|
2011-10-13 00:37:45 +08:00
|
|
|
PT.getCloseLocation());
|
2009-06-28 04:38:33 +08:00
|
|
|
}
|
2007-08-30 23:52:49 +08:00
|
|
|
break;
|
2006-08-13 03:16:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2007-08-30 23:51:11 +08:00
|
|
|
}
|
2007-08-04 05:21:27 +08:00
|
|
|
case tok::kw___builtin_choose_expr: {
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Cond(ParseAssignmentExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Cond.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Cond;
|
2007-08-04 05:21:27 +08:00
|
|
|
}
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::comma)) {
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-12-12 06:33:27 +08:00
|
|
|
return ExprError();
|
2014-01-01 11:08:43 +08:00
|
|
|
}
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Expr1(ParseAssignmentExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Expr1.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Expr1;
|
2008-12-09 21:15:23 +08:00
|
|
|
}
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::comma)) {
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-12-12 06:33:27 +08:00
|
|
|
return ExprError();
|
2014-01-01 11:08:43 +08:00
|
|
|
}
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Expr2(ParseAssignmentExpression());
|
2008-12-09 21:15:23 +08:00
|
|
|
if (Expr2.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2012-08-24 05:35:17 +08:00
|
|
|
return Expr2;
|
2008-12-09 21:15:23 +08:00
|
|
|
}
|
2007-10-10 01:41:39 +08:00
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::r_paren;
|
2008-12-12 06:33:27 +08:00
|
|
|
return ExprError();
|
2007-08-04 05:21:27 +08:00
|
|
|
}
|
2014-05-29 18:55:11 +08:00
|
|
|
Res = Actions.ActOnChooseExpr(StartLoc, Cond.get(), Expr1.get(),
|
|
|
|
Expr2.get(), ConsumeParen());
|
2007-08-30 23:52:49 +08:00
|
|
|
break;
|
2007-08-04 05:21:27 +08:00
|
|
|
}
|
2011-06-04 08:47:47 +08:00
|
|
|
case tok::kw___builtin_astype: {
|
|
|
|
// The first argument is an expression to be converted, followed by a comma.
|
|
|
|
ExprResult Expr(ParseAssignmentExpression());
|
|
|
|
if (Expr.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-06-04 08:47:47 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2014-01-01 11:08:43 +08:00
|
|
|
|
|
|
|
if (ExpectAndConsume(tok::comma)) {
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-06-04 08:47:47 +08:00
|
|
|
return ExprError();
|
2014-01-01 11:08:43 +08:00
|
|
|
}
|
|
|
|
|
2011-06-04 08:47:47 +08:00
|
|
|
// Second argument is the type to bitcast to.
|
|
|
|
TypeResult DestTy = ParseTypeName();
|
|
|
|
if (DestTy.isInvalid())
|
|
|
|
return ExprError();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-06-04 08:47:47 +08:00
|
|
|
// Attempt to consume the r-paren.
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::r_paren;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-06-04 08:47:47 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
|
|
|
Res = Actions.ActOnAsTypeExpr(Expr.get(), DestTy.get(), StartLoc,
|
2011-06-04 08:47:47 +08:00
|
|
|
ConsumeParen());
|
|
|
|
break;
|
2008-12-12 05:36:32 +08:00
|
|
|
}
|
2013-09-18 11:29:45 +08:00
|
|
|
case tok::kw___builtin_convertvector: {
|
|
|
|
// The first argument is an expression to be converted, followed by a comma.
|
|
|
|
ExprResult Expr(ParseAssignmentExpression());
|
|
|
|
if (Expr.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2013-09-18 11:29:45 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2014-01-01 11:08:43 +08:00
|
|
|
|
|
|
|
if (ExpectAndConsume(tok::comma)) {
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2013-09-18 11:29:45 +08:00
|
|
|
return ExprError();
|
2014-01-01 11:08:43 +08:00
|
|
|
}
|
|
|
|
|
2013-09-18 11:29:45 +08:00
|
|
|
// Second argument is the type to bitcast to.
|
|
|
|
TypeResult DestTy = ParseTypeName();
|
|
|
|
if (DestTy.isInvalid())
|
|
|
|
return ExprError();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2013-09-18 11:29:45 +08:00
|
|
|
// Attempt to consume the r-paren.
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
2013-12-24 17:48:30 +08:00
|
|
|
Diag(Tok, diag::err_expected) << tok::r_paren;
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2013-09-18 11:29:45 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
|
|
|
Res = Actions.ActOnConvertVectorExpr(Expr.get(), DestTy.get(), StartLoc,
|
2013-09-18 11:29:45 +08:00
|
|
|
ConsumeParen());
|
|
|
|
break;
|
|
|
|
}
|
Implement __builtin_LINE() et. al. to support source location capture.
Summary:
This patch implements the source location builtins `__builtin_LINE(), `__builtin_FUNCTION()`, `__builtin_FILE()` and `__builtin_COLUMN()`. These builtins are needed to implement [`std::experimental::source_location`](https://rawgit.com/cplusplus/fundamentals-ts/v2/main.html#reflection.src_loc.creation).
With the exception of `__builtin_COLUMN`, GCC also implements these builtins, and Clangs behavior is intended to match as closely as possible.
Reviewers: rsmith, joerg, aaron.ballman, bogner, majnemer, shafik, martong
Reviewed By: rsmith
Subscribers: rnkovacs, loskutov, riccibruno, mgorny, kunitoki, alexr, majnemer, hfinkel, cfe-commits
Differential Revision: https://reviews.llvm.org/D37035
llvm-svn: 360937
2019-05-17 05:04:15 +08:00
|
|
|
case tok::kw___builtin_COLUMN:
|
|
|
|
case tok::kw___builtin_FILE:
|
|
|
|
case tok::kw___builtin_FUNCTION:
|
|
|
|
case tok::kw___builtin_LINE: {
|
|
|
|
// Attempt to consume the r-paren.
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
|
|
|
Diag(Tok, diag::err_expected) << tok::r_paren;
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
SourceLocExpr::IdentKind Kind = [&] {
|
|
|
|
switch (T) {
|
|
|
|
case tok::kw___builtin_FILE:
|
|
|
|
return SourceLocExpr::File;
|
|
|
|
case tok::kw___builtin_FUNCTION:
|
|
|
|
return SourceLocExpr::Function;
|
|
|
|
case tok::kw___builtin_LINE:
|
|
|
|
return SourceLocExpr::Line;
|
|
|
|
case tok::kw___builtin_COLUMN:
|
|
|
|
return SourceLocExpr::Column;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("invalid keyword");
|
|
|
|
}
|
|
|
|
}();
|
|
|
|
Res = Actions.ActOnSourceLocExpr(Kind, StartLoc, ConsumeParen());
|
|
|
|
break;
|
|
|
|
}
|
2011-07-08 12:59:44 +08:00
|
|
|
}
|
2008-12-12 05:36:32 +08:00
|
|
|
|
2010-08-24 07:25:46 +08:00
|
|
|
if (Res.isInvalid())
|
|
|
|
return ExprError();
|
|
|
|
|
2006-08-13 03:16:08 +08:00
|
|
|
// These can be followed by postfix-expr pieces because they are
|
|
|
|
// primary-expressions.
|
2014-05-29 18:55:11 +08:00
|
|
|
return ParsePostfixExpressionSuffix(Res.get());
|
2006-08-13 03:16:08 +08:00
|
|
|
}
|
|
|
|
|
[OPENMP50]Add basic support for array-shaping operation.
Summary:
Added basic representation and parsing/sema handling of array-shaping
operations. Array shaping expression is an expression of form ([s0]..[sn])base,
where s0, ..., sn must be a positive integer, base - a pointer. This
expression is a kind of cast operation that converts pointer expression
into an array-like kind of expression.
Reviewers: rjmccall, rsmith, jdoerfert
Subscribers: guansong, arphaman, cfe-commits, caomhin, kkwli0
Tags: #clang
Differential Revision: https://reviews.llvm.org/D74144
2020-02-05 22:33:05 +08:00
|
|
|
bool Parser::tryParseOpenMPArrayShapingCastPart() {
|
|
|
|
assert(Tok.is(tok::l_square) && "Expected open bracket");
|
|
|
|
bool ErrorFound = true;
|
|
|
|
TentativeParsingAction TPA(*this);
|
|
|
|
do {
|
|
|
|
if (Tok.isNot(tok::l_square))
|
|
|
|
break;
|
|
|
|
// Consume '['
|
|
|
|
ConsumeBracket();
|
|
|
|
// Skip inner expression.
|
|
|
|
while (!SkipUntil(tok::r_square, tok::annot_pragma_openmp_end,
|
|
|
|
StopAtSemi | StopBeforeMatch))
|
|
|
|
;
|
|
|
|
if (Tok.isNot(tok::r_square))
|
|
|
|
break;
|
|
|
|
// Consume ']'
|
|
|
|
ConsumeBracket();
|
|
|
|
// Found ')' - done.
|
|
|
|
if (Tok.is(tok::r_paren)) {
|
|
|
|
ErrorFound = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (Tok.isNot(tok::annot_pragma_openmp_end));
|
|
|
|
TPA.Revert();
|
|
|
|
return !ErrorFound;
|
|
|
|
}
|
|
|
|
|
2006-08-11 09:33:00 +08:00
|
|
|
/// ParseParenExpression - This parses the unit that starts with a '(' token,
|
|
|
|
/// based on what is allowed by ExprType. The actual thing parsed is returned
|
2009-05-22 18:23:40 +08:00
|
|
|
/// in ExprType. If stopIfCastExpr is true, it will only return the parsed type,
|
|
|
|
/// not the parsed cast-expression.
|
2006-08-11 09:33:00 +08:00
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2006-08-11 09:33:00 +08:00
|
|
|
/// primary-expression: [C99 6.5.1]
|
2006-08-10 12:23:57 +08:00
|
|
|
/// '(' expression ')'
|
2006-08-11 06:01:51 +08:00
|
|
|
/// [GNU] '(' compound-statement ')' (if !ParenExprOnly)
|
|
|
|
/// postfix-expression: [C99 6.5.2]
|
|
|
|
/// '(' type-name ')' '{' initializer-list '}'
|
|
|
|
/// '(' type-name ')' '{' initializer-list ',' '}'
|
2006-08-11 09:33:00 +08:00
|
|
|
/// cast-expression: [C99 6.5.4]
|
|
|
|
/// '(' type-name ')' cast-expression
|
2011-06-16 07:02:42 +08:00
|
|
|
/// [ARC] bridged-cast-expression
|
|
|
|
/// [ARC] bridged-cast-expression:
|
|
|
|
/// (__bridge type-name) cast-expression
|
|
|
|
/// (__bridge_transfer type-name) cast-expression
|
|
|
|
/// (__bridge_retained type-name) cast-expression
|
2014-11-08 13:07:16 +08:00
|
|
|
/// fold-expression: [C++1z]
|
|
|
|
/// '(' cast-expression fold-operator '...' ')'
|
|
|
|
/// '(' '...' fold-operator cast-expression ')'
|
|
|
|
/// '(' cast-expression fold-operator '...'
|
|
|
|
/// fold-operator cast-expression ')'
|
[OPENMP50]Add basic support for array-shaping operation.
Summary:
Added basic representation and parsing/sema handling of array-shaping
operations. Array shaping expression is an expression of form ([s0]..[sn])base,
where s0, ..., sn must be a positive integer, base - a pointer. This
expression is a kind of cast operation that converts pointer expression
into an array-like kind of expression.
Reviewers: rjmccall, rsmith, jdoerfert
Subscribers: guansong, arphaman, cfe-commits, caomhin, kkwli0
Tags: #clang
Differential Revision: https://reviews.llvm.org/D74144
2020-02-05 22:33:05 +08:00
|
|
|
/// [OPENMP] Array shaping operation
|
|
|
|
/// '(' '[' expression ']' { '[' expression ']' } cast-expression
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2009-05-22 18:23:40 +08:00
|
|
|
Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr,
|
2011-07-02 06:22:59 +08:00
|
|
|
bool isTypeCast, ParsedType &CastTy,
|
2009-08-11 07:49:36 +08:00
|
|
|
SourceLocation &RParenLoc) {
|
2007-10-10 01:41:39 +08:00
|
|
|
assert(Tok.is(tok::l_paren) && "Not a paren expr!");
|
2014-05-15 10:43:47 +08:00
|
|
|
ColonProtectionRAIIObject ColonProtection(*this, false);
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
|
|
|
if (T.consumeOpen())
|
|
|
|
return ExprError();
|
|
|
|
SourceLocation OpenLoc = T.getOpenLocation();
|
|
|
|
|
2019-02-01 04:20:32 +08:00
|
|
|
PreferredType.enterParenExpr(Tok.getLocation(), OpenLoc);
|
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Result(true);
|
2009-05-22 18:24:42 +08:00
|
|
|
bool isAmbiguousTypeId;
|
2016-01-16 07:43:34 +08:00
|
|
|
CastTy = nullptr;
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2010-09-15 07:59:36 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2021-03-12 19:00:54 +08:00
|
|
|
cutOffParsing();
|
2019-02-01 04:20:32 +08:00
|
|
|
Actions.CodeCompleteExpression(
|
|
|
|
getCurScope(), PreferredType.get(Tok.getLocation()),
|
|
|
|
/*IsParenthesized=*/ExprType >= CompoundLiteral);
|
2010-09-15 07:59:36 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2011-04-06 10:35:25 +08:00
|
|
|
|
2011-12-20 05:06:15 +08:00
|
|
|
// Diagnose use of bridge casts in non-arc mode.
|
2018-10-31 04:31:30 +08:00
|
|
|
bool BridgeCast = (getLangOpts().ObjC &&
|
2015-06-18 18:59:26 +08:00
|
|
|
Tok.isOneOf(tok::kw___bridge,
|
|
|
|
tok::kw___bridge_transfer,
|
|
|
|
tok::kw___bridge_retained,
|
|
|
|
tok::kw___bridge_retain));
|
2012-03-11 15:00:24 +08:00
|
|
|
if (BridgeCast && !getLangOpts().ObjCAutoRefCount) {
|
2014-01-01 11:08:43 +08:00
|
|
|
if (!TryConsumeToken(tok::kw___bridge)) {
|
2013-04-03 07:48:59 +08:00
|
|
|
StringRef BridgeCastName = Tok.getName();
|
|
|
|
SourceLocation BridgeKeywordLoc = ConsumeToken();
|
|
|
|
if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc))
|
|
|
|
Diag(BridgeKeywordLoc, diag::warn_arc_bridge_cast_nonarc)
|
|
|
|
<< BridgeCastName
|
|
|
|
<< FixItHint::CreateReplacement(BridgeKeywordLoc, "");
|
|
|
|
}
|
2011-12-20 05:06:15 +08:00
|
|
|
BridgeCast = false;
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-04-06 10:35:25 +08:00
|
|
|
// None of these cases should fall through with an invalid Result
|
|
|
|
// unless they've already reported an error.
|
2007-10-10 01:41:39 +08:00
|
|
|
if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
|
2006-08-11 06:01:51 +08:00
|
|
|
Diag(Tok, diag::ext_gnu_statement_expr);
|
2012-04-04 09:27:53 +08:00
|
|
|
|
2020-08-28 07:08:11 +08:00
|
|
|
checkCompoundToken(OpenLoc, tok::l_paren, CompoundToken::StmtExprBegin);
|
|
|
|
|
2015-01-09 17:38:14 +08:00
|
|
|
if (!getCurScope()->getFnParent() && !getCurScope()->getBlockParent()) {
|
|
|
|
Result = ExprError(Diag(OpenLoc, diag::err_stmtexpr_file_scope));
|
2012-04-04 09:27:53 +08:00
|
|
|
} else {
|
2015-04-21 04:00:49 +08:00
|
|
|
// Find the nearest non-record decl context. Variables declared in a
|
|
|
|
// statement expression behave as if they were declared in the enclosing
|
|
|
|
// function, block, or other code construct.
|
|
|
|
DeclContext *CodeDC = Actions.CurContext;
|
|
|
|
while (CodeDC->isRecord() || isa<EnumDecl>(CodeDC)) {
|
|
|
|
CodeDC = CodeDC->getParent();
|
|
|
|
assert(CodeDC && !CodeDC->isFileContext() &&
|
|
|
|
"statement expr not in code context");
|
|
|
|
}
|
|
|
|
Sema::ContextRAII SavedContext(Actions, CodeDC, /*NewThisContext=*/false);
|
|
|
|
|
2015-01-09 17:38:14 +08:00
|
|
|
Actions.ActOnStartStmtExpr();
|
|
|
|
|
|
|
|
StmtResult Stmt(ParseCompoundStatement(true));
|
|
|
|
ExprType = CompoundStmt;
|
|
|
|
|
|
|
|
// If the substmt parsed correctly, build the AST node.
|
|
|
|
if (!Stmt.isInvalid()) {
|
2020-03-10 08:34:33 +08:00
|
|
|
Result = Actions.ActOnStmtExpr(getCurScope(), OpenLoc, Stmt.get(),
|
|
|
|
Tok.getLocation());
|
2015-01-09 17:38:14 +08:00
|
|
|
} else {
|
|
|
|
Actions.ActOnStmtExprError();
|
|
|
|
}
|
2012-04-04 09:27:53 +08:00
|
|
|
}
|
2011-12-20 05:06:15 +08:00
|
|
|
} else if (ExprType >= CompoundLiteral && BridgeCast) {
|
2011-06-18 05:56:12 +08:00
|
|
|
tok::TokenKind tokenKind = Tok.getKind();
|
|
|
|
SourceLocation BridgeKeywordLoc = ConsumeToken();
|
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
// Parse an Objective-C ARC ownership cast expression.
|
|
|
|
ObjCBridgeCastKind Kind;
|
2011-06-18 05:56:12 +08:00
|
|
|
if (tokenKind == tok::kw___bridge)
|
2011-06-16 07:02:42 +08:00
|
|
|
Kind = OBC_Bridge;
|
2011-06-18 05:56:12 +08:00
|
|
|
else if (tokenKind == tok::kw___bridge_transfer)
|
2011-06-16 07:02:42 +08:00
|
|
|
Kind = OBC_BridgeTransfer;
|
2011-06-18 05:56:12 +08:00
|
|
|
else if (tokenKind == tok::kw___bridge_retained)
|
|
|
|
Kind = OBC_BridgeRetained;
|
|
|
|
else {
|
|
|
|
// As a hopefully temporary workaround, allow __bridge_retain as
|
|
|
|
// a synonym for __bridge_retained, but only in system headers.
|
|
|
|
assert(tokenKind == tok::kw___bridge_retain);
|
2011-06-16 07:02:42 +08:00
|
|
|
Kind = OBC_BridgeRetained;
|
2011-06-18 05:56:12 +08:00
|
|
|
if (!PP.getSourceManager().isInSystemHeader(BridgeKeywordLoc))
|
|
|
|
Diag(BridgeKeywordLoc, diag::err_arc_bridge_retain)
|
|
|
|
<< FixItHint::CreateReplacement(BridgeKeywordLoc,
|
|
|
|
"__bridge_retained");
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
TypeResult Ty = ParseTypeName();
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2014-05-15 10:43:47 +08:00
|
|
|
ColonProtection.restore();
|
2011-10-13 00:37:45 +08:00
|
|
|
RParenLoc = T.getCloseLocation();
|
2019-02-01 04:20:32 +08:00
|
|
|
|
|
|
|
PreferredType.enterTypeCast(Tok.getLocation(), Ty.get().get());
|
2020-01-09 21:07:51 +08:00
|
|
|
ExprResult SubExpr = ParseCastExpression(AnyCastExpr);
|
2020-02-18 10:48:38 +08:00
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
if (Ty.isInvalid() || SubExpr.isInvalid())
|
|
|
|
return ExprError();
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-06-16 07:02:42 +08:00
|
|
|
return Actions.ActOnObjCBridgedCast(getCurScope(), OpenLoc, Kind,
|
|
|
|
BridgeKeywordLoc, Ty.get(),
|
|
|
|
RParenLoc, SubExpr.get());
|
2009-05-22 18:24:42 +08:00
|
|
|
} else if (ExprType >= CompoundLiteral &&
|
|
|
|
isTypeIdInParens(isAmbiguousTypeId)) {
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2006-08-13 00:54:25 +08:00
|
|
|
// Otherwise, this is a compound literal expression or cast expression.
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2009-05-22 18:24:42 +08:00
|
|
|
// In C++, if the type-id is ambiguous we disambiguate based on context.
|
|
|
|
// If stopIfCastExpr is true the context is a typeof/sizeof/alignof
|
|
|
|
// in which case we should treat it as type-id.
|
|
|
|
// if stopIfCastExpr is false, we need to determine the context past the
|
|
|
|
// parens, so we defer to ParseCXXAmbiguousParenExpression for that.
|
2011-10-13 00:37:45 +08:00
|
|
|
if (isAmbiguousTypeId && !stopIfCastExpr) {
|
2014-05-15 10:43:47 +08:00
|
|
|
ExprResult res = ParseCXXAmbiguousParenExpression(ExprType, CastTy, T,
|
|
|
|
ColonProtection);
|
2011-10-13 00:37:45 +08:00
|
|
|
RParenLoc = T.getCloseLocation();
|
|
|
|
return res;
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-07-02 06:22:59 +08:00
|
|
|
// Parse the type declarator.
|
|
|
|
DeclSpec DS(AttrFactory);
|
|
|
|
ParseSpecifierQualifierList(DS);
|
2020-11-11 13:40:12 +08:00
|
|
|
Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName);
|
2011-07-02 06:22:59 +08:00
|
|
|
ParseDeclarator(DeclaratorInfo);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
|
|
|
// If our type is followed by an identifier and either ':' or ']', then
|
2010-09-16 07:19:31 +08:00
|
|
|
// this is probably an Objective-C message send where the leading '[' is
|
|
|
|
// missing. Recover as if that were the case.
|
2011-07-02 06:22:59 +08:00
|
|
|
if (!DeclaratorInfo.isInvalidType() && Tok.is(tok::identifier) &&
|
2018-10-31 04:31:30 +08:00
|
|
|
!InMessageExpression && getLangOpts().ObjC &&
|
2011-07-02 06:22:59 +08:00
|
|
|
(NextToken().is(tok::colon) || NextToken().is(tok::r_square))) {
|
|
|
|
TypeResult Ty;
|
|
|
|
{
|
|
|
|
InMessageExpressionRAIIObject InMessage(*this, false);
|
|
|
|
Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
Result = ParseObjCMessageExpressionBody(SourceLocation(),
|
|
|
|
SourceLocation(),
|
2014-05-21 14:02:52 +08:00
|
|
|
Ty.get(), nullptr);
|
2018-07-31 03:24:48 +08:00
|
|
|
} else {
|
2010-09-16 07:19:31 +08:00
|
|
|
// Match the ')'.
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
2014-05-15 10:43:47 +08:00
|
|
|
ColonProtection.restore();
|
2011-10-13 00:37:45 +08:00
|
|
|
RParenLoc = T.getCloseLocation();
|
2010-09-16 07:19:31 +08:00
|
|
|
if (Tok.is(tok::l_brace)) {
|
|
|
|
ExprType = CompoundLiteral;
|
2011-07-02 06:22:59 +08:00
|
|
|
TypeResult Ty;
|
|
|
|
{
|
|
|
|
InMessageExpressionRAIIObject InMessage(*this, false);
|
|
|
|
Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
|
|
|
}
|
2010-09-16 07:19:31 +08:00
|
|
|
return ParseCompoundLiteralExpression(Ty.get(), OpenLoc, RParenLoc);
|
|
|
|
}
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2017-03-29 20:09:39 +08:00
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
// This could be OpenCL vector Literals
|
|
|
|
if (getLangOpts().OpenCL)
|
|
|
|
{
|
|
|
|
TypeResult Ty;
|
|
|
|
{
|
|
|
|
InMessageExpressionRAIIObject InMessage(*this, false);
|
|
|
|
Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
|
|
|
}
|
|
|
|
if(Ty.isInvalid())
|
|
|
|
{
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
QualType QT = Ty.get().get().getCanonicalType();
|
|
|
|
if (QT->isVectorType())
|
|
|
|
{
|
|
|
|
// We parsed '(' vector-type-name ')' followed by '('
|
|
|
|
|
|
|
|
// Parse the cast-expression that follows it next.
|
|
|
|
// isVectorLiteral = true will make sure we don't parse any
|
|
|
|
// Postfix expression yet
|
2020-01-09 21:07:51 +08:00
|
|
|
Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr,
|
2017-03-29 20:09:39 +08:00
|
|
|
/*isAddressOfOperand=*/false,
|
|
|
|
/*isTypeCast=*/IsTypeCast,
|
|
|
|
/*isVectorLiteral=*/true);
|
|
|
|
|
|
|
|
if (!Result.isInvalid()) {
|
|
|
|
Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc,
|
|
|
|
DeclaratorInfo, CastTy,
|
|
|
|
RParenLoc, Result.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
// After we performed the cast we can check for postfix-expr pieces.
|
|
|
|
if (!Result.isInvalid()) {
|
|
|
|
Result = ParsePostfixExpressionSuffix(Result);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-16 07:19:31 +08:00
|
|
|
if (ExprType == CastExpr) {
|
|
|
|
// We parsed '(' type-name ')' and the thing after it wasn't a '{'.
|
2009-01-20 06:31:54 +08:00
|
|
|
|
2011-07-02 06:22:59 +08:00
|
|
|
if (DeclaratorInfo.isInvalidType())
|
2010-09-16 07:19:31 +08:00
|
|
|
return ExprError();
|
2009-02-19 01:45:20 +08:00
|
|
|
|
2010-09-16 07:19:31 +08:00
|
|
|
// Note that this doesn't parse the subsequent cast-expression, it just
|
|
|
|
// returns the parsed type to the callee.
|
2011-07-02 06:22:59 +08:00
|
|
|
if (stopIfCastExpr) {
|
|
|
|
TypeResult Ty;
|
|
|
|
{
|
|
|
|
InMessageExpressionRAIIObject InMessage(*this, false);
|
|
|
|
Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
|
|
|
|
}
|
|
|
|
CastTy = Ty.get();
|
2010-09-16 07:19:31 +08:00
|
|
|
return ExprResult();
|
2011-07-02 06:22:59 +08:00
|
|
|
}
|
2014-05-04 05:57:40 +08:00
|
|
|
|
2010-09-16 07:19:31 +08:00
|
|
|
// Reject the cast of super idiom in ObjC.
|
2018-10-31 04:31:30 +08:00
|
|
|
if (Tok.is(tok::identifier) && getLangOpts().ObjC &&
|
2018-07-31 03:24:48 +08:00
|
|
|
Tok.getIdentifierInfo() == Ident_super &&
|
2010-09-16 07:19:31 +08:00
|
|
|
getCurScope()->isInObjcMethodScope() &&
|
|
|
|
GetLookAheadToken(1).isNot(tok::period)) {
|
|
|
|
Diag(Tok.getLocation(), diag::err_illegal_super_cast)
|
|
|
|
<< SourceRange(OpenLoc, RParenLoc);
|
|
|
|
return ExprError();
|
|
|
|
}
|
2009-05-22 18:23:40 +08:00
|
|
|
|
2019-02-01 04:20:32 +08:00
|
|
|
PreferredType.enterTypeCast(Tok.getLocation(), CastTy.get());
|
2010-09-16 07:19:31 +08:00
|
|
|
// Parse the cast-expression that follows it next.
|
|
|
|
// TODO: For cast expression with CastTy.
|
2020-01-09 21:07:51 +08:00
|
|
|
Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr,
|
2011-07-02 06:22:59 +08:00
|
|
|
/*isAddressOfOperand=*/false,
|
2017-03-29 13:40:45 +08:00
|
|
|
/*isTypeCast=*/IsTypeCast);
|
2011-07-02 06:22:59 +08:00
|
|
|
if (!Result.isInvalid()) {
|
|
|
|
Result = Actions.ActOnCastExpr(getCurScope(), OpenLoc,
|
2018-07-31 03:24:48 +08:00
|
|
|
DeclaratorInfo, CastTy,
|
2014-05-29 18:55:11 +08:00
|
|
|
RParenLoc, Result.get());
|
2011-07-02 06:22:59 +08:00
|
|
|
}
|
2012-08-24 05:35:17 +08:00
|
|
|
return Result;
|
2010-04-11 16:28:14 +08:00
|
|
|
}
|
2009-05-22 18:23:40 +08:00
|
|
|
|
2010-09-16 07:19:31 +08:00
|
|
|
Diag(Tok, diag::err_expected_lbrace_in_compound_literal);
|
|
|
|
return ExprError();
|
2006-08-11 07:56:11 +08:00
|
|
|
}
|
2018-07-28 05:55:12 +08:00
|
|
|
} else if (ExprType >= FoldExpr && Tok.is(tok::ellipsis) &&
|
2014-11-11 11:28:50 +08:00
|
|
|
isFoldOperator(NextToken().getKind())) {
|
2018-07-28 05:55:12 +08:00
|
|
|
ExprType = FoldExpr;
|
2014-11-11 11:28:50 +08:00
|
|
|
return ParseFoldExpression(ExprResult(), T);
|
2011-07-02 06:22:59 +08:00
|
|
|
} else if (isTypeCast) {
|
2009-08-11 07:49:36 +08:00
|
|
|
// Parse the expression-list.
|
2010-09-15 22:51:05 +08:00
|
|
|
InMessageExpressionRAIIObject InMessage(*this, false);
|
2014-11-11 11:28:50 +08:00
|
|
|
|
2012-08-24 06:51:59 +08:00
|
|
|
ExprVector ArgExprs;
|
2009-08-11 07:49:36 +08:00
|
|
|
CommaLocsTy CommaLocs;
|
|
|
|
|
2013-08-14 07:38:34 +08:00
|
|
|
if (!ParseSimpleExpressionList(ArgExprs, CommaLocs)) {
|
2014-11-11 11:28:50 +08:00
|
|
|
// FIXME: If we ever support comma expressions as operands to
|
|
|
|
// fold-expressions, we'll need to allow multiple ArgExprs here.
|
2018-07-28 05:55:12 +08:00
|
|
|
if (ExprType >= FoldExpr && ArgExprs.size() == 1 &&
|
|
|
|
isFoldOperator(Tok.getKind()) && NextToken().is(tok::ellipsis)) {
|
|
|
|
ExprType = FoldExpr;
|
2017-02-16 03:57:10 +08:00
|
|
|
return ParseFoldExpression(ArgExprs[0], T);
|
2018-07-28 05:55:12 +08:00
|
|
|
}
|
2014-11-11 11:28:50 +08:00
|
|
|
|
2009-08-11 07:49:36 +08:00
|
|
|
ExprType = SimpleExpr;
|
Represent C++ direct initializers as ParenListExprs before semantic analysis
instead of having a special-purpose function.
- ActOnCXXDirectInitializer, which was mostly duplication of
AddInitializerToDecl (leading e.g. to PR10620, which Eli fixed a few days
ago), is dropped completely.
- MultiInitializer, which was an ugly hack I added, is dropped again.
- We now have the infrastructure in place to distinguish between
int x = {1};
int x({1});
int x{1};
-- VarDecl now has getInitStyle(), which indicates which of the above was used.
-- CXXConstructExpr now has a flag to indicate that it represents list-
initialization, although this is not yet used.
- InstantiateInitializer was renamed to SubstInitializer and simplified.
- ActOnParenOrParenListExpr has been replaced by ActOnParenListExpr, which
always produces a ParenListExpr. Placed that so far failed to convert that
back to a ParenExpr containing comma operators have been fixed. I'm pretty
sure I could have made a crashing test case before this.
The end result is a (I hope) considerably cleaner design of initializers.
More importantly, the fact that I can now distinguish between the various
initialization kinds means that I can get the tricky generalized initializer
test cases Johannes Schaub supplied to work. (This is not yet done.)
This commit passed self-host, with the resulting compiler passing the tests. I
hope it doesn't break more complicated code. It's a pretty big change, but one
that I feel is necessary.
llvm-svn: 150318
2012-02-12 07:51:47 +08:00
|
|
|
Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(),
|
2012-08-24 05:35:17 +08:00
|
|
|
ArgExprs);
|
2009-08-11 07:49:36 +08:00
|
|
|
}
|
[OPENMP50]Add basic support for array-shaping operation.
Summary:
Added basic representation and parsing/sema handling of array-shaping
operations. Array shaping expression is an expression of form ([s0]..[sn])base,
where s0, ..., sn must be a positive integer, base - a pointer. This
expression is a kind of cast operation that converts pointer expression
into an array-like kind of expression.
Reviewers: rjmccall, rsmith, jdoerfert
Subscribers: guansong, arphaman, cfe-commits, caomhin, kkwli0
Tags: #clang
Differential Revision: https://reviews.llvm.org/D74144
2020-02-05 22:33:05 +08:00
|
|
|
} else if (getLangOpts().OpenMP >= 50 && OpenMPDirectiveParsing &&
|
|
|
|
ExprType == CastExpr && Tok.is(tok::l_square) &&
|
|
|
|
tryParseOpenMPArrayShapingCastPart()) {
|
|
|
|
bool ErrorFound = false;
|
|
|
|
SmallVector<Expr *, 4> OMPDimensions;
|
|
|
|
SmallVector<SourceRange, 4> OMPBracketsRanges;
|
|
|
|
do {
|
|
|
|
BalancedDelimiterTracker TS(*this, tok::l_square);
|
|
|
|
TS.consumeOpen();
|
|
|
|
ExprResult NumElements =
|
|
|
|
Actions.CorrectDelayedTyposInExpr(ParseExpression());
|
|
|
|
if (!NumElements.isUsable()) {
|
|
|
|
ErrorFound = true;
|
|
|
|
while (!SkipUntil(tok::r_square, tok::r_paren,
|
|
|
|
StopAtSemi | StopBeforeMatch))
|
|
|
|
;
|
|
|
|
}
|
|
|
|
TS.consumeClose();
|
|
|
|
OMPDimensions.push_back(NumElements.get());
|
|
|
|
OMPBracketsRanges.push_back(TS.getRange());
|
|
|
|
} while (Tok.isNot(tok::r_paren));
|
|
|
|
// Match the ')'.
|
|
|
|
T.consumeClose();
|
|
|
|
RParenLoc = T.getCloseLocation();
|
2020-04-01 04:53:00 +08:00
|
|
|
Result = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
|
[OPENMP50]Add basic support for array-shaping operation.
Summary:
Added basic representation and parsing/sema handling of array-shaping
operations. Array shaping expression is an expression of form ([s0]..[sn])base,
where s0, ..., sn must be a positive integer, base - a pointer. This
expression is a kind of cast operation that converts pointer expression
into an array-like kind of expression.
Reviewers: rjmccall, rsmith, jdoerfert
Subscribers: guansong, arphaman, cfe-commits, caomhin, kkwli0
Tags: #clang
Differential Revision: https://reviews.llvm.org/D74144
2020-02-05 22:33:05 +08:00
|
|
|
if (ErrorFound) {
|
|
|
|
Result = ExprError();
|
|
|
|
} else if (!Result.isInvalid()) {
|
|
|
|
Result = Actions.ActOnOMPArrayShapingExpr(
|
|
|
|
Result.get(), OpenLoc, RParenLoc, OMPDimensions, OMPBracketsRanges);
|
|
|
|
}
|
|
|
|
return Result;
|
2006-08-11 09:33:00 +08:00
|
|
|
} else {
|
2010-09-15 22:51:05 +08:00
|
|
|
InMessageExpressionRAIIObject InMessage(*this, false);
|
2014-11-11 11:28:50 +08:00
|
|
|
|
2012-01-26 04:49:08 +08:00
|
|
|
Result = ParseExpression(MaybeTypeCast);
|
2015-05-02 03:36:25 +08:00
|
|
|
if (!getLangOpts().CPlusPlus && MaybeTypeCast && Result.isUsable()) {
|
|
|
|
// Correct typos in non-C++ code earlier so that implicit-cast-like
|
|
|
|
// expressions are parsed correctly.
|
|
|
|
Result = Actions.CorrectDelayedTyposInExpr(Result);
|
|
|
|
}
|
2011-04-06 10:35:25 +08:00
|
|
|
|
2018-07-28 05:55:12 +08:00
|
|
|
if (ExprType >= FoldExpr && isFoldOperator(Tok.getKind()) &&
|
|
|
|
NextToken().is(tok::ellipsis)) {
|
|
|
|
ExprType = FoldExpr;
|
2014-11-08 13:07:16 +08:00
|
|
|
return ParseFoldExpression(Result, T);
|
2018-07-28 05:55:12 +08:00
|
|
|
}
|
|
|
|
ExprType = SimpleExpr;
|
2014-11-08 13:07:16 +08:00
|
|
|
|
2011-04-06 10:35:25 +08:00
|
|
|
// Don't build a paren expression unless we actually match a ')'.
|
2008-12-09 21:15:23 +08:00
|
|
|
if (!Result.isInvalid() && Tok.is(tok::r_paren))
|
2014-05-04 05:57:40 +08:00
|
|
|
Result =
|
2014-05-29 18:55:11 +08:00
|
|
|
Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.get());
|
2006-08-11 06:01:51 +08:00
|
|
|
}
|
2008-12-12 06:33:27 +08:00
|
|
|
|
2006-08-11 07:14:52 +08:00
|
|
|
// Match the ')'.
|
2008-12-12 14:00:12 +08:00
|
|
|
if (Result.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2008-12-12 14:00:12 +08:00
|
|
|
return ExprError();
|
2006-08-24 14:37:51 +08:00
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
|
|
|
RParenLoc = T.getCloseLocation();
|
2012-08-24 05:35:17 +08:00
|
|
|
return Result;
|
2006-08-10 12:23:57 +08:00
|
|
|
}
|
2006-10-06 13:22:26 +08:00
|
|
|
|
2009-05-22 18:24:05 +08:00
|
|
|
/// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name
|
|
|
|
/// and we are at the left brace.
|
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2009-05-22 18:24:05 +08:00
|
|
|
/// postfix-expression: [C99 6.5.2]
|
|
|
|
/// '(' type-name ')' '{' initializer-list '}'
|
|
|
|
/// '(' type-name ')' '{' initializer-list ',' '}'
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult
|
2010-08-24 13:47:05 +08:00
|
|
|
Parser::ParseCompoundLiteralExpression(ParsedType Ty,
|
2009-05-22 18:24:05 +08:00
|
|
|
SourceLocation LParenLoc,
|
|
|
|
SourceLocation RParenLoc) {
|
|
|
|
assert(Tok.is(tok::l_brace) && "Not a compound literal!");
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().C99) // Compound literals don't exist in C90.
|
2009-05-22 18:24:05 +08:00
|
|
|
Diag(LParenLoc, diag::ext_c99_compound_literal);
|
2020-12-01 16:58:56 +08:00
|
|
|
PreferredType.enterTypeCast(Tok.getLocation(), Ty.get());
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Result = ParseInitializer();
|
2009-05-22 18:24:05 +08:00
|
|
|
if (!Result.isInvalid() && Ty)
|
2014-05-29 18:55:11 +08:00
|
|
|
return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.get());
|
2012-08-24 05:35:17 +08:00
|
|
|
return Result;
|
2009-05-22 18:24:05 +08:00
|
|
|
}
|
|
|
|
|
2006-10-06 13:22:26 +08:00
|
|
|
/// ParseStringLiteralExpression - This handles the various token types that
|
|
|
|
/// form string literals, and also handles string concatenation [C99 5.1.1.2,
|
|
|
|
/// translation phase #6].
|
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2006-10-06 13:22:26 +08:00
|
|
|
/// primary-expression: [C99 6.5.1]
|
|
|
|
/// string-literal
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2012-03-06 11:21:47 +08:00
|
|
|
ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral) {
|
2006-10-06 13:22:26 +08:00
|
|
|
assert(isTokenStringLiteral() && "Not a string literal!");
|
2008-12-12 06:51:44 +08:00
|
|
|
|
2006-10-06 13:22:26 +08:00
|
|
|
// String concat. Note that keywords like __func__ and __FUNCTION__ are not
|
|
|
|
// considered to be strings for concatenation purposes.
|
2011-07-23 18:55:15 +08:00
|
|
|
SmallVector<Token, 4> StringToks;
|
2008-12-12 06:51:44 +08:00
|
|
|
|
2006-10-06 13:22:26 +08:00
|
|
|
do {
|
|
|
|
StringToks.push_back(Tok);
|
|
|
|
ConsumeStringToken();
|
|
|
|
} while (isTokenStringLiteral());
|
2006-11-09 14:34:47 +08:00
|
|
|
|
|
|
|
// Pass the set of string tokens, ready for concatenation, to the actions.
|
2014-06-26 12:58:39 +08:00
|
|
|
return Actions.ActOnStringLiteral(StringToks,
|
2014-05-21 14:02:52 +08:00
|
|
|
AllowUserDefinedLiteral ? getCurScope()
|
|
|
|
: nullptr);
|
2006-10-06 13:22:26 +08:00
|
|
|
}
|
2008-08-17 04:03:01 +08:00
|
|
|
|
2011-12-24 01:00:35 +08:00
|
|
|
/// ParseGenericSelectionExpression - Parse a C11 generic-selection
|
|
|
|
/// [C11 6.5.1.1].
|
2011-04-15 08:35:48 +08:00
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2011-04-15 08:35:48 +08:00
|
|
|
/// generic-selection:
|
|
|
|
/// _Generic ( assignment-expression , generic-assoc-list )
|
|
|
|
/// generic-assoc-list:
|
|
|
|
/// generic-association
|
|
|
|
/// generic-assoc-list , generic-association
|
|
|
|
/// generic-association:
|
|
|
|
/// type-name : assignment-expression
|
|
|
|
/// default : assignment-expression
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2011-04-15 08:35:48 +08:00
|
|
|
ExprResult Parser::ParseGenericSelectionExpression() {
|
|
|
|
assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected");
|
2012-03-11 15:00:24 +08:00
|
|
|
if (!getLangOpts().C11)
|
2019-08-27 22:41:39 +08:00
|
|
|
Diag(Tok, diag::ext_c11_feature) << Tok.getName();
|
2011-04-15 08:35:48 +08:00
|
|
|
|
2019-08-27 22:41:39 +08:00
|
|
|
SourceLocation KeyLoc = ConsumeToken();
|
2011-10-13 00:37:45 +08:00
|
|
|
BalancedDelimiterTracker T(*this, tok::l_paren);
|
2014-01-01 11:08:43 +08:00
|
|
|
if (T.expectAndConsume())
|
2011-04-15 08:35:48 +08:00
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
ExprResult ControllingExpr;
|
|
|
|
{
|
2011-12-24 01:00:35 +08:00
|
|
|
// C11 6.5.1.1p3 "The controlling expression of a generic selection is
|
2011-04-15 08:35:48 +08:00
|
|
|
// not evaluated."
|
2017-04-02 05:30:49 +08:00
|
|
|
EnterExpressionEvaluationContext Unevaluated(
|
|
|
|
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
|
2015-03-20 04:56:07 +08:00
|
|
|
ControllingExpr =
|
|
|
|
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
|
2011-04-15 08:35:48 +08:00
|
|
|
if (ControllingExpr.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-04-15 08:35:48 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::comma)) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-04-15 08:35:48 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
SourceLocation DefaultLoc;
|
2012-08-24 06:51:59 +08:00
|
|
|
TypeVector Types;
|
|
|
|
ExprVector Exprs;
|
2013-12-17 22:12:37 +08:00
|
|
|
do {
|
2011-04-15 08:35:48 +08:00
|
|
|
ParsedType Ty;
|
|
|
|
if (Tok.is(tok::kw_default)) {
|
2011-12-24 01:00:35 +08:00
|
|
|
// C11 6.5.1.1p2 "A generic selection shall have no more than one default
|
2011-04-15 08:35:48 +08:00
|
|
|
// generic association."
|
|
|
|
if (!DefaultLoc.isInvalid()) {
|
|
|
|
Diag(Tok, diag::err_duplicate_default_assoc);
|
|
|
|
Diag(DefaultLoc, diag::note_previous_default_assoc);
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-04-15 08:35:48 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
DefaultLoc = ConsumeToken();
|
2016-01-16 07:43:34 +08:00
|
|
|
Ty = nullptr;
|
2011-04-15 08:35:48 +08:00
|
|
|
} else {
|
|
|
|
ColonProtectionRAIIObject X(*this);
|
|
|
|
TypeResult TR = ParseTypeName();
|
|
|
|
if (TR.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-04-15 08:35:48 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2014-05-29 18:55:11 +08:00
|
|
|
Ty = TR.get();
|
2011-04-15 08:35:48 +08:00
|
|
|
}
|
|
|
|
Types.push_back(Ty);
|
|
|
|
|
2014-01-01 11:08:43 +08:00
|
|
|
if (ExpectAndConsume(tok::colon)) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-04-15 08:35:48 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: These expressions should be parsed in a potentially potentially
|
|
|
|
// evaluated context.
|
2015-03-20 04:56:07 +08:00
|
|
|
ExprResult ER(
|
|
|
|
Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()));
|
2011-04-15 08:35:48 +08:00
|
|
|
if (ER.isInvalid()) {
|
2013-11-18 16:17:37 +08:00
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
2011-04-15 08:35:48 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2014-05-29 18:55:11 +08:00
|
|
|
Exprs.push_back(ER.get());
|
2013-12-17 22:12:37 +08:00
|
|
|
} while (TryConsumeToken(tok::comma));
|
2011-04-15 08:35:48 +08:00
|
|
|
|
2011-10-13 00:37:45 +08:00
|
|
|
T.consumeClose();
|
|
|
|
if (T.getCloseLocation().isInvalid())
|
2011-04-15 08:35:48 +08:00
|
|
|
return ExprError();
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc,
|
2011-10-13 00:37:45 +08:00
|
|
|
T.getCloseLocation(),
|
2014-05-29 18:55:11 +08:00
|
|
|
ControllingExpr.get(),
|
2012-08-24 05:35:17 +08:00
|
|
|
Types, Exprs);
|
2011-04-15 08:35:48 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
/// Parse A C++1z fold-expression after the opening paren and optional
|
2014-11-08 13:07:16 +08:00
|
|
|
/// left-hand-side expression.
|
|
|
|
///
|
|
|
|
/// \verbatim
|
|
|
|
/// fold-expression:
|
|
|
|
/// ( cast-expression fold-operator ... )
|
|
|
|
/// ( ... fold-operator cast-expression )
|
|
|
|
/// ( cast-expression fold-operator ... fold-operator cast-expression )
|
|
|
|
ExprResult Parser::ParseFoldExpression(ExprResult LHS,
|
|
|
|
BalancedDelimiterTracker &T) {
|
|
|
|
if (LHS.isInvalid()) {
|
|
|
|
T.skipToEnd();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
tok::TokenKind Kind = tok::unknown;
|
|
|
|
SourceLocation FirstOpLoc;
|
|
|
|
if (LHS.isUsable()) {
|
|
|
|
Kind = Tok.getKind();
|
|
|
|
assert(isFoldOperator(Kind) && "missing fold-operator");
|
|
|
|
FirstOpLoc = ConsumeToken();
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(Tok.is(tok::ellipsis) && "not a fold-expression");
|
|
|
|
SourceLocation EllipsisLoc = ConsumeToken();
|
|
|
|
|
|
|
|
ExprResult RHS;
|
|
|
|
if (Tok.isNot(tok::r_paren)) {
|
|
|
|
if (!isFoldOperator(Tok.getKind()))
|
|
|
|
return Diag(Tok.getLocation(), diag::err_expected_fold_operator);
|
|
|
|
|
|
|
|
if (Kind != tok::unknown && Tok.getKind() != Kind)
|
|
|
|
Diag(Tok.getLocation(), diag::err_fold_operator_mismatch)
|
|
|
|
<< SourceRange(FirstOpLoc);
|
|
|
|
Kind = Tok.getKind();
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
RHS = ParseExpression();
|
|
|
|
if (RHS.isInvalid()) {
|
|
|
|
T.skipToEnd();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-05 04:27:34 +08:00
|
|
|
Diag(EllipsisLoc, getLangOpts().CPlusPlus17
|
2014-11-08 13:07:16 +08:00
|
|
|
? diag::warn_cxx14_compat_fold_expression
|
|
|
|
: diag::ext_fold_expression);
|
|
|
|
|
|
|
|
T.consumeClose();
|
2020-08-07 06:57:35 +08:00
|
|
|
return Actions.ActOnCXXFoldExpr(getCurScope(), T.getOpenLocation(), LHS.get(),
|
|
|
|
Kind, EllipsisLoc, RHS.get(),
|
|
|
|
T.getCloseLocation());
|
2014-11-08 13:07:16 +08:00
|
|
|
}
|
|
|
|
|
2008-08-17 04:03:01 +08:00
|
|
|
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
|
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2008-08-17 04:03:01 +08:00
|
|
|
/// argument-expression-list:
|
|
|
|
/// assignment-expression
|
|
|
|
/// argument-expression-list , assignment-expression
|
|
|
|
///
|
|
|
|
/// [C++] expression-list:
|
2011-06-05 20:23:16 +08:00
|
|
|
/// [C++] assignment-expression
|
|
|
|
/// [C++] expression-list , assignment-expression
|
|
|
|
///
|
|
|
|
/// [C++0x] expression-list:
|
|
|
|
/// [C++0x] initializer-list
|
|
|
|
///
|
|
|
|
/// [C++0x] initializer-list
|
|
|
|
/// [C++0x] initializer-clause ...[opt]
|
|
|
|
/// [C++0x] initializer-list , initializer-clause ...[opt]
|
|
|
|
///
|
|
|
|
/// [C++0x] initializer-clause:
|
|
|
|
/// [C++0x] assignment-expression
|
|
|
|
/// [C++0x] braced-init-list
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2015-01-22 00:24:11 +08:00
|
|
|
bool Parser::ParseExpressionList(SmallVectorImpl<Expr *> &Exprs,
|
2013-01-13 03:30:44 +08:00
|
|
|
SmallVectorImpl<SourceLocation> &CommaLocs,
|
2022-02-09 02:27:52 +08:00
|
|
|
llvm::function_ref<void()> ExpressionStarts,
|
|
|
|
bool FailImmediatelyOnInvalidExpr,
|
|
|
|
bool EarlyTypoCorrection) {
|
2014-07-15 06:48:10 +08:00
|
|
|
bool SawError = false;
|
2022-01-09 16:19:47 +08:00
|
|
|
while (true) {
|
2019-02-26 19:01:50 +08:00
|
|
|
if (ExpressionStarts)
|
|
|
|
ExpressionStarts();
|
2011-06-05 20:23:16 +08:00
|
|
|
|
|
|
|
ExprResult Expr;
|
2013-01-02 19:42:31 +08:00
|
|
|
if (getLangOpts().CPlusPlus11 && Tok.is(tok::l_brace)) {
|
2011-10-15 13:09:34 +08:00
|
|
|
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
|
2011-06-05 20:23:16 +08:00
|
|
|
Expr = ParseBraceInitializer();
|
2011-10-15 13:09:34 +08:00
|
|
|
} else
|
2011-06-05 20:23:16 +08:00
|
|
|
Expr = ParseAssignmentExpression();
|
|
|
|
|
2022-02-09 02:27:52 +08:00
|
|
|
if (EarlyTypoCorrection)
|
|
|
|
Expr = Actions.CorrectDelayedTyposInExpr(Expr);
|
|
|
|
|
2011-01-04 03:31:53 +08:00
|
|
|
if (Tok.is(tok::ellipsis))
|
2018-07-31 03:24:48 +08:00
|
|
|
Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());
|
2020-01-22 21:10:01 +08:00
|
|
|
else if (Tok.is(tok::code_completion)) {
|
|
|
|
// There's nothing to suggest in here as we parsed a full expression.
|
|
|
|
// Instead fail and propogate the error since caller might have something
|
|
|
|
// the suggest, e.g. signature help in function call. Note that this is
|
|
|
|
// performed before pushing the \p Expr, so that signature help can report
|
|
|
|
// current argument correctly.
|
|
|
|
SawError = true;
|
|
|
|
cutOffParsing();
|
|
|
|
break;
|
|
|
|
}
|
2014-07-15 06:48:10 +08:00
|
|
|
if (Expr.isInvalid()) {
|
|
|
|
SawError = true;
|
2022-02-09 02:27:52 +08:00
|
|
|
if (FailImmediatelyOnInvalidExpr)
|
|
|
|
break;
|
|
|
|
SkipUntil(tok::comma, tok::r_paren, StopBeforeMatch);
|
2014-07-15 06:48:10 +08:00
|
|
|
} else {
|
|
|
|
Exprs.push_back(Expr.get());
|
|
|
|
}
|
2008-08-17 04:03:01 +08:00
|
|
|
|
|
|
|
if (Tok.isNot(tok::comma))
|
2014-11-22 02:48:04 +08:00
|
|
|
break;
|
2008-08-17 04:03:01 +08:00
|
|
|
// Move to the next argument, remember where the comma was.
|
2018-06-27 09:32:04 +08:00
|
|
|
Token Comma = Tok;
|
2008-08-17 04:03:01 +08:00
|
|
|
CommaLocs.push_back(ConsumeToken());
|
2018-06-27 09:32:04 +08:00
|
|
|
|
|
|
|
checkPotentialAngleBracketDelimiter(Comma);
|
2008-08-17 04:03:01 +08:00
|
|
|
}
|
2014-11-22 02:48:04 +08:00
|
|
|
if (SawError) {
|
|
|
|
// Ensure typos get diagnosed when errors were encountered while parsing the
|
|
|
|
// expression list.
|
|
|
|
for (auto &E : Exprs) {
|
|
|
|
ExprResult Expr = Actions.CorrectDelayedTyposInExpr(E);
|
|
|
|
if (Expr.isUsable()) E = Expr.get();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return SawError;
|
2008-08-17 04:03:01 +08:00
|
|
|
}
|
2008-08-29 03:20:44 +08:00
|
|
|
|
2013-08-14 07:38:34 +08:00
|
|
|
/// ParseSimpleExpressionList - A simple comma-separated list of expressions,
|
|
|
|
/// used for misc language extensions.
|
|
|
|
///
|
|
|
|
/// \verbatim
|
|
|
|
/// simple-expression-list:
|
|
|
|
/// assignment-expression
|
|
|
|
/// simple-expression-list , assignment-expression
|
|
|
|
/// \endverbatim
|
|
|
|
bool
|
|
|
|
Parser::ParseSimpleExpressionList(SmallVectorImpl<Expr*> &Exprs,
|
|
|
|
SmallVectorImpl<SourceLocation> &CommaLocs) {
|
2022-01-09 16:19:47 +08:00
|
|
|
while (true) {
|
2013-08-14 07:38:34 +08:00
|
|
|
ExprResult Expr = ParseAssignmentExpression();
|
|
|
|
if (Expr.isInvalid())
|
|
|
|
return true;
|
|
|
|
|
2014-05-29 18:55:11 +08:00
|
|
|
Exprs.push_back(Expr.get());
|
2013-08-14 07:38:34 +08:00
|
|
|
|
|
|
|
if (Tok.isNot(tok::comma))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Move to the next argument, remember where the comma was.
|
2018-06-27 09:32:04 +08:00
|
|
|
Token Comma = Tok;
|
2013-08-14 07:38:34 +08:00
|
|
|
CommaLocs.push_back(ConsumeToken());
|
2018-06-27 09:32:04 +08:00
|
|
|
|
|
|
|
checkPotentialAngleBracketDelimiter(Comma);
|
2013-08-14 07:38:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-05 06:31:32 +08:00
|
|
|
/// ParseBlockId - Parse a block-id, which roughly looks like int (int x).
|
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2009-02-05 06:31:32 +08:00
|
|
|
/// [clang] block-id:
|
|
|
|
/// [clang] specifier-qualifier-list block-declarator
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2012-06-16 00:59:29 +08:00
|
|
|
void Parser::ParseBlockId(SourceLocation CaretLoc) {
|
2010-10-19 05:34:55 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
2021-03-12 19:00:54 +08:00
|
|
|
cutOffParsing();
|
2010-10-19 05:34:55 +08:00
|
|
|
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Type);
|
2021-03-12 19:00:54 +08:00
|
|
|
return;
|
2010-10-19 05:34:55 +08:00
|
|
|
}
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2009-02-05 06:31:32 +08:00
|
|
|
// Parse the specifier-qualifier-list piece.
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2009-02-05 06:31:32 +08:00
|
|
|
ParseSpecifierQualifierList(DS);
|
|
|
|
|
|
|
|
// Parse the block-declarator.
|
2020-11-11 13:40:12 +08:00
|
|
|
Declarator DeclaratorInfo(DS, DeclaratorContext::BlockLiteral);
|
2020-11-21 23:49:52 +08:00
|
|
|
DeclaratorInfo.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
|
2009-02-05 06:31:32 +08:00
|
|
|
ParseDeclarator(DeclaratorInfo);
|
2009-04-30 03:03:13 +08:00
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(DeclaratorInfo);
|
2009-04-30 03:03:13 +08:00
|
|
|
|
2009-02-05 06:31:32 +08:00
|
|
|
// Inform sema that we are starting a block.
|
2012-06-16 00:59:29 +08:00
|
|
|
Actions.ActOnBlockArguments(CaretLoc, DeclaratorInfo, getCurScope());
|
2009-02-05 06:31:32 +08:00
|
|
|
}
|
|
|
|
|
2008-08-29 03:20:44 +08:00
|
|
|
/// ParseBlockLiteralExpression - Parse a block literal, which roughly looks
|
2008-09-17 07:11:46 +08:00
|
|
|
/// like ^(int x){ return x+1; }
|
2008-08-29 03:20:44 +08:00
|
|
|
///
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \verbatim
|
2008-08-29 03:20:44 +08:00
|
|
|
/// block-literal:
|
|
|
|
/// [clang] '^' block-args[opt] compound-statement
|
2009-02-05 06:31:32 +08:00
|
|
|
/// [clang] '^' block-id compound-statement
|
2008-08-29 03:20:44 +08:00
|
|
|
/// [clang] block-args:
|
|
|
|
/// [clang] '(' parameter-list ')'
|
2012-06-17 12:36:28 +08:00
|
|
|
/// \endverbatim
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Parser::ParseBlockLiteralExpression() {
|
2008-08-29 03:20:44 +08:00
|
|
|
assert(Tok.is(tok::caret) && "block literal starts with ^");
|
|
|
|
SourceLocation CaretLoc = ConsumeToken();
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2009-03-05 15:32:12 +08:00
|
|
|
PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), CaretLoc,
|
|
|
|
"block literal parsing");
|
|
|
|
|
2009-09-09 23:08:12 +08:00
|
|
|
// Enter a scope to hold everything within the block. This includes the
|
2008-08-29 03:20:44 +08:00
|
|
|
// argument decls, decls within the compound expression, etc. This also
|
|
|
|
// allows determining whether a variable reference inside the block is
|
|
|
|
// within or outside of the block.
|
2009-02-10 02:23:29 +08:00
|
|
|
ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope |
|
2017-08-10 23:43:06 +08:00
|
|
|
Scope::CompoundStmtScope | Scope::DeclScope);
|
2008-10-10 09:28:17 +08:00
|
|
|
|
|
|
|
// Inform sema that we are starting a block.
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnBlockStart(CaretLoc, getCurScope());
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2008-08-29 03:20:44 +08:00
|
|
|
// Parse the return type if present.
|
2011-03-24 19:26:52 +08:00
|
|
|
DeclSpec DS(AttrFactory);
|
2020-11-11 13:40:12 +08:00
|
|
|
Declarator ParamInfo(DS, DeclaratorContext::BlockLiteral);
|
2020-11-21 23:49:52 +08:00
|
|
|
ParamInfo.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
|
2009-02-10 02:23:29 +08:00
|
|
|
// FIXME: Since the return type isn't actually parsed, it can't be used to
|
|
|
|
// fill ParamInfo with an initial valid range, so do it manually.
|
|
|
|
ParamInfo.SetSourceRange(SourceRange(Tok.getLocation(), Tok.getLocation()));
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2008-08-29 03:20:44 +08:00
|
|
|
// If this block has arguments, parse them. There is no ambiguity here with
|
|
|
|
// the expression case, because the expression case requires a parameter list.
|
|
|
|
if (Tok.is(tok::l_paren)) {
|
|
|
|
ParseParenDeclarator(ParamInfo);
|
|
|
|
// Parse the pieces after the identifier as if we had "int(...)".
|
2009-02-10 02:23:29 +08:00
|
|
|
// SetIdentifier sets the source range end, but in this case we're past
|
|
|
|
// that location.
|
|
|
|
SourceLocation Tmp = ParamInfo.getSourceRange().getEnd();
|
2014-05-21 14:02:52 +08:00
|
|
|
ParamInfo.SetIdentifier(nullptr, CaretLoc);
|
2009-02-10 02:23:29 +08:00
|
|
|
ParamInfo.SetRangeEnd(Tmp);
|
2009-04-25 16:06:05 +08:00
|
|
|
if (ParamInfo.isInvalidType()) {
|
2009-02-05 06:31:32 +08:00
|
|
|
// If there was an error parsing the arguments, they may have
|
|
|
|
// tried to use ^(x+y) which requires an argument list. Just
|
|
|
|
// skip the whole block literal.
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnBlockError(CaretLoc, getCurScope());
|
2008-12-13 23:32:12 +08:00
|
|
|
return ExprError();
|
2008-08-29 03:20:44 +08:00
|
|
|
}
|
2009-04-30 03:03:13 +08:00
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(ParamInfo);
|
2009-04-30 03:03:13 +08:00
|
|
|
|
2009-02-05 06:31:32 +08:00
|
|
|
// Inform sema that we are starting a block.
|
2012-06-16 00:59:29 +08:00
|
|
|
Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope());
|
2009-04-15 02:24:37 +08:00
|
|
|
} else if (!Tok.is(tok::l_brace)) {
|
2012-06-16 00:59:29 +08:00
|
|
|
ParseBlockId(CaretLoc);
|
2008-08-29 03:20:44 +08:00
|
|
|
} else {
|
|
|
|
// Otherwise, pretend we saw (void).
|
2012-10-05 05:42:10 +08:00
|
|
|
SourceLocation NoLoc;
|
2018-07-13 05:09:05 +08:00
|
|
|
ParamInfo.AddTypeInfo(
|
|
|
|
DeclaratorChunk::getFunction(/*HasProto=*/true,
|
|
|
|
/*IsAmbiguous=*/false,
|
|
|
|
/*RParenLoc=*/NoLoc,
|
|
|
|
/*ArgInfo=*/nullptr,
|
2019-07-16 12:46:31 +08:00
|
|
|
/*NumParams=*/0,
|
2018-07-13 05:09:05 +08:00
|
|
|
/*EllipsisLoc=*/NoLoc,
|
|
|
|
/*RParenLoc=*/NoLoc,
|
|
|
|
/*RefQualifierIsLvalueRef=*/true,
|
|
|
|
/*RefQualifierLoc=*/NoLoc,
|
|
|
|
/*MutableLoc=*/NoLoc, EST_None,
|
|
|
|
/*ESpecRange=*/SourceRange(),
|
|
|
|
/*Exceptions=*/nullptr,
|
|
|
|
/*ExceptionRanges=*/nullptr,
|
|
|
|
/*NumExceptions=*/0,
|
|
|
|
/*NoexceptExpr=*/nullptr,
|
|
|
|
/*ExceptionSpecTokens=*/nullptr,
|
|
|
|
/*DeclsInPrototype=*/None, CaretLoc,
|
|
|
|
CaretLoc, ParamInfo),
|
|
|
|
CaretLoc);
|
2009-04-30 03:03:13 +08:00
|
|
|
|
2010-12-24 10:08:15 +08:00
|
|
|
MaybeParseGNUAttributes(ParamInfo);
|
2009-04-30 03:03:13 +08:00
|
|
|
|
2009-02-05 06:31:32 +08:00
|
|
|
// Inform sema that we are starting a block.
|
2012-06-16 00:59:29 +08:00
|
|
|
Actions.ActOnBlockArguments(CaretLoc, ParamInfo, getCurScope());
|
2008-08-29 03:20:44 +08:00
|
|
|
}
|
|
|
|
|
2008-12-13 23:32:12 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
ExprResult Result(true);
|
2009-03-27 12:18:06 +08:00
|
|
|
if (!Tok.is(tok::l_brace)) {
|
2009-01-15 03:39:53 +08:00
|
|
|
// Saw something like: ^expr
|
|
|
|
Diag(Tok, diag::err_expected_expression);
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnBlockError(CaretLoc, getCurScope());
|
2009-01-15 03:39:53 +08:00
|
|
|
return ExprError();
|
|
|
|
}
|
2009-09-09 23:08:12 +08:00
|
|
|
|
2010-08-24 14:29:42 +08:00
|
|
|
StmtResult Stmt(ParseCompoundStatementBody());
|
2011-03-17 01:05:57 +08:00
|
|
|
BlockScope.Exit();
|
2009-03-27 12:18:06 +08:00
|
|
|
if (!Stmt.isInvalid())
|
2014-05-29 18:55:11 +08:00
|
|
|
Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.get(), getCurScope());
|
2009-03-27 12:18:06 +08:00
|
|
|
else
|
2010-07-03 01:43:08 +08:00
|
|
|
Actions.ActOnBlockError(CaretLoc, getCurScope());
|
2012-08-24 05:35:17 +08:00
|
|
|
return Result;
|
2008-08-29 03:20:44 +08:00
|
|
|
}
|
2012-03-07 04:05:56 +08:00
|
|
|
|
|
|
|
/// ParseObjCBoolLiteral - This handles the objective-c Boolean literals.
|
|
|
|
///
|
|
|
|
/// '__objc_yes'
|
|
|
|
/// '__objc_no'
|
|
|
|
ExprResult Parser::ParseObjCBoolLiteral() {
|
|
|
|
tok::TokenKind Kind = Tok.getKind();
|
|
|
|
return Actions.ActOnObjCBoolLiteral(ConsumeToken(), Kind);
|
|
|
|
}
|
2016-07-16 08:35:23 +08:00
|
|
|
|
|
|
|
/// Validate availability spec list, emitting diagnostics if necessary. Returns
|
|
|
|
/// true if invalid.
|
|
|
|
static bool CheckAvailabilitySpecList(Parser &P,
|
|
|
|
ArrayRef<AvailabilitySpec> AvailSpecs) {
|
|
|
|
llvm::SmallSet<StringRef, 4> Platforms;
|
|
|
|
bool HasOtherPlatformSpec = false;
|
|
|
|
bool Valid = true;
|
|
|
|
for (const auto &Spec : AvailSpecs) {
|
|
|
|
if (Spec.isOtherPlatformSpec()) {
|
|
|
|
if (HasOtherPlatformSpec) {
|
|
|
|
P.Diag(Spec.getBeginLoc(), diag::err_availability_query_repeated_star);
|
|
|
|
Valid = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
HasOtherPlatformSpec = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Inserted = Platforms.insert(Spec.getPlatform()).second;
|
|
|
|
if (!Inserted) {
|
|
|
|
// Rule out multiple version specs referring to the same platform.
|
|
|
|
// For example, we emit an error for:
|
|
|
|
// @available(macos 10.10, macos 10.11, *)
|
|
|
|
StringRef Platform = Spec.getPlatform();
|
|
|
|
P.Diag(Spec.getBeginLoc(), diag::err_availability_query_repeated_platform)
|
|
|
|
<< Spec.getEndLoc() << Platform;
|
|
|
|
Valid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!HasOtherPlatformSpec) {
|
|
|
|
SourceLocation InsertWildcardLoc = AvailSpecs.back().getEndLoc();
|
|
|
|
P.Diag(InsertWildcardLoc, diag::err_availability_query_wildcard_required)
|
|
|
|
<< FixItHint::CreateInsertion(InsertWildcardLoc, ", *");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return !Valid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Parse availability query specification.
|
|
|
|
///
|
|
|
|
/// availability-spec:
|
|
|
|
/// '*'
|
|
|
|
/// identifier version-tuple
|
|
|
|
Optional<AvailabilitySpec> Parser::ParseAvailabilitySpec() {
|
|
|
|
if (Tok.is(tok::star)) {
|
|
|
|
return AvailabilitySpec(ConsumeToken());
|
|
|
|
} else {
|
|
|
|
// Parse the platform name.
|
2017-05-10 00:05:04 +08:00
|
|
|
if (Tok.is(tok::code_completion)) {
|
|
|
|
cutOffParsing();
|
2021-03-12 19:00:54 +08:00
|
|
|
Actions.CodeCompleteAvailabilityPlatformName();
|
2017-05-10 00:05:04 +08:00
|
|
|
return None;
|
|
|
|
}
|
2016-07-16 08:35:23 +08:00
|
|
|
if (Tok.isNot(tok::identifier)) {
|
|
|
|
Diag(Tok, diag::err_avail_query_expected_platform_name);
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierLoc *PlatformIdentifier = ParseIdentifierLoc();
|
|
|
|
SourceRange VersionRange;
|
|
|
|
VersionTuple Version = ParseVersionTuple(VersionRange);
|
|
|
|
|
|
|
|
if (Version.empty())
|
|
|
|
return None;
|
|
|
|
|
2017-05-09 23:34:46 +08:00
|
|
|
StringRef GivenPlatform = PlatformIdentifier->Ident->getName();
|
|
|
|
StringRef Platform =
|
|
|
|
AvailabilityAttr::canonicalizePlatformName(GivenPlatform);
|
2016-07-16 08:35:23 +08:00
|
|
|
|
|
|
|
if (AvailabilityAttr::getPrettyPlatformName(Platform).empty()) {
|
|
|
|
Diag(PlatformIdentifier->Loc,
|
|
|
|
diag::err_avail_query_unrecognized_platform_name)
|
2017-05-09 23:34:46 +08:00
|
|
|
<< GivenPlatform;
|
2016-07-16 08:35:23 +08:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
return AvailabilitySpec(Version, Platform, PlatformIdentifier->Loc,
|
|
|
|
VersionRange.getEnd());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ExprResult Parser::ParseAvailabilityCheckExpr(SourceLocation BeginLoc) {
|
|
|
|
assert(Tok.is(tok::kw___builtin_available) ||
|
|
|
|
Tok.isObjCAtKeyword(tok::objc_available));
|
|
|
|
|
|
|
|
// Eat the available or __builtin_available.
|
|
|
|
ConsumeToken();
|
|
|
|
|
|
|
|
BalancedDelimiterTracker Parens(*this, tok::l_paren);
|
|
|
|
if (Parens.expectAndConsume())
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
SmallVector<AvailabilitySpec, 4> AvailSpecs;
|
|
|
|
bool HasError = false;
|
|
|
|
while (true) {
|
|
|
|
Optional<AvailabilitySpec> Spec = ParseAvailabilitySpec();
|
|
|
|
if (!Spec)
|
|
|
|
HasError = true;
|
|
|
|
else
|
|
|
|
AvailSpecs.push_back(*Spec);
|
|
|
|
|
|
|
|
if (!TryConsumeToken(tok::comma))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HasError) {
|
|
|
|
SkipUntil(tok::r_paren, StopAtSemi);
|
|
|
|
return ExprError();
|
|
|
|
}
|
|
|
|
|
|
|
|
CheckAvailabilitySpecList(*this, AvailSpecs);
|
|
|
|
|
|
|
|
if (Parens.consumeClose())
|
|
|
|
return ExprError();
|
|
|
|
|
|
|
|
return Actions.ActOnObjCAvailabilityCheckExpr(AvailSpecs, BeginLoc,
|
|
|
|
Parens.getCloseLocation());
|
|
|
|
}
|