/// 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.
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>">;
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 {
}
}
+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;
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;
-
- auto *Decomp = dyn_cast<DecompositionDecl>(D);
- if (Decomp && !FirstDecompDeclaratorInGroup)
- FirstDecompDeclaratorInGroup = Decomp;
-
- // 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;
+ // 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;
+
+ 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 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);
// 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;
}
}
}
+// 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() {
}
void g() {
- auto a = 0,
#if __has_feature(cxx_trailing_return)
- (*b)() -> void,
-#endif
+ auto a = 0,
+ (*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)
#endif
}
-namespace dr1250 { // dr1250: 3.9
+namespace dr1250 { // dr1250: 3.9
struct Incomplete;
struct Base {
struct Derived : Base {
virtual Incomplete *meow();
};
-} // dr1250
+}
+
+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
+namespace dr1295 { // dr1295: 4
struct X {
unsigned bitfield : 4;
};
// 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'}}
#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; };
<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>
<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>