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