[clang] 45d7080 - PR42694 Support explicit(bool) in older language modes as an extension.
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Jan 16 18:14:16 PST 2020
Also b78e8e0d79c47a6698a0abc10a37b8a253cb6064 which has an extra test file
that I forgot to git add.
On Wed, 15 Jan 2020 at 18:52, Richard Smith <richard at metafoo.co.uk> wrote:
> Hans, could this change be ported to the Clang 10 branch? In PR42694 the
> MSVC stdlib developers requested that Clang support this because their
> standard library will soon rely on it.
>
> On Wed, 15 Jan 2020 at 18:50, Richard Smith via cfe-commits <
> cfe-commits at lists.llvm.org> wrote:
>
>>
>> Author: Richard Smith
>> Date: 2020-01-15T18:38:23-08:00
>> New Revision: 45d70806f4386adfb62b0d75949a8aad58e0576f
>>
>> URL:
>> https://github.com/llvm/llvm-project/commit/45d70806f4386adfb62b0d75949a8aad58e0576f
>> DIFF:
>> https://github.com/llvm/llvm-project/commit/45d70806f4386adfb62b0d75949a8aad58e0576f.diff
>>
>> LOG: PR42694 Support explicit(bool) in older language modes as an
>> extension.
>>
>> This needs somewhat careful disambiguation, as C++2a explicit(bool) is a
>> breaking change. We only enable it in cases where the source construct
>> could not possibly be anything else.
>>
>> Added:
>>
>>
>> Modified:
>> clang/include/clang/Basic/DiagnosticParseKinds.td
>> clang/include/clang/Parse/Parser.h
>> clang/lib/Parse/ParseDecl.cpp
>> clang/lib/Parse/ParseTentative.cpp
>> clang/lib/Parse/Parser.cpp
>> clang/test/SemaCXX/cxx2a-explicit-bool.cpp
>>
>> Removed:
>>
>>
>>
>>
>> ################################################################################
>> diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td
>> b/clang/include/clang/Basic/DiagnosticParseKinds.td
>> index cc6a74ac3e6d..41f788e7d9bd 100644
>> --- a/clang/include/clang/Basic/DiagnosticParseKinds.td
>> +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
>> @@ -33,10 +33,6 @@ def err_asm_goto_cannot_have_output : Error<
>>
>> let CategoryName = "Parse Issue" in {
>>
>> -def warn_cxx2a_compat_explicit_bool : Warning<
>> - "this expression will be parsed as explicit(bool) in C++2a">,
>> - InGroup<CXX2aCompat>, DefaultIgnore;
>> -
>> def ext_empty_translation_unit : Extension<
>> "ISO C requires a translation unit to contain at least one
>> declaration">,
>> InGroup<DiagGroup<"empty-translation-unit">>;
>> @@ -684,6 +680,15 @@ def err_ms_property_expected_comma_or_rparen : Error<
>> def err_ms_property_initializer : Error<
>> "property declaration cannot have an in-class initializer">;
>>
>> +def warn_cxx2a_compat_explicit_bool : Warning<
>> + "this expression will be parsed as explicit(bool) in C++2a">,
>> + InGroup<CXX2aCompat>, DefaultIgnore;
>> +def warn_cxx17_compat_explicit_bool : Warning<
>> + "explicit(bool) is incompatible with C++ standards before C++2a">,
>> + InGroup<CXXPre2aCompat>, DefaultIgnore;
>> +def ext_explicit_bool : ExtWarn<"explicit(bool) is a C++2a extension">,
>> + InGroup<CXX2a>;
>> +
>> /// C++ Templates
>> def err_expected_template : Error<"expected template">;
>> def err_unknown_template_name : Error<
>>
>> diff --git a/clang/include/clang/Parse/Parser.h
>> b/clang/include/clang/Parse/Parser.h
>> index e320c9647818..b7bed4713992 100644
>> --- a/clang/include/clang/Parse/Parser.h
>> +++ b/clang/include/clang/Parse/Parser.h
>> @@ -806,6 +806,16 @@ class Parser : public CodeCompletionHandler {
>> bool IsNewScope);
>> bool TryAnnotateCXXScopeToken(bool EnteringContext = false);
>>
>> + bool MightBeCXXScopeToken() {
>> + return Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
>> + (Tok.is(tok::annot_template_id) &&
>> + NextToken().is(tok::coloncolon)) ||
>> + Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super);
>> + }
>> + bool TryAnnotateOptionalCXXScopeToken(bool EnteringContext = false) {
>> + return MightBeCXXScopeToken() &&
>> TryAnnotateCXXScopeToken(EnteringContext);
>> + }
>> +
>> private:
>> enum AnnotatedNameKind {
>> /// Annotation has failed and emitted an error.
>> @@ -2395,6 +2405,11 @@ class Parser : public CodeCompletionHandler {
>> /// rather than a less-than expression.
>> TPResult isTemplateArgumentList(unsigned TokensToSkip);
>>
>> + /// Determine whether an '(' after an 'explicit' keyword is part of a
>> C++20
>> + /// 'explicit(bool)' declaration, in earlier language modes where that
>> is an
>> + /// extension.
>> + TPResult isExplicitBool();
>> +
>> /// Determine whether an identifier has been tentatively declared as a
>> /// non-type. Such tentative declarations should not be found to name
>> a type
>> /// during a tentative parse, but also should not be annotated as a
>> non-type.
>>
>> diff --git a/clang/lib/Parse/ParseDecl.cpp
>> b/clang/lib/Parse/ParseDecl.cpp
>> index 69a3ed9cbad7..d8c5a0ab02d3 100644
>> --- a/clang/lib/Parse/ParseDecl.cpp
>> +++ b/clang/lib/Parse/ParseDecl.cpp
>> @@ -3617,7 +3617,11 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec
>> &DS,
>> ConsumedEnd = ExplicitLoc;
>> ConsumeToken(); // kw_explicit
>> if (Tok.is(tok::l_paren)) {
>> - if (getLangOpts().CPlusPlus2a) {
>> + if (getLangOpts().CPlusPlus2a || isExplicitBool() ==
>> TPResult::True) {
>> + Diag(Tok.getLocation(), getLangOpts().CPlusPlus2a
>> + ?
>> diag::warn_cxx17_compat_explicit_bool
>> + : diag::ext_explicit_bool);
>> +
>> ExprResult ExplicitExpr(static_cast<Expr *>(nullptr));
>> BalancedDelimiterTracker Tracker(*this, tok::l_paren);
>> Tracker.consumeOpen();
>> @@ -3630,8 +3634,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec
>> &DS,
>> Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get());
>> } else
>> Tracker.skipToEnd();
>> - } else
>> + } else {
>> Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool);
>> + }
>> }
>> isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec,
>> DiagID,
>> ExplicitSpec,
>> CloseParenLoc);
>>
>> diff --git a/clang/lib/Parse/ParseTentative.cpp
>> b/clang/lib/Parse/ParseTentative.cpp
>> index 4d69fb4693fb..d5068fb11b86 100644
>> --- a/clang/lib/Parse/ParseTentative.cpp
>> +++ b/clang/lib/Parse/ParseTentative.cpp
>> @@ -202,9 +202,7 @@ Parser::TPResult
>> Parser::TryConsumeDeclarationSpecifier() {
>> }
>> }
>>
>> - if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_decltype,
>> - tok::annot_template_id) &&
>> - TryAnnotateCXXScopeToken())
>> + if (TryAnnotateOptionalCXXScopeToken())
>> return TPResult::Error;
>> if (Tok.is(tok::annot_cxxscope))
>> ConsumeAnnotationToken();
>> @@ -785,9 +783,8 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
>>
>> Parser::TPResult Parser::TryParsePtrOperatorSeq() {
>> while (true) {
>> - if (Tok.isOneOf(tok::coloncolon, tok::identifier))
>> - if (TryAnnotateCXXScopeToken(true))
>> - return TPResult::Error;
>> + if (TryAnnotateOptionalCXXScopeToken(true))
>> + return TPResult::Error;
>>
>> if (Tok.isOneOf(tok::star, tok::amp, tok::caret, tok::ampamp) ||
>> (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
>> @@ -2137,3 +2134,58 @@ Parser::TPResult
>> Parser::isTemplateArgumentList(unsigned TokensToSkip) {
>> return TPResult::Ambiguous;
>> return TPResult::False;
>> }
>> +
>> +/// Determine whether we might be looking at the '(' of a C++20
>> explicit(bool)
>> +/// in an earlier language mode.
>> +Parser::TPResult Parser::isExplicitBool() {
>> + assert(Tok.is(tok::l_paren) && "expected to be looking at a '('
>> token");
>> +
>> + RevertingTentativeParsingAction PA(*this);
>> + ConsumeParen();
>> +
>> + // We can only have 'explicit' on a constructor, conversion function,
>> or
>> + // deduction guide. The declarator of a deduction guide cannot be
>> + // parenthesized, so we know this isn't a deduction guide. So the only
>> + // thing we need to check for is some number of parens followed by
>> either
>> + // the current class name or 'operator'.
>> + while (Tok.is(tok::l_paren))
>> + ConsumeParen();
>> +
>> + if (TryAnnotateOptionalCXXScopeToken())
>> + return TPResult::Error;
>> +
>> + // Class-scope constructor and conversion function names can't really
>> be
>> + // qualified, but we get better diagnostics if we assume they can be.
>> + CXXScopeSpec SS;
>> + if (Tok.is(tok::annot_cxxscope)) {
>> +
>> Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
>> +
>> Tok.getAnnotationRange(),
>> + SS);
>> + ConsumeAnnotationToken();
>> + }
>> +
>> + // 'explicit(operator' might be explicit(bool) or the declaration of a
>> + // conversion function, but it's probably a conversion function.
>> + if (Tok.is(tok::kw_operator))
>> + return TPResult::Ambiguous;
>> +
>> + // If this can't be a constructor name, it can only be explicit(bool).
>> + if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
>> + return TPResult::True;
>> + if (!Actions.isCurrentClassName(Tok.is(tok::identifier)
>> + ? *Tok.getIdentifierInfo()
>> + :
>> *takeTemplateIdAnnotation(Tok)->Name,
>> + getCurScope(), &SS))
>> + return TPResult::True;
>> + // Formally, we must have a right-paren after the constructor name to
>> match
>> + // the grammar for a constructor. But clang permits a parenthesized
>> + // constructor declarator, so also allow a constructor declarator to
>> follow
>> + // with no ')' token after the constructor name.
>> + if (!NextToken().is(tok::r_paren) &&
>> + !isConstructorDeclarator(/*Unqualified=*/SS.isEmpty(),
>> + /*DeductionGuide=*/false))
>> + return TPResult::True;
>> +
>> + // Might be explicit(bool) or a parenthesized constructor name.
>> + return TPResult::Ambiguous;
>> +}
>>
>> diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
>> index 4249de361b89..0fb0a5217d54 100644
>> --- a/clang/lib/Parse/Parser.cpp
>> +++ b/clang/lib/Parse/Parser.cpp
>> @@ -2005,10 +2005,7 @@ bool
>> Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(CXXScopeSpec &SS,
>> bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) {
>> assert(getLangOpts().CPlusPlus &&
>> "Call sites of this function should be guarded by checking for
>> C++");
>> - assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
>> - (Tok.is(tok::annot_template_id) &&
>> NextToken().is(tok::coloncolon)) ||
>> - Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super)) &&
>> - "Cannot be a type or scope token!");
>> + assert(MightBeCXXScopeToken() && "Cannot be a type or scope token!");
>>
>> CXXScopeSpec SS;
>> if (ParseOptionalCXXScopeSpecifier(SS, nullptr, EnteringContext))
>>
>> diff --git a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
>> b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
>> index df776b390548..45385972cab8 100644
>> --- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
>> +++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp
>> @@ -1,3 +1,4 @@
>> +// RUN: %clang_cc1 -std=c++17 -fsyntax-only %s -verify
>> -Wno-c++2a-extensions
>> // RUN: %clang_cc1 -std=c++2a -fsyntax-only %s -verify
>>
>> template <bool b, auto val> struct enable_ifv {};
>>
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200116/23bcdd1b/attachment-0001.html>
More information about the cfe-commits
mailing list