Implement DR1265 (wg21.link/cwg1265).

Diasllow a declaration using the 'auto' type specifier from using two different
meanings of it at once, or from declaring multiple functions with deduced
return types or introducing multiple trailing return types.

The standard does not technically disallow the multiple trailing return types
case if all the declarators declare variables (such as function pointers with
trailing return types), but we disallow that too, following the clear intent.

llvm-svn: 291880
This commit is contained in:
Richard Smith 2017-01-13 02:22:01 +00:00
parent 8515875e24
commit 8210ed5586
8 changed files with 163 additions and 76 deletions

View File

@ -1867,6 +1867,11 @@ public:
/// types, but not through decltype or typedefs.
AutoType *getContainedAutoType() const;
/// Determine whether this type was written with a leading 'auto'
/// corresponding to a trailing return type (possibly for a nested
/// function type within a pointer to function type or similar).
bool hasAutoForTrailingReturnType() const;
/// Member-template getAs<specific type>'. Look through sugar for
/// an instance of \<specific type>. This scheme will eventually
/// replace the specific getAsXXXX methods above.

View File

@ -1900,6 +1900,10 @@ def err_auto_new_deduction_failure : Error<
def err_auto_different_deductions : Error<
"'%select{auto|decltype(auto)|__auto_type}0' deduced as %1 in declaration "
"of %2 and deduced as %3 in declaration of %4">;
def err_auto_non_deduced_not_alone : Error<
"%select{function with deduced return type|"
"declaration with trailing return type}0 "
"must be the only declaration in its group">;
def err_implied_std_initializer_list_not_found : Error<
"cannot deduce type of initializer list because std::initializer_list was "
"not found; include <initializer_list>">;

View File

