Skip to content

Commit 9eb0f86

Browse files
authored
[clang] Implement CWG1878 "operator auto template" (#78103)
C++14 introduced deduced return type for regular functions, but shortly after [CWG1878](https://wg21.link/cwg1878) was filed and resolved to disallow deduced return types in conversion function templates. So this patch diagnoses such usage of deduced return type in C++14 mode onwards. Fixes #51776
1 parent a7d7da6 commit 9eb0f86

File tree

6 files changed

+102
-15
lines changed

6 files changed

+102
-15
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,8 @@ Improvements to Clang's diagnostics
575575
- Clang now diagnoses unexpanded packs within the template argument lists of function template specializations.
576576
- Clang now diagnoses attempts to bind a bitfield to an NTTP of a reference type as erroneous
577577
converted constant expression and not as a reference to subobject.
578+
- Clang now diagnoses ``auto`` and ``decltype(auto)`` in declarations of conversion function template
579+
(`CWG1878: <https://cplusplus.github.io/CWG/issues/1878.html>`_)
578580
- Clang now diagnoses the requirement that non-template friend declarations with requires clauses
579581
and template friend declarations with a constraint that depends on a template parameter from an
580582
enclosing template must be a definition.

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2411,7 +2411,8 @@ def err_auto_not_allowed : Error<
24112411
"|in type allocated by 'new'|in K&R-style function parameter"
24122412
"|in template parameter|in friend declaration|in function prototype that is "
24132413
"not a function declaration|in requires expression parameter"
2414-
"|in array declaration}1">;
2414+
"|in array declaration"
2415+
"|in declaration of conversion function template}1">;
24152416
def err_dependent_deduced_tst : Error<
24162417
"typename specifier refers to "
24172418
"%select{class template|function template|variable template|alias template|"

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11321,9 +11321,20 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) {
1132111321
<< ClassType << ConvType;
1132211322
}
1132311323

11324-
if (FunctionTemplateDecl *ConversionTemplate
11325-
= Conversion->getDescribedFunctionTemplate())
11324+
if (FunctionTemplateDecl *ConversionTemplate =
11325+
Conversion->getDescribedFunctionTemplate()) {
11326+
if (const auto *ConvTypePtr = ConvType->getAs<PointerType>()) {
11327+
ConvType = ConvTypePtr->getPointeeType();
11328+
}
11329+
if (ConvType->isUndeducedAutoType()) {
11330+
Diag(Conversion->getTypeSpecStartLoc(), diag::err_auto_not_allowed)
11331+
<< getReturnTypeLoc(Conversion).getSourceRange()
11332+
<< llvm::to_underlying(ConvType->getAs<AutoType>()->getKeyword())
11333+
<< /* in declaration of conversion function template= */ 24;
11334+
}
11335+
1132611336
return ConversionTemplate;
11337+
}
1132711338

1132811339
return Conversion;
1132911340
}

clang/test/CXX/drs/dr18xx.cpp

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -verify=expected,cxx98-14,cxx98 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
22
// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -verify=expected,cxx98-14,cxx11-17,since-cxx11 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
3-
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,cxx98-14,cxx11-17,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
4-
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx17,cxx11-17,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
5-
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx17,since-cxx20,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
6-
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx17,since-cxx20,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
7-
// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx17,since-cxx20,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
3+
// RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,cxx98-14,cxx11-17,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
4+
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,since-cxx17,cxx11-17,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
5+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,since-cxx17,since-cxx20,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
6+
// RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,since-cxx17,since-cxx20,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
7+
// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -verify=expected,since-cxx14,since-cxx17,since-cxx20,since-cxx11,since-cxx14 -fexceptions -Wno-deprecated-builtins -fcxx-exceptions -pedantic-errors
88

99
#if __cplusplus == 199711L
1010
#define static_assert(...) __extension__ _Static_assert(__VA_ARGS__)
@@ -319,6 +319,41 @@ namespace dr1872 { // dr1872: 9
319319
#endif
320320
}
321321

