aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Parse/ParseDecl.cpp
diff options
context:
space:
mode:
authorAaron Ballman <aaron@aaronballman.com>2022-09-28 13:25:58 -0400
committerAaron Ballman <aaron@aaronballman.com>2022-09-28 13:27:52 -0400
commit60727d856927383daf304fcf8f19fcc8ade828ad (patch)
treee3d1edab73e44dbc346dd82a43d381c485f72f30 /clang/lib/Parse/ParseDecl.cpp
parent153eeb4a5e68c6054a220667646b14f3785a942e (diff)
downloadllvm-60727d856927383daf304fcf8f19fcc8ade828ad.zip
llvm-60727d856927383daf304fcf8f19fcc8ade828ad.tar.gz
llvm-60727d856927383daf304fcf8f19fcc8ade828ad.tar.bz2
[C2x] implement typeof and typeof_unqual
This implements WG14 N2927 and WG14 N2930, which together define the feature for typeof and typeof_unqual, which get the type of their argument as either fully qualified or fully unqualified. The argument to either operator is either a type name or an expression. If given a type name, the type information is pulled directly from the given name. If given an expression, the type information is pulled from the expression. Recursive use of these operators is allowed and has the expected behavior (the innermost operator is resolved to a type, and that's used to resolve the next layer of typeof specifier, until a fully resolved type is determined. Note, we already supported typeof in GNU mode as a non-conforming extension and we are *not* exposing typeof_unqual as a non-conforming extension in that mode, nor are we exposing typeof or typeof_unqual as a nonconforming extension in other language modes. The GNU variant of typeof supports a form where the parentheses are elided from the operator when given an expression (e.g., typeof 0 i = 12;). When in C2x mode, we do not support this extension. Differential Revision: https://reviews.llvm.org/D134286
Diffstat (limited to 'clang/lib/Parse/ParseDecl.cpp')
-rw-r--r--clang/lib/Parse/ParseDecl.cpp39
1 files changed, 30 insertions, 9 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 9363827..dfedbf5 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4241,8 +4241,9 @@ void Parser::ParseDeclarationSpecifiers(
continue;
break;
- // GNU typeof support.
+ // C2x/GNU typeof support.
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
ParseTypeofSpecifier(DS);
continue;
@@ -5252,8 +5253,9 @@ bool Parser::isTypeSpecifierQualifier() {
// GNU attributes support.
case tok::kw___attribute:
- // GNU typeof support.
+ // C2x/GNU typeof support.
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
// type-specifiers
case tok::kw_short:
@@ -5495,8 +5497,9 @@ bool Parser::isDeclarationSpecifier(
case tok::kw_static_assert:
case tok::kw__Static_assert:
- // GNU typeof support.
+ // C2x/GNU typeof support.
case tok::kw_typeof:
+ case tok::kw_typeof_unqual:
// GNU attributes.
case tok::kw___attribute:
@@ -7543,13 +7546,27 @@ void Parser::ParseMisplacedBracketDeclarator(Declarator &D) {
/// typeof ( expressions )
/// typeof ( type-name )
/// [GNU/C++] typeof unary-expression
+/// [C2x] typeof-specifier:
+/// typeof '(' typeof-specifier-argument ')'
+/// typeof_unqual '(' typeof-specifier-argument ')'
+///
+/// typeof-specifier-argument:
+/// expression
+/// type-name
///
void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
- assert(Tok.is(tok::kw_typeof) && "Not a typeof specifier");
+ assert(Tok.isOneOf(tok::kw_typeof, tok::kw_typeof_unqual) &&
+ "Not a typeof specifier");
+
+ bool IsUnqual = Tok.is(tok::kw_typeof_unqual);
+ const IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (getLangOpts().C2x && !II->getName().startswith("__"))
+ Diag(Tok.getLocation(), diag::warn_c2x_compat_typeof_type_specifier)
+ << IsUnqual;
+
Token OpTok = Tok;
SourceLocation StartLoc = ConsumeToken();
-
- const bool hasParens = Tok.is(tok::l_paren);
+ bool HasParens = Tok.is(tok::l_paren);
EnterExpressionEvaluationContext Unevaluated(
Actions, Sema::ExpressionEvaluationContext::Unevaluated,
@@ -7560,7 +7577,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
SourceRange CastRange;
ExprResult Operand = Actions.CorrectDelayedTyposInExpr(
ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, CastTy, CastRange));
- if (hasParens)
+ if (HasParens)
DS.setTypeArgumentRange(CastRange);
if (CastRange.getEnd().isInvalid())
@@ -7578,7 +7595,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const char *PrevSpec = nullptr;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int typeof(int)").
- if (DS.SetTypeSpecType(DeclSpec::TST_typeofType, StartLoc, PrevSpec,
+ if (DS.SetTypeSpecType(IsUnqual ? DeclSpec::TST_typeof_unqualType
+ : DeclSpec::TST_typeofType,
+ StartLoc, PrevSpec,
DiagID, CastTy,
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;
@@ -7601,7 +7620,9 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const char *PrevSpec = nullptr;
unsigned DiagID;
// Check for duplicate type specifiers (e.g. "int typeof(int)").
- if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
+ if (DS.SetTypeSpecType(IsUnqual ? DeclSpec::TST_typeof_unqualExpr
+ : DeclSpec::TST_typeofExpr,
+ StartLoc, PrevSpec,
DiagID, Operand.get(),
Actions.getASTContext().getPrintingPolicy()))
Diag(StartLoc, DiagID) << PrevSpec;