diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index a0e4ef958e6a..ae1a041596ab 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -92,8 +92,8 @@ def err_duplicate_default_assoc : Error< def note_previous_default_assoc : Note< "previous default generic association is here">; -def ext_c11_alignas : Extension< - "_Alignas is a C11-specific feature">, InGroup; +def ext_c11_alignment : Extension< + "%0 is a C11-specific feature">, InGroup; def ext_gnu_indirect_goto : Extension< "use of GNU indirect-goto extension">, InGroup; diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index c380f8c907d8..751d8674aecd 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -251,6 +251,7 @@ KEYWORD(void , KEYALL) KEYWORD(volatile , KEYALL) KEYWORD(while , KEYALL) KEYWORD(_Alignas , KEYALL) +KEYWORD(_Alignof , KEYALL) KEYWORD(_Atomic , KEYALL) KEYWORD(_Bool , KEYNOCXX) KEYWORD(_Complex , KEYALL) diff --git a/clang/lib/AST/StmtDumper.cpp b/clang/lib/AST/StmtDumper.cpp index ce330e06b703..d5e12c873d0e 100644 --- a/clang/lib/AST/StmtDumper.cpp +++ b/clang/lib/AST/StmtDumper.cpp @@ -463,7 +463,7 @@ void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) { OS << " sizeof "; break; case UETT_AlignOf: - OS << " __alignof "; + OS << " alignof "; break; case UETT_VecStep: OS << " vec_step "; diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 9c7259745ca8..5bd61c3b5292 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -814,7 +814,12 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){ OS << "sizeof"; break; case UETT_AlignOf: - OS << "__alignof"; + if (Policy.LangOpts.CPlusPlus) + OS << "alignof"; + else if (Policy.LangOpts.C11) + OS << "_Alignof"; + else + OS << "__alignof"; break; case UETT_VecStep: OS << "vec_step"; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 409f8e002abc..c6db497a53d4 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2478,7 +2478,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // alignment-specifier case tok::kw__Alignas: if (!getLangOpts().C11) - Diag(Tok, diag::ext_c11_alignas); + Diag(Tok, diag::ext_c11_alignment) << Tok.getName(); ParseAlignmentSpecifier(DS.getAttributes()); continue; diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 840402530b0d..7f268b523df2 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -507,6 +507,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// [C++11] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' +/// [C11] '_Alignof' '(' type-name ')' /// [C++11] 'alignof' '(' type-id ')' /// [GNU] '&&' identifier /// [C++11] 'noexcept' '(' expression ')' [C++11 5.3.7] @@ -921,12 +922,15 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return move(Res); } - case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression - // unary-expression: 'sizeof' '(' type-name ')' - case tok::kw_alignof: + 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 ')' - // unary-expression: 'alignof' '(' type-id ')' + 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 return ParseUnaryExprOrTypeTraitExpression(); case tok::ampamp: { // unary-expression: '&&' identifier @@ -1514,6 +1518,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /// 'sizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' +/// [C11] '_Alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' /// /// [GNU] typeof-specifier: @@ -1533,7 +1538,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) || OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof) || - OpTok.is(tok::kw_vec_step)) && + OpTok.is(tok::kw__Alignof) || OpTok.is(tok::kw_vec_step)) && "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; @@ -1591,11 +1596,13 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, /// [C++0x] 'sizeof' '...' '(' identifier ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' +/// [C11] '_Alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' /// \endverbatim ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { - assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) - || Tok.is(tok::kw_alignof) || Tok.is(tok::kw_vec_step)) && + assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) || + Tok.is(tok::kw_alignof) || Tok.is(tok::kw__Alignof) || + Tok.is(tok::kw_vec_step)) && "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); @@ -1643,7 +1650,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { RParenLoc); } - if (OpTok.is(tok::kw_alignof)) + if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof)) Diag(OpTok, diag::warn_cxx98_compat_alignof); EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); @@ -1657,7 +1664,8 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { CastRange); UnaryExprOrTypeTrait ExprKind = UETT_SizeOf; - if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw___alignof)) + if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw___alignof) || + OpTok.is(tok::kw__Alignof)) ExprKind = UETT_AlignOf; else if (OpTok.is(tok::kw_vec_step)) ExprKind = UETT_VecStep; diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 8a5e7266d36e..41d793f3f29a 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -735,6 +735,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_alignof: case tok::kw_noexcept: case tok::kw_nullptr: + case tok::kw__Alignof: case tok::kw___null: case tok::kw___alignof: case tok::kw___builtin_choose_expr: diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 5cab990d33fc..ff83324de225 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -1955,6 +1955,19 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, AddObjCExpressionResults(Results, true); } + if (SemaRef.getLangOpts().C11) { + // _Alignof + Builder.AddResultTypeChunk("size_t"); + if (SemaRef.getASTContext().Idents.get("alignof").hasMacroDefinition()) + Builder.AddTypedTextChunk("alignof"); + else + Builder.AddTypedTextChunk("_Alignof"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); + } + // sizeof expression Builder.AddResultTypeChunk("size_t"); Builder.AddTypedTextChunk("sizeof"); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 827cfbcfffcc..94efb2fff380 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3604,6 +3604,12 @@ static void AddKeywordsToConsumer(Sema &SemaRef, Consumer.addKeywordResult("nullptr"); } } + + if (SemaRef.getLangOpts().C11) { + // FIXME: We should not suggest _Alignof if the alignof macro + // is present. + Consumer.addKeywordResult("_Alignof"); + } } if (CCC.WantRemainingKeywords) { diff --git a/clang/test/Parser/c1x-alignas.c b/clang/test/Parser/c1x-alignas.c index 5dccc99035ad..81cd6816307f 100644 --- a/clang/test/Parser/c1x-alignas.c +++ b/clang/test/Parser/c1x-alignas.c @@ -1,7 +1,13 @@ -// RUN: %clang_cc1 -std=c1x -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c11 -fsyntax-only -verify %s +// RUN: not %clang_cc1 -pedantic -fsyntax-only %s 2>&1 | FileCheck -check-prefix=CHECK-EXT %s _Alignas(4) char c1; unsigned _Alignas(long) char c2; char _Alignas(16) c3; char c4 _Alignas(32); // expected-error {{expected ';' after top level declarator}} + +char _Alignas(_Alignof(int)) c5; + +// CHECK-EXT: _Alignas is a C11-specific feature +// CHECK-EXT: _Alignof is a C11-specific feature diff --git a/clang/test/Sema/alignas.c b/clang/test/Sema/alignas.c index 5832393e3b61..d9a0164010f9 100644 --- a/clang/test/Sema/alignas.c +++ b/clang/test/Sema/alignas.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c1x %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -Dalignof=__alignof %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -Dalignof=_Alignof %s _Alignas(3) int align_illegal; //expected-error {{requested alignment is not a power of 2}} _Alignas(int) char align_big; @@ -11,9 +12,9 @@ struct align_member { typedef _Alignas(8) char align_typedef; // FIXME: this should be rejected -_Static_assert(__alignof(align_big) == __alignof(int), "k's alignment is wrong"); -_Static_assert(__alignof(align_small) == 1, "j's alignment is wrong"); -_Static_assert(__alignof(align_multiple) == 8, "l's alignment is wrong"); -_Static_assert(__alignof(struct align_member) == 8, "quuux's alignment is wrong"); +_Static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong"); +_Static_assert(alignof(align_small) == 1, "j's alignment is wrong"); +_Static_assert(alignof(align_multiple) == 8, "l's alignment is wrong"); +_Static_assert(alignof(struct align_member) == 8, "quuux's alignment is wrong"); _Static_assert(sizeof(struct align_member) == 8, "quuux's size is wrong"); -_Static_assert(__alignof(align_typedef) == 8, "typedef's alignment is wrong"); +_Static_assert(alignof(align_typedef) == 8, "typedef's alignment is wrong");