Also b78e8e0d79c47a6698a0abc10a37b8a253cb6064 which has an extra test file that I forgot to git add.
On Wed, 15 Jan 2020 at 18:52, Richard Smith <rich...@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@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@lists.llvm.org >> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >> >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits