in tools/clang/lib/Parse/ParseExpr.cpp [695:1464]
ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
bool isAddressOfOperand,
bool &NotCastExpr,
TypeCastState isTypeCast) {
ExprResult Res;
tok::TokenKind SavedKind = Tok.getKind();
NotCastExpr = false;
// 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
// break out of the switch; at the end we call ParsePostfixExpressionSuffix
// to handle the postfix expression suffixes. Cases that cannot be followed
// by postfix exprs should return without invoking
// ParsePostfixExpressionSuffix.
switch (SavedKind) {
case tok::l_paren: {
// If this expression is limited to being a unary-expression, the parent can
// not start a cast expression.
ParenParseOption ParenExprType =
(isUnaryExpression && !getLangOpts().CPlusPlus) ? CompoundLiteral
: CastExpr;
ParsedType CastTy;
SourceLocation RParenLoc;
Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/,
isTypeCast == IsTypeCast, CastTy, RParenLoc);
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:
// We have parsed the cast-expression and no postfix-expr pieces are
// following.
return Res;
}
break;
}
// primary-expression
case tok::numeric_constant:
// constant: integer-constant
// constant: floating-constant
Res = Actions.ActOnNumericConstant(Tok, /*UDLScope*/getCurScope());
ConsumeToken();
break;
case tok::kw_true:
case tok::kw_false:
return ParseCXXBoolLiteral();
case tok::kw___objc_yes:
case tok::kw___objc_no:
// HLSL Change Starts
HLSLReservedKeyword:
if (getLangOpts().HLSL) {
Diag(Tok, diag::err_hlsl_reserved_keyword) << Tok.getName();
return ExprError();
}
// HLSL Change Ends
return ParseObjCBoolLiteral();
case tok::kw_nullptr:
// HLSL Change Starts
assert(!getLangOpts().HLSL && "nullptr is not a keyword in HLSL");
if (getLangOpts().HLSL) goto tok_default_case;
// HLSL Change Ends
Diag(Tok, diag::warn_cxx98_compat_nullptr);
return Actions.ActOnCXXNullPtrLiteral(ConsumeToken());
case tok::annot_primary_expr:
assert(Res.get() == nullptr && "Stray primary-expression annotation?");
Res = getExprAnnotation(Tok);
ConsumeToken();
break;
case tok::kw___super:
case tok::kw_decltype:
// HLSL Change Starts
assert(!getLangOpts().HLSL && "decltype is not a keyword in HLSL");
if (getLangOpts().HLSL) goto tok_default_case;
// HLSL Change Ends
// Annotate the token and tail recurse.
if (TryAnnotateTypeOrScopeToken())
return ExprError();
assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super));
return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
// HLSL Change Starts
case tok::kw_precise:
case tok::kw_sample:
case tok::kw_globallycoherent:
case tok::kw_center:
case tok::kw_indices:
case tok::kw_vertices:
case tok::kw_primitives:
case tok::kw_payload:
// Back-compat: 'precise', 'globallycoherent', 'center' and 'sample' are keywords when used as an interpolation
// modifiers, but in FXC they can also be used an identifiers. No interpolation modifiers are expected here
// so we need to change the token type to tok::identifier and fall through to the next case.
// Similarly 'indices', 'vertices', 'primitives' and 'payload' are keywords when used
// as a type qualifer in mesh shader, but may still be used as a variable name.
Tok.setKind(tok::identifier);
__fallthrough;
// HLSL Change Ends
case tok::identifier: { // primary-expression: identifier
// unqualified-id: identifier
// constant: enumeration-constant
// Turn a potentially qualified name into a annot_typename or
// annot_cxxscope if it would be valid. This handles things like x::y, etc.
if (getLangOpts().CPlusPlus) {
// Avoid the unnecessary parse-time lookup in the common case
// where the syntax forbids a type.
const Token &Next = NextToken();
// 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.
if (Next.is(tok::l_paren) && !getLangOpts().HLSL && // HLSL Change - no type trait support in HLSL
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)
REVERTIBLE_TYPE_TRAIT(__is_abstract);
REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
REVERTIBLE_TYPE_TRAIT(__is_array);
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);
REVERTIBLE_TYPE_TRAIT(__is_convertible);
REVERTIBLE_TYPE_TRAIT(__is_convertible_to);
REVERTIBLE_TYPE_TRAIT(__is_destructible);
REVERTIBLE_TYPE_TRAIT(__is_empty);
REVERTIBLE_TYPE_TRAIT(__is_enum);
REVERTIBLE_TYPE_TRAIT(__is_floating_point);
REVERTIBLE_TYPE_TRAIT(__is_final);
REVERTIBLE_TYPE_TRAIT(__is_function);
REVERTIBLE_TYPE_TRAIT(__is_fundamental);
REVERTIBLE_TYPE_TRAIT(__is_integral);
REVERTIBLE_TYPE_TRAIT(__is_interface_class);
REVERTIBLE_TYPE_TRAIT(__is_literal);
REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer);
REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable);
REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible);
REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible);
REVERTIBLE_TYPE_TRAIT(__is_object);
REVERTIBLE_TYPE_TRAIT(__is_pod);
REVERTIBLE_TYPE_TRAIT(__is_pointer);
REVERTIBLE_TYPE_TRAIT(__is_polymorphic);
REVERTIBLE_TYPE_TRAIT(__is_reference);
REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr);
REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference);
REVERTIBLE_TYPE_TRAIT(__is_same);
REVERTIBLE_TYPE_TRAIT(__is_scalar);
REVERTIBLE_TYPE_TRAIT(__is_sealed);
REVERTIBLE_TYPE_TRAIT(__is_signed);
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);
REVERTIBLE_TYPE_TRAIT(__is_unsigned);
REVERTIBLE_TYPE_TRAIT(__is_void);
REVERTIBLE_TYPE_TRAIT(__is_volatile);
#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);
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
NotCastExpr, isTypeCast);
}
}
if ((!ColonIsSacred && Next.is(tok::colon)) ||
Next.isOneOf(tok::coloncolon, tok::less, tok::l_paren,
tok::l_brace)) {
// If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
if (TryAnnotateTypeOrScopeToken())
return ExprError();
if (!Tok.is(tok::identifier))
return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
}
}
// Consume the identifier so that we can see if it is followed by a '(' or
// '.'.
IdentifierInfo &II = *Tok.getIdentifierInfo();
SourceLocation ILoc = ConsumeToken();
// Support 'Class.property' and 'super.property' notation.
if (getLangOpts().ObjC1 && Tok.is(tok::period) &&
(Actions.getTypeName(II, ILoc, getCurScope()) ||
// Allow the base to be 'super' if in an objc-method.
(&II == Ident_super && getCurScope()->isInObjcMethodScope()))) {
ConsumeToken();
// Allow either an identifier or the keyword 'class' (in C++).
if (Tok.isNot(tok::identifier) &&
!(getLangOpts().CPlusPlus && Tok.is(tok::kw_class))) {
Diag(Tok, diag::err_expected_property_name);
return ExprError();
}
IdentifierInfo &PropertyName = *Tok.getIdentifierInfo();
SourceLocation PropertyLoc = ConsumeToken();
Res = Actions.ActOnClassPropertyRefExpr(II, PropertyName,
ILoc, PropertyLoc);
break;
}
// In an Objective-C method, if we have "super" followed by an identifier,
// the token sequence is ill-formed. However, if there's a ':' or ']' after
// that identifier, this is probably a message send with a missing open
// bracket. Treat it as such.
if (getLangOpts().ObjC1 && &II == Ident_super && !InMessageExpression &&
getCurScope()->isInObjcMethodScope() &&
((Tok.is(tok::identifier) &&
(NextToken().is(tok::colon) || NextToken().is(tok::r_square))) ||
Tok.is(tok::code_completion))) {
Res = ParseObjCMessageExpressionBody(SourceLocation(), ILoc, ParsedType(),
nullptr);
break;
}
// 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.
if (getLangOpts().ObjC1 &&
((Tok.is(tok::identifier) && !InMessageExpression) ||
Tok.is(tok::code_completion))) {
const Token& Next = NextToken();
if (Tok.is(tok::code_completion) ||
Next.is(tok::colon) || Next.is(tok::r_square))
if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope()))
if (Typ.get()->isObjCObjectOrInterfaceType()) {
// Fake up a Declarator to use with ActOnTypeName.
DeclSpec DS(AttrFactory);
DS.SetRangeStart(ILoc);
DS.SetRangeEnd(ILoc);
const char *PrevSpec = nullptr;
unsigned DiagID;
DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ,
Actions.getASTContext().getPrintingPolicy());
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
TypeResult Ty = Actions.ActOnTypeName(getCurScope(),
DeclaratorInfo);
if (Ty.isInvalid())
break;
Res = ParseObjCMessageExpressionBody(SourceLocation(),
SourceLocation(),
Ty.get(), nullptr);
break;
}
}
// Make sure to pass down the right value for isAddressOfOperand.
if (isAddressOfOperand && isPostfixExpressionSuffixStart())
isAddressOfOperand = false;
// 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.
UnqualifiedId Name;
CXXScopeSpec ScopeSpec;
SourceLocation TemplateKWLoc;
Token Replacement;
auto Validator = llvm::make_unique<CastExpressionIdValidator>(
Tok, isTypeCast != NotTypeCast, isTypeCast != IsTypeCast);
Validator->IsAddressOfOperand = isAddressOfOperand;
if (Tok.isOneOf(tok::periodstar, tok::arrowstar)) {
Validator->WantExpressionKeywords = false;
Validator->WantRemainingKeywords = false;
} else {
Validator->WantRemainingKeywords = Tok.isNot(tok::r_paren);
}
Name.setIdentifier(&II, ILoc);
Res = Actions.ActOnIdExpression(
getCurScope(), ScopeSpec, TemplateKWLoc, Name, Tok.is(tok::l_paren),
isAddressOfOperand, std::move(Validator),
/*IsInlineAsmIdentifier=*/false,
Tok.is(tok::r_paren) ? nullptr : &Replacement);
if (!Res.isInvalid() && !Res.get()) {
UnconsumeToken(Replacement);
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
NotCastExpr, isTypeCast);
}
break;
}
case tok::char_constant: // constant: character-constant
case tok::wide_char_constant:
case tok::utf8_char_constant:
case tok::utf16_char_constant:
case tok::utf32_char_constant:
// HLSL Change Starts
// Character constants become 32-bit unsigned ints. That will happen in Sema.
if (getLangOpts().HLSL && Tok.getKind() != tok::char_constant) {
Diag(Tok, diag::err_hlsl_unsupported_construct) << "non-ASCII/multiple-char character constant";
return ExprError();
}
// HLSL Change Ends
Res = Actions.ActOnCharacterConstant(Tok, /*UDLScope*/getCurScope());
ConsumeToken();
break;
case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2]
case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU]
case tok::kw___FUNCDNAME__: // primary-expression: __FUNCDNAME__ [MS]
case tok::kw___FUNCSIG__: // primary-expression: __FUNCSIG__ [MS]
case tok::kw_L__FUNCTION__: // primary-expression: L__FUNCTION__ [MS]
case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU]
// HLSL Change Starts
if (getLangOpts().HLSL) {
Diag(Tok, diag::err_hlsl_reserved_keyword) << Tok.getName();
return ExprError();
}
// HLSL Change Ends
Res = Actions.ActOnPredefinedExpr(Tok.getLocation(), SavedKind);
ConsumeToken();
break;
case tok::string_literal: // primary-expression: string-literal
case tok::wide_string_literal:
case tok::utf8_string_literal:
case tok::utf16_string_literal:
case tok::utf32_string_literal:
// HLSL Change Starts
if (getLangOpts().HLSL && Tok.getKind() != tok::string_literal) {
Diag(Tok, diag::err_hlsl_unsupported_construct) << "non-ASCII string constant";
return ExprError();
}
// HLSL Change Ends
Res = ParseStringLiteralExpression(true);
break;
case tok::kw__Generic: // primary-expression: generic-selection [C11 6.5.1]
// HLSL Change Starts
if (getLangOpts().HLSL) {
Diag(Tok, diag::err_hlsl_reserved_keyword) << Tok.getName();
return ExprError();
}
// HLSL Change Ends
Res = ParseGenericSelectionExpression();
break;
case tok::kw___builtin_va_arg:
case tok::kw___builtin_offsetof:
case tok::kw___builtin_choose_expr:
case tok::kw___builtin_astype: // primary-expression: [OCL] as_type()
case tok::kw___builtin_convertvector:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - not supported
return ParseBuiltinPrimaryExpression();
case tok::kw___null:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - not supported
return Actions.ActOnGNUNullExpr(ConsumeToken());
case tok::plusplus: // unary-expression: '++' unary-expression [C99]
case tok::minusminus: { // unary-expression: '--' unary-expression [C99]
// C++ [expr.unary] has:
// unary-expression:
// ++ cast-expression
// -- cast-expression
SourceLocation SavedLoc = ConsumeToken();
// 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.
Res = ParseCastExpression(!getLangOpts().CPlusPlus,
/*isAddressOfOperand*/false, NotCastExpr,
NotTypeCast);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
return Res;
}
case tok::amp: { // unary-expression: '&' cast-expression
// Special treatment because of member pointers
SourceLocation SavedLoc = ConsumeToken();
Res = ParseCastExpression(false, true);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
return Res;
}
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]
case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU]
// HLSL Change Starts
if (getLangOpts().HLSL && (SavedKind == tok::kw___real || SavedKind == tok::kw___imag)) {
goto HLSLReservedKeyword;
}
// HLSL Change Ends
SourceLocation SavedLoc = ConsumeToken();
Res = ParseCastExpression(false);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
return Res;
}
case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU]
// __extension__ silences extension warnings in the subexpression.
ExtensionRAIIObject O(Diags); // Use RAII to do this.
SourceLocation SavedLoc = ConsumeToken();
Res = ParseCastExpression(false);
if (!Res.isInvalid())
Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
return Res;
}
case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')'
if (!getLangOpts().C11)
Diag(Tok, diag::ext_c11_alignment) << Tok.getName();
// fallthrough
case tok::kw_alignof: // unary-expression: 'alignof' '(' type-id ')'
case tok::kw___alignof: // unary-expression: '__alignof' unary-expression
// unary-expression: '__alignof' '(' type-name ')'
case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression
// unary-expression: 'sizeof' '(' type-name ')'
case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression
// unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')'
case tok::kw___builtin_omp_required_simd_align:
if (getLangOpts().HLSL && Tok.getKind() != tok::kw_sizeof) { goto HLSLReservedKeyword; } // HLSL Change - not supported
return ParseUnaryExprOrTypeTraitExpression();
case tok::ampamp: { // unary-expression: '&&' identifier
// HLSL Change Starts
if (getLangOpts().HLSL) {
Diag(Tok, diag::err_hlsl_unsupported_construct) << "address of label";
return ExprError();
}
// HLSL Change Ends
SourceLocation AmpAmpLoc = ConsumeToken();
if (Tok.isNot(tok::identifier))
return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
if (getCurScope()->getFnParent() == nullptr)
return ExprError(Diag(Tok, diag::err_address_of_label_outside_fn));
Diag(AmpAmpLoc, diag::ext_gnu_address_of_label);
LabelDecl *LD = Actions.LookupOrCreateLabel(Tok.getIdentifierInfo(),
Tok.getLocation());
Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD);
ConsumeToken();
return Res;
}
case tok::kw_const_cast:
case tok::kw_dynamic_cast:
case tok::kw_reinterpret_cast:
case tok::kw_static_cast:
// HLSL Change Starts
if (getLangOpts().HLSL) {
Diag(Tok, diag::err_hlsl_unsupported_construct) << "C++-style cast";
return ExprError();
}
// HLSL Change Ends
Res = ParseCXXCasts();
break;
case tok::kw_typeid:
if (getLangOpts().HLSL) { goto HLSLReservedKeyword; } // HLSL Change - not supported
Res = ParseCXXTypeid();
break;
case tok::kw___uuidof:
// HLSL Change Starts
assert(!getLangOpts().HLSL && "__uuidof is not a keyword in HLSL");
if (getLangOpts().HLSL) goto tok_default_case;
// HLSL Change Ends
Res = ParseCXXUuidof();
break;
case tok::kw_this:
Res = ParseCXXThis();
break;
case tok::annot_typename:
if (isStartOfObjCClassMessageMissingOpenBracket()) {
ParsedType Type = getTypeAnnotation(Tok);
// Fake up a Declarator to use with ActOnTypeName.
DeclSpec DS(AttrFactory);
DS.SetRangeStart(Tok.getLocation());
DS.SetRangeEnd(Tok.getLastLoc());
const char *PrevSpec = nullptr;
unsigned DiagID;
DS.SetTypeSpecType(TST_typename, Tok.getAnnotationEndLoc(),
PrevSpec, DiagID, Type,
Actions.getASTContext().getPrintingPolicy());
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo);
if (Ty.isInvalid())
break;
ConsumeToken();
Res = ParseObjCMessageExpressionBody(SourceLocation(), SourceLocation(),
Ty.get(), nullptr);
break;
}
// Fall through
case tok::annot_decltype:
case tok::kw_char:
case tok::kw_wchar_t:
case tok::kw_char16_t:
case tok::kw_char32_t:
case tok::kw_bool:
case tok::kw_short:
case tok::kw_int:
case tok::kw_long:
case tok::kw___int64:
case tok::kw___int128:
// HLSL Change Starts
case tok::kw_column_major:
case tok::kw_row_major:
case tok::kw_snorm:
case tok::kw_unorm:
// HLSL Change Ends
case tok::kw_signed:
case tok::kw_unsigned:
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
case tok::kw_void:
case tok::kw_typename:
case tok::kw_typeof:
case tok::kw___vector: {
// HLSL Change Starts
if (getLangOpts().HLSL && (
SavedKind == tok::kw_wchar_t || SavedKind == tok::kw_char || SavedKind == tok::kw_char16_t || SavedKind == tok::kw_char32_t ||
SavedKind == tok::kw_short || SavedKind == tok::kw_long || SavedKind == tok::kw___int64 || SavedKind == tok::kw___int128 ||
(SavedKind == tok::kw_typename && !getLangOpts().EnableTemplates) || SavedKind == tok::kw_typeof)) {
// the vector/image/sampler/event keywords aren't returned by the lexer for HLSL
goto HLSLReservedKeyword;
}
// HLSL Change Ends
if (!getLangOpts().CPlusPlus) {
Diag(Tok, diag::err_expected_expression);
return ExprError();
}
if (SavedKind == tok::kw_typename) {
// postfix-expression: typename-specifier '(' expression-list[opt] ')'
// typename-specifier braced-init-list
if (TryAnnotateTypeOrScopeToken())
return ExprError();
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();
}
// postfix-expression: simple-type-specifier '(' expression-list[opt] ')'
// simple-type-specifier braced-init-list
//
DeclSpec DS(AttrFactory);
ParseCXXSimpleTypeSpecifier(DS);
if (Tok.isNot(tok::l_paren) &&
(!getLangOpts().CPlusPlus11 || Tok.isNot(tok::l_brace)))
return ExprError(Diag(Tok, diag::err_expected_lparen_after_type)
<< DS.getSourceRange());
if (Tok.is(tok::l_brace))
Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists);
Res = ParseCXXTypeConstructExpression(DS);
break;
}
case tok::annot_cxxscope: { // [C++] id-expression: qualified-id
// 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))
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
NotCastExpr, isTypeCast);
Token Next = NextToken();
if (Next.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next);
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;
ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
/*EnteringContext=*/false);
AnnotateTemplateIdTokenAsType();
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
NotCastExpr, isTypeCast);
}
}
// Parse as an id-expression.
Res = ParseCXXIdExpression(isAddressOfOperand);
break;
}
case tok::annot_template_id: { // [C++] template-id
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
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.
AnnotateTemplateIdTokenAsType();
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
NotCastExpr, isTypeCast);
}
// Fall through to treat the template-id as an id-expression.
}
case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
if (getLangOpts().HLSL && !getLangOpts().EnableOperatorOverloading &&
SavedKind == tok::kw_operator) {
goto HLSLReservedKeyword; // HLSL Change - 'operator' is reserved
}
Res = ParseCXXIdExpression(isAddressOfOperand);
break;
case tok::coloncolon: {
// ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken
// annotates the token, tail recurse.
if (TryAnnotateTypeOrScopeToken())
return ExprError();
if (!Tok.is(tok::coloncolon))
return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
// ::new -> [C++] new-expression
// ::delete -> [C++] delete-expression
SourceLocation CCLoc = ConsumeToken();
if (Tok.is(tok::kw_new)) {
if (getLangOpts().HLSL) goto HLSLReservedKeyword; // HLSL Change - 'new' is reserved
return ParseCXXNewExpression(true, CCLoc);
}
if (Tok.is(tok::kw_delete)) {
if (getLangOpts().HLSL) goto HLSLReservedKeyword; // HLSL Change - 'delete' is reserved
return ParseCXXDeleteExpression(true, CCLoc);
}
// This is not a type name or scope specifier, it is an invalid expression.
Diag(CCLoc, diag::err_expected_expression);
return ExprError();
}
case tok::kw_new: // [C++] new-expression
if (getLangOpts().HLSL) goto HLSLReservedKeyword; // HLSL Change - 'new' is reserved
return ParseCXXNewExpression(false, Tok.getLocation());
case tok::kw_delete: // [C++] delete-expression
if (getLangOpts().HLSL) goto HLSLReservedKeyword; // HLSL Change - 'delete' is reserved
return ParseCXXDeleteExpression(false, Tok.getLocation());
case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')'
if (getLangOpts().HLSL) goto HLSLReservedKeyword; // HLSL Change - reserved keyword
Diag(Tok, diag::warn_cxx98_compat_noexcept_expr);
SourceLocation KeyLoc = ConsumeToken();
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen_after, "noexcept"))
return ExprError();
// C++11 [expr.unary.noexcept]p1:
// The noexcept operator determines whether the evaluation of its operand,
// which is an unevaluated operand, can throw an exception.
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
ExprResult Result = ParseExpression();
T.consumeClose();
if (!Result.isInvalid())
Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(),
Result.get(), T.getCloseLocation());
return Result;
}
#define TYPE_TRAIT(N,Spelling,K) \
case tok::kw_##Spelling:
#include "clang/Basic/TokenKinds.def"
return ParseTypeTrait();
case tok::kw___array_rank:
case tok::kw___array_extent:
return ParseArrayTypeTrait();
case tok::kw___is_lvalue_expr:
case tok::kw___is_rvalue_expr:
return ParseExpressionTrait();
case tok::at: {
// HLSL Change Starts
assert(!getLangOpts().HLSL && "HLSL does not recognize '@' as a token");
if (getLangOpts().HLSL) goto tok_default_case;
// HLSL Change Ends
SourceLocation AtLoc = ConsumeToken();
return ParseObjCAtExpression(AtLoc);
}
case tok::caret:
// HLSL Change Starts
if (getLangOpts().HLSL) {
Diag(Tok, diag::err_hlsl_unsupported_construct) << "block";
return ExprError();
}
// HLSL Change Ends
Res = ParseBlockLiteralExpression();
break;
case tok::code_completion: {
Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression);
cutOffParsing();
return ExprError();
}
case tok::l_square:
if (getLangOpts().CPlusPlus11) {
if (getLangOpts().ObjC1) {
// 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.
Res = TryParseLambdaExpression();
if (!Res.isInvalid() && !Res.get())
Res = ParseObjCMessageExpression();
break;
}
Res = ParseLambdaExpression();
break;
}
if (getLangOpts().ObjC1) {
Res = ParseObjCMessageExpression();
break;
}
// FALL THROUGH.
tok_default_case: // HLSL Change - add to target cases dead-code'd by HLSL
default:
NotCastExpr = true;
return ExprError();
}
// These can be followed by postfix-expr pieces.
return ParsePostfixExpressionSuffix(Res);
}