322+
namespace dr1878 { // dr1878: 18
323+
#if __cplusplus >= 201402L
324+
#if __cplusplus >= 202002L
325+
template <typename T>
326+
concept C = true;
327+
#endif
328+
329+
struct S {
330+
template <typename T>
331+
operator auto() const { return short(); }
332+
// since-cxx14-error@-1 {{'auto' not allowed in declaration of conversion function template}}
333+
template <typename T>
334+
operator const auto() const { return int(); }
335+
// since-cxx14-error@-1 {{'auto' not allowed in declaration of conversion function template}}
336+
template <typename T>
337+
operator const auto&() const { return char(); }
338+
// since-cxx14-error@-1 {{'auto' not allowed in declaration of conversion function template}}
339+
template <typename T>
340+
operator const auto*() const { return long(); }
341+
// since-cxx14-error@-1 {{'auto' not allowed in declaration of conversion function template}}
342+
template <typename T>
343+
operator decltype(auto)() const { return unsigned(); }
344+
// since-cxx14-error@-1 {{'decltype(auto)' not allowed in declaration of conversion function template}}
345+
#if __cplusplus >= 202002L
346+
template <typename T>
347+
operator C auto() const { return float(); }
348+
// since-cxx20-error@-1 {{'auto' not allowed in declaration of conversion function template}}
349+
template <typename T>
350+
operator C decltype(auto)() const { return double(); }
351+
// since-cxx20-error@-1 {{'decltype(auto)' not allowed in declaration of conversion function template}}
352+
#endif
353+
};
354+
#endif
355+
}
356+
322357
namespace dr1881 { // dr1881: 7
323358
struct A { int a : 4; };
324359
struct B : A { int b : 3; };

clang/test/SemaCXX/deduced-return-type-cxx14.cpp

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify=expected,cxx20_23,cxx23 %s
2-
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify=expected,cxx20_23,cxx23 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING
1+
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify=expected,since-cxx20,since-cxx14,cxx20_23,cxx23 %s
2+
// RUN: %clang_cc1 -std=c++23 -fsyntax-only -verify=expected,since-cxx20,since-cxx14,cxx20_23,cxx23 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING
33

4-
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx14_20,cxx20_23 %s
5-
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,cxx14_20,cxx20_23 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING
4+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,since-cxx20,since-cxx14,cxx14_20,cxx20_23 %s
5+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify=expected,since-cxx20,since-cxx14,cxx14_20,cxx20_23 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING
66

7-
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14_20,cxx14 %s
8-
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,cxx14_20,cxx14 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING
7+
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,since-cxx14,cxx14_20,cxx14 %s
8+
// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify=expected,since-cxx14,cxx14_20,cxx14 %s -fdelayed-template-parsing -DDELAYED_TEMPLATE_PARSING
99

1010
auto f(); // expected-note {{previous}}
1111
int f(); // expected-error {{differ only in their return type}}
@@ -686,3 +686,41 @@ auto f(auto x) { // cxx14-error {{'auto' not allowed in function prototype}}
686686
}
687687

688688
}
689+
690+
#if __cplusplus >= 202002L
691+
template <typename T>
692+
concept C = true;
693+
#endif
694+
695+
struct DeducedTargetTypeOfConversionFunction {
696+
operator auto() const { return char(); }
697+
operator const auto() const { return float(); }
698+
operator const auto&() const { return int(); }
699+
// expected-warning@-1 {{returning reference to local temporary object}}
700+
operator decltype(auto)() const { return double(); }
701+
#if __cplusplus >= 202002L
702+
operator C auto() const { return unsigned(); }
703+
operator C decltype(auto)() const { return long(); }
704+
#endif
705+
706+
template <typename T>
707+
operator auto() const { return short(); }
708+
// since-cxx14-error@-1 {{'auto' not allowed in declaration of conversion function template}}
709+
template <typename T>
710+
operator const auto() const { return int(); }
711+
// since-cxx14-error@-1 {{'auto' not allowed in declaration of conversion function template}}
712+
template <typename T>
713+
operator const auto&() const { return char(); }
714+
// since-cxx14-error@-1 {{'auto' not allowed in declaration of conversion function template}}
715+
template <typename T>
716+
operator decltype(auto)() const { return unsigned(); }
717+
// since-cxx14-error@-1 {{'decltype(auto)' not allowed in declaration of conversion function template}}
718+
#if __cplusplus >= 202002L
719+
template <typename T>
720+
operator C auto() const { return float(); }
721+
// since-cxx20-error@-1 {{'auto' not allowed in declaration of conversion function template}}
722+
template <typename T>
723+
operator C decltype(auto)() const { return double(); }
724+
// since-cxx20-error@-1 {{'decltype(auto)' not allowed in declaration of conversion function template}}
725+
#endif
726+
};

clang/www/cxx_dr_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11076,7 +11076,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
1107611076
<td><a href="https://cplusplus.github.io/CWG/issues/1878.html">1878</a></td>
1107711077
<td>CD4</td>
1107811078
<td><TT>operator auto</TT> template</td>
11079-
<td class="unknown" align="center">Unknown</td>
11079+
<td class="unreleased" align="center">Clang 18</td>
1108011080
</tr>
1108111081
<tr id="1879">
1108211082
<td><a href="https://cplusplus.github.io/CWG/issues/1879.html">1879</a></td>

0 commit comments

Comments
 (0)