@ -1560,60 +1560,73 @@ TagDecl *Type::getAsTagDecl() const {
namespace {
class GetContainedAutoVisitor :
public TypeVisitor<GetContainedAutoVisitor, AutoType*> {
public TypeVisitor<GetContainedAutoVisitor, Type*> {
bool Syntactic;
public:
using TypeVisitor<GetContainedAutoVisitor, AutoType*>::Visit;
AutoType *Visit(QualType T) {
GetContainedAutoVisitor(bool Syntactic = false) : Syntactic(Syntactic) {}
using TypeVisitor<GetContainedAutoVisitor, Type*>::Visit;
Type *Visit(QualType T) {
if (T.isNull())
return nullptr;
return Visit(T.getTypePtr());
}
// The 'auto' type itself.
AutoType *VisitAutoType(const AutoType *AT) {
Type *VisitAutoType(const AutoType *AT) {
return const_cast<AutoType*>(AT);
}
// Only these types can contain the desired 'auto' type.
AutoType *VisitPointerType(const PointerType *T) {
Type *VisitPointerType(const PointerType *T) {
return Visit(T->getPointeeType());
}
AutoType *VisitBlockPointerType(const BlockPointerType *T) {
Type *VisitBlockPointerType(const BlockPointerType *T) {
return Visit(T->getPointeeType());
}
AutoType *VisitReferenceType(const ReferenceType *T) {
Type *VisitReferenceType(const ReferenceType *T) {
return Visit(T->getPointeeTypeAsWritten());
}
AutoType *VisitMemberPointerType(const MemberPointerType *T) {
Type *VisitMemberPointerType(const MemberPointerType *T) {
return Visit(T->getPointeeType());
}
AutoType *VisitArrayType(const ArrayType *T) {
Type *VisitArrayType(const ArrayType *T) {
return Visit(T->getElementType());
}
AutoType *VisitDependentSizedExtVectorType(
Type *VisitDependentSizedExtVectorType(
const DependentSizedExtVectorType *T) {
return Visit(T->getElementType());
}
AutoType *VisitVectorType(const VectorType *T) {
Type *VisitVectorType(const VectorType *T) {
return Visit(T->getElementType());
}
AutoType *VisitFunctionType(const FunctionType *T) {
Type *VisitFunctionProtoType(const FunctionProtoType *T) {
if (Syntactic && T->hasTrailingReturn())
return const_cast<FunctionProtoType*>(T);
return VisitFunctionType(T);
}
Type *VisitFunctionType(const FunctionType *T) {
return Visit(T->getReturnType());
}
AutoType *VisitParenType(const ParenType *T) {
Type *VisitParenType(const ParenType *T) {
return Visit(T->getInnerType());
}
AutoType *VisitAttributedType(const AttributedType *T) {
Type *VisitAttributedType(const AttributedType *T) {
return Visit(T->getModifiedType());
}
AutoType *VisitAdjustedType(const AdjustedType *T) {
Type *VisitAdjustedType(const AdjustedType *T) {
return Visit(T->getOriginalType());
}
};
}
AutoType *Type::getContainedAutoType() const {
return GetContainedAutoVisitor().Visit(this);
return cast_or_null<AutoType>(GetContainedAutoVisitor().Visit(this));
}
bool Type::hasAutoForTrailingReturnType() const {
return dyn_cast_or_null<FunctionType>(
GetContainedAutoVisitor(true).Visit(this));
}
bool Type::hasIntegerRepresentation() const {

View File

@ -11045,6 +11045,11 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
}
}
static bool hasDeducedAuto(DeclaratorDecl *DD) {
auto *VD = dyn_cast<VarDecl>(DD);
return VD && !VD->getType()->hasAutoForTrailingReturnType();
}
Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
ArrayRef<Decl *> Group) {
SmallVector<Decl*, 8> Decls;
@ -11055,29 +11060,46 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS,
DeclaratorDecl *FirstDeclaratorInGroup = nullptr;
DecompositionDecl *FirstDecompDeclaratorInGroup = nullptr;
bool DiagnosedMultipleDecomps = false;
DeclaratorDecl *FirstNonDeducedAutoInGroup = nullptr;
bool DiagnosedNonDeducedAuto = false;
for (unsigned i = 0, e = Group.size(); i != e; ++i) {
if (Decl *D = Group[i]) {
auto *DD = dyn_cast<DeclaratorDecl>(D);
if (DD && !FirstDeclaratorInGroup)
FirstDeclaratorInGroup = DD;
// For declarators, there are some additional syntactic-ish checks we need
// to perform.
if (auto *DD = dyn_cast<DeclaratorDecl>(D)) {
if (!FirstDeclaratorInGroup)
FirstDeclaratorInGroup = DD;
if (!FirstDecompDeclaratorInGroup)
FirstDecompDeclaratorInGroup = dyn_cast<DecompositionDecl>(D);
if (!FirstNonDeducedAutoInGroup && DS.containsPlaceholderType() &&
!hasDeducedAuto(DD))
FirstNonDeducedAutoInGroup = DD;
auto *Decomp = dyn_cast<DecompositionDecl>(D);
if (Decomp && !FirstDecompDeclaratorInGroup)
FirstDecompDeclaratorInGroup = Decomp;
if (FirstDeclaratorInGroup != DD) {
// A decomposition declaration cannot be combined with any other
// declaration in the same group.
if (FirstDecompDeclaratorInGroup && !DiagnosedMultipleDecomps) {
Diag(FirstDecompDeclaratorInGroup->getLocation(),
diag::err_decomp_decl_not_alone)
<< FirstDeclaratorInGroup->getSourceRange()
<< DD->getSourceRange();
DiagnosedMultipleDecomps = true;
}
// A decomposition declaration cannot be combined with any other
// declaration in the same group.
auto *OtherDD = FirstDeclaratorInGroup;
if (OtherDD == FirstDecompDeclaratorInGroup)
OtherDD = DD;
if (OtherDD && FirstDecompDeclaratorInGroup &&
OtherDD != FirstDecompDeclaratorInGroup &&
!DiagnosedMultipleDecomps) {
Diag(FirstDecompDeclaratorInGroup->getLocation(),
diag::err_decomp_decl_not_alone)
<< OtherDD->getSourceRange();
DiagnosedMultipleDecomps = true;
// A declarator that uses 'auto' in any way other than to declare a
// variable with a deduced type cannot be combined with any other
// declarator in the same group.
if (FirstNonDeducedAutoInGroup && !DiagnosedNonDeducedAuto) {
Diag(FirstNonDeducedAutoInGroup->getLocation(),
diag::err_auto_non_deduced_not_alone)
<< FirstNonDeducedAutoInGroup->getType()
->hasAutoForTrailingReturnType()
<< FirstDeclaratorInGroup->getSourceRange()
<< DD->getSourceRange();
DiagnosedNonDeducedAuto = true;
}
}
}
Decls.push_back(D);
@ -11105,38 +11127,27 @@ Sema::BuildDeclaratorGroup(MutableArrayRef<Decl *> Group) {
// deduction, the program is ill-formed.
if (Group.size() > 1) {
QualType Deduced;
CanQualType DeducedCanon;
VarDecl *DeducedDecl = nullptr;
for (unsigned i = 0, e = Group.size(); i != e; ++i) {
if (VarDecl *D = dyn_cast<VarDecl>(Group[i])) {
AutoType *AT = D->getType()->getContainedAutoType();
// FIXME: DR1265: if we have a function pointer declaration, we can have
// an 'auto' from a trailing return type. In that case, the return type
// must match the various other uses of 'auto'.
if (!AT)
continue;
// Don't reissue diagnostics when instantiating a template.
if (D->isInvalidDecl())
break;
QualType U = AT->getDeducedType();
if (!U.isNull()) {
CanQualType UCanon = Context.getCanonicalType(U);
if (Deduced.isNull()) {
Deduced = U;
DeducedCanon = UCanon;
DeducedDecl = D;
} else if (DeducedCanon != UCanon) {
Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
diag::err_auto_different_deductions)
<< (unsigned)AT->getKeyword()
<< Deduced << DeducedDecl->getDeclName()
<< U << D->getDeclName()
<< DeducedDecl->getInit()->getSourceRange()
<< D->getInit()->getSourceRange();
D->setInvalidDecl();
break;
}
}
VarDecl *D = dyn_cast<VarDecl>(Group[i]);
if (!D || D->isInvalidDecl())
break;
AutoType *AT = D->getType()->getContainedAutoType();
if (!AT || AT->getDeducedType().isNull())
continue;
if (Deduced.isNull()) {
Deduced = AT->getDeducedType();
DeducedDecl = D;
} else if (!Context.hasSameType(AT->getDeducedType(), Deduced)) {
Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(),
diag::err_auto_different_deductions)
<< (unsigned)AT->getKeyword()
<< Deduced << DeducedDecl->getDeclName()
<< AT->getDeducedType() << D->getDeclName()
<< DeducedDecl->getInit()->getSourceRange()
<< D->getInit()->getSourceRange();
D->setInvalidDecl();
break;
}
}
}

View File

@ -1,3 +1,4 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++98 -Wno-c++11-extensions
void f() {
@ -19,22 +20,42 @@ void f() {
}
void g() {
#if __has_feature(cxx_trailing_return)
auto a = 0,
#if __has_feature(cxx_trailing_return)
(*b)() -> void,
#endif
(*b)() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
c = 0;
auto d = 0, // expected-error {{'auto' deduced as 'int' in declaration of 'd' and deduced as 'double' in declaration of 'f'}}
#if __has_feature(cxx_trailing_return)
(*e)() -> void,
#endif
auto d = 0,
e() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
f = 0.0;
auto x() -> void, // expected-error {{declaration with trailing return type must be the only declaration in its group}}
y() -> void;
#endif
#if __has_feature(cxx_decltype)
auto g = 0ull, h = decltype(g)(0);
#endif
}
#if __has_feature(cxx_trailing_return)
int F();
auto p = 0, (*q)() -> auto = F; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
#if __cplusplus < 201402L
// expected-error@-2 {{'auto' not allowed in function return type}}
#endif
#endif
#if __cplusplus >= 201402L
namespace DeducedReturnType {
auto a = 0,
b(), // expected-error {{function with deduced return type must be the only declaration in its group}}
c = 0.0;
auto d(), // expected-error {{function with deduced return type must be the only declaration in its group}}
e = 1;
auto f(), // expected-error {{function with deduced return type must be the only declaration in its group}}
g();
}
#endif
template<typename T> void h() {
auto a = T(), *b = &a;
#if __has_feature(cxx_decltype)

View File

@ -14,7 +14,7 @@ namespace dr1213 { // dr1213: 4
#endif
}
namespace dr1250 { // dr1250: 3.9
namespace dr1250 { // dr1250: 3.9
struct Incomplete;
struct Base {
@ -24,9 +24,23 @@ struct Base {
struct Derived : Base {
virtual Incomplete *meow();
};
} // dr1250
}
namespace dr1295 { // dr1295: 4
namespace dr1265 { // dr1265: 5
#if __cplusplus >= 201103L
auto a = 0, b() -> int; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
auto b() -> int, d = 0; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
auto e() -> int, f() -> int; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
#endif
#if __cplusplus >= 201402L
auto g(), h = 0; // expected-error {{function with deduced return type must be the only declaration in its group}}
auto i = 0, j(); // expected-error {{function with deduced return type must be the only declaration in its group}}
auto k(), l(); // expected-error {{function with deduced return type must be the only declaration in its group}}
#endif
}
namespace dr1295 { // dr1295: 4
struct X {
unsigned bitfield : 4;
};

View File

@ -3,6 +3,16 @@
// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++1z %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
__extension__ typedef __SIZE_TYPE__ size_t;
namespace std {
template<typename T> struct initializer_list {
const T *ptr;
size_t n;
initializer_list(const T*, size_t);
};
}
namespace dr1315 { // dr1315: partial
template <int I, int J> struct A {};
template <int I> // expected-note {{non-deducible template parameter 'I'}}
@ -159,6 +169,15 @@ namespace dr1346 { // dr1346: 3.5
#endif
}
namespace dr1347 { // dr1347: yes
auto x = 5, *y = &x; // expected-error 0-1{{extension}}
auto z = y, *q = y; // expected-error {{'auto' deduced as 'int *' in declaration of 'z' and deduced as 'int' in declaration of 'q'}} expected-error 0-1{{extension}}
#if __cplusplus >= 201103L
auto a = 5, b = {1, 2}; // expected-error {{'auto' deduced as 'int' in declaration of 'a' and deduced as 'std::initializer_list<int>' in declaration of 'b'}}
auto (*fp)(int) -> int, i = 0; // expected-error {{declaration with trailing return type must be the only declaration in its group}}
#endif
}
namespace dr1359 { // dr1359: 3.5
#if __cplusplus >= 201103L
union A { constexpr A() = default; };

View File

@ -7405,7 +7405,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1265">1265</a></td>
<td>CD3</td>
<td>Mixed use of the <TT>auto</TT> specifier</td>
<td class="none" align="center">Unknown</td>
<td class="svn" align="center">SVN</td>
</tr>
<tr class="open" id="1266">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1266">1266</a></td>
@ -7897,7 +7897,7 @@ and <I>POD class</I></td>
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1347">1347</a></td>
<td>CD3</td>
<td>Consistency of <TT>auto</TT> in multiple-declarator declarations</td>
<td class="none" align="center">Unknown</td>
<td class="full" align="center">Yes</td>
</tr>
<tr class="open" id="1348">
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1348">1348</a></td>