Rvalue references for *this:
- Add ref-qualifiers to the type system; they are part of the
canonical type. Print & profile ref-qualifiers
- Translate the ref-qualifier from the Declarator chunk for
functions to the function type.
- Diagnose mis-uses of ref-qualifiers w.r.t. static member
functions, free functions, constructors, destructors, etc.
- Add serialization and deserialization of ref-qualifiers.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124281 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 95c5797..cc365a2 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -823,6 +823,18 @@
}
};
+/// \brief The kind of C++0x ref-qualifier associated with a function type,
+/// which determines whether a member function's "this" object can be an
+/// lvalue, rvalue, or neither.
+enum RefQualifierKind {
+ /// \brief No ref-qualifier was provided.
+ RQ_None = 0,
+ /// \brief An lvalue ref-qualifier was provided (\c &).
+ RQ_LValue,
+ /// \brief An rvalue ref-qualifier was provided (\c &&).
+ RQ_RValue
+};
+
/// Type - This is the base class of the type hierarchy. A central concept
/// with types is that each type always has a canonical type. A canonical type
/// is the type with any typedef names stripped out of it or the types it
@@ -961,6 +973,11 @@
/// C++ 8.3.5p4: The return type, the parameter type list and the
/// cv-qualifier-seq, [...], are part of the function type.
unsigned TypeQuals : 3;
+
+ /// \brief The ref-qualifier associated with a \c FunctionProtoType.
+ ///
+ /// This is a value of type \c RefQualifierKind.
+ unsigned RefQualifier : 2;
};
class ObjCObjectTypeBitfields {
@@ -2267,7 +2284,8 @@
protected:
FunctionType(TypeClass tc, QualType res, bool variadic,
- unsigned typeQuals, QualType Canonical, bool Dependent,
+ unsigned typeQuals, RefQualifierKind RefQualifier,
+ QualType Canonical, bool Dependent,
bool VariablyModified, bool ContainsUnexpandedParameterPack,
ExtInfo Info)
: Type(tc, Canonical, Dependent, VariablyModified,
@@ -2276,9 +2294,15 @@
FunctionTypeBits.ExtInfo = Info.Bits;
FunctionTypeBits.Variadic = variadic;
FunctionTypeBits.TypeQuals = typeQuals;
+ FunctionTypeBits.RefQualifier = static_cast<unsigned>(RefQualifier);
}
bool isVariadic() const { return FunctionTypeBits.Variadic; }
unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; }
+
+ RefQualifierKind getRefQualifier() const {
+ return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier);
+ }
+
public:
QualType getResultType() const { return ResultType; }
@@ -2307,7 +2331,7 @@
/// no information available about its arguments.
class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode {
FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info)
- : FunctionType(FunctionNoProto, Result, false, 0, Canonical,
+ : FunctionType(FunctionNoProto, Result, false, 0, RQ_None, Canonical,
/*Dependent=*/false, Result->isVariablyModifiedType(),
/*ContainsUnexpandedParameterPack=*/false, Info) {}
@@ -2345,13 +2369,14 @@
struct ExtProtoInfo {
ExtProtoInfo() :
Variadic(false), HasExceptionSpec(false), HasAnyExceptionSpec(false),
- TypeQuals(0), NumExceptions(0), Exceptions(0) {}
+ TypeQuals(0), RefQualifier(RQ_None), NumExceptions(0), Exceptions(0) {}
FunctionType::ExtInfo ExtInfo;
bool Variadic;
bool HasExceptionSpec;
bool HasAnyExceptionSpec;
unsigned char TypeQuals;
+ RefQualifierKind RefQualifier;
unsigned NumExceptions;
const QualType *Exceptions;
};
@@ -2405,6 +2430,7 @@
EPI.HasExceptionSpec = hasExceptionSpec();
EPI.HasAnyExceptionSpec = hasAnyExceptionSpec();
EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals());
+ EPI.RefQualifier = getRefQualifier();
EPI.NumExceptions = NumExceptions;
EPI.Exceptions = exception_begin();
return EPI;
@@ -2434,6 +2460,12 @@
unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); }
+
+ /// \brief Retrieve the ref-qualifier associated with this function type.
+ RefQualifierKind getRefQualifier() const {
+ return FunctionType::getRefQualifier();
+ }
+
typedef const QualType *arg_type_iterator;
arg_type_iterator arg_type_begin() const {
return reinterpret_cast<const QualType *>(this+1);
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 55e9ca3..fe4c182 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -730,6 +730,9 @@
def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">;
def err_invalid_qualified_constructor : Error<
"'%0' qualifier is not allowed on a constructor">;
+def err_ref_qualifier_constructor : Error<
+ "ref-qualifier '%select{&&|&}0' is not allowed on a constructor">;
+
def err_constructor_return_type : Error<
"constructor cannot have a return type">;
def err_constructor_redeclared : Error<"constructor cannot be redeclared">;
@@ -749,6 +752,8 @@
def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">;
def err_invalid_qualified_destructor : Error<
"'%0' qualifier is not allowed on a destructor">;
+def err_ref_qualifier_destructor : Error<
+ "ref-qualifier '%select{&&|&}0' is not allowed on a destructor">;
def err_destructor_return_type : Error<"destructor cannot have a return type">;
def err_destructor_redeclared : Error<"destructor cannot be redeclared">;
def err_destructor_with_params : Error<"destructor cannot have any parameters">;
@@ -2461,11 +2466,17 @@
"invalid use of member %0 in static member function">;
def err_invalid_qualified_function_type : Error<
"type qualifier is not allowed on this function">;
+def err_invalid_ref_qualifier_function_type : Error<
+ "ref-qualifier '%select{&&|&}0' is only allowed on non-static member functions,"
+ " member function pointers, and typedefs of function types">;
def err_invalid_qualified_function_pointer : Error<
"type qualifier is not allowed on this function %select{pointer|reference}0">;
def err_invalid_qualified_typedef_function_type_use : Error<
"a qualified function type cannot be used to declare a "
"%select{static member|nonmember}0 function">;
+def err_invalid_ref_qualifier_typedef_function_type_use : Error<
+ "%select{static member|nonmember}0 function cannot have a ref-qualifier "
+ "'%select{&&|&}1'">;
def err_invalid_non_static_member_use : Error<
"invalid use of nonstatic data member %0">;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 90242e6..cc64935 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -620,7 +620,8 @@
SourceLocation AttrLoc);
QualType BuildFunctionType(QualType T,
QualType *ParamTypes, unsigned NumParamTypes,
- bool Variadic, unsigned Quals,
+ bool Variadic, unsigned Quals,
+ RefQualifierKind RefQualifier,
SourceLocation Loc, DeclarationName Entity,
FunctionType::ExtInfo Info);
QualType BuildMemberPointerType(QualType T, QualType Class,
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index d8939cc..36d5015 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1112,7 +1112,8 @@
FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
unsigned numArgs, QualType canonical,
const ExtProtoInfo &epi)
- : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals, canonical,
+ : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals,
+ epi.RefQualifier, canonical,
result->isDependentType(),
result->isVariablyModifiedType(),
result->containsUnexpandedParameterPack(),
@@ -1162,6 +1163,7 @@
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
ID.AddBoolean(epi.Variadic);
ID.AddInteger(epi.TypeQuals);
+ ID.AddInteger(epi.RefQualifier);
if (epi.HasExceptionSpec) {
ID.AddBoolean(epi.HasAnyExceptionSpec);
for (unsigned i = 0; i != epi.NumExceptions; ++i)
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 8a740d4..c0ce1f2 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -354,6 +354,21 @@
S += " __attribute__((regparm (" +
llvm::utostr_32(Info.getRegParm()) + ")))";
+ AppendTypeQualList(S, T->getTypeQuals());
+
+ switch (T->getRefQualifier()) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ S += " &";
+ break;
+
+ case RQ_RValue:
+ S += " &&";
+ break;
+ }
+
if (T->hasExceptionSpec()) {
S += " throw(";
if (T->hasAnyExceptionSpec())
@@ -370,8 +385,6 @@
S += ")";
}
- AppendTypeQualList(S, T->getTypeQuals());
-
print(T->getResultType(), S);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index d5dea78..78d9a5b 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3023,6 +3023,15 @@
D.setInvalidType();
}
+ // C++0x [class.ctor]p4:
+ // A constructor shall not be declared with a ref-qualifier.
+ if (FTI.hasRefQualifier()) {
+ Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_constructor)
+ << FTI.RefQualifierIsLValueRef
+ << FixItHint::CreateRemoval(FTI.getRefQualifierLoc());
+ D.setInvalidType();
+ }
+
// Rebuild the function type "R" without any type qualifiers (in
// case any of the errors above fired) and with "void" as the
// return type, since constructors don't have return types.
@@ -3032,7 +3041,8 @@
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
EPI.TypeQuals = 0;
-
+ EPI.RefQualifier = RQ_None;
+
return Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
Proto->getNumArgs(), EPI);
}
@@ -3173,6 +3183,15 @@
D.setInvalidType();
}
+ // C++0x [class.dtor]p2:
+ // A destructor shall not be declared with a ref-qualifier.
+ if (FTI.hasRefQualifier()) {
+ Diag(FTI.getRefQualifierLoc(), diag::err_ref_qualifier_destructor)
+ << FTI.RefQualifierIsLValueRef
+ << FixItHint::CreateRemoval(FTI.getRefQualifierLoc());
+ D.setInvalidType();
+ }
+
// Make sure we don't have any parameters.
if (FTI.NumArgs > 0 && !FTIHasSingleVoidArgument(FTI)) {
Diag(D.getIdentifierLoc(), diag::err_destructor_with_params);
@@ -3199,6 +3218,7 @@
FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo();
EPI.Variadic = false;
EPI.TypeQuals = 0;
+ EPI.RefQualifier = RQ_None;
return Context.getFunctionType(Context.VoidTy, 0, 0, EPI);
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 00d92bc..70e9973 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2106,6 +2106,7 @@
ParamTypes.data(), ParamTypes.size(),
Proto->isVariadic(),
Proto->getTypeQuals(),
+ Proto->getRefQualifier(),
Function->getLocation(),
Function->getDeclName(),
Proto->getExtInfo());
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index b663f58..64d5c42 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1269,6 +1269,7 @@
QualType *ParamTypes,
unsigned NumParamTypes,
bool Variadic, unsigned Quals,
+ RefQualifierKind RefQualifier,
SourceLocation Loc, DeclarationName Entity,
FunctionType::ExtInfo Info) {
if (T->isArrayType() || T->isFunctionType()) {
@@ -1294,6 +1295,7 @@
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = Variadic;
EPI.TypeQuals = Quals;
+ EPI.RefQualifier = RefQualifier;
EPI.ExtInfo = Info;
return Context.getFunctionType(T, ParamTypes, NumParamTypes, EPI);
@@ -1722,7 +1724,10 @@
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = FTI.isVariadic;
EPI.TypeQuals = FTI.TypeQuals;
-
+ EPI.RefQualifier = !FTI.hasRefQualifier()? RQ_None
+ : FTI.RefQualifierIsLValueRef? RQ_LValue
+ : RQ_RValue;
+
// Otherwise, we have a function with an argument list that is
// potentially variadic.
llvm::SmallVector<QualType, 16> ArgTys;
@@ -1876,21 +1881,44 @@
FreeFunction = (DC && !DC->isRecord());
}
- if (FnTy->getTypeQuals() != 0 &&
+ // C++0x [dcl.fct]p6:
+ // A ref-qualifier shall only be part of the function type for a
+ // non-static member function, the function type to which a pointer to
+ // member refers, or the top-level function type of a function typedef
+ // declaration.
+ if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) &&
D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef &&
(FreeFunction ||
D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) {
- if (D.isFunctionDeclarator())
- Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
- else
- Diag(D.getIdentifierLoc(),
- diag::err_invalid_qualified_typedef_function_type_use)
- << FreeFunction;
-
- // Strip the cv-quals from the type.
+ if (FnTy->getTypeQuals() != 0) {
+ if (D.isFunctionDeclarator())
+ Diag(D.getIdentifierLoc(), diag::err_invalid_qualified_function_type);
+ else
+ Diag(D.getIdentifierLoc(),
+ diag::err_invalid_qualified_typedef_function_type_use)
+ << FreeFunction;
+ }
+
+ if (FnTy->getRefQualifier()) {
+ if (D.isFunctionDeclarator()) {
+ SourceLocation Loc
+ = D.getTypeObject(D.getNumTypeObjects()-1).Fun.getRefQualifierLoc();
+ Diag(Loc, diag::err_invalid_ref_qualifier_function_type)
+ << (FnTy->getRefQualifier() == RQ_LValue)
+ << FixItHint::CreateRemoval(Loc);
+ } else {
+ Diag(D.getIdentifierLoc(),
+ diag::err_invalid_ref_qualifier_typedef_function_type_use)
+ << FreeFunction
+ << (FnTy->getRefQualifier() == RQ_LValue);
+ }
+ }
+
+ // Strip the cv-quals and ref-qualifier from the type.
FunctionProtoType::ExtProtoInfo EPI = FnTy->getExtProtoInfo();
EPI.TypeQuals = 0;
-
+ EPI.RefQualifier = RQ_None;
+
T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(),
FnTy->getNumArgs(), EPI);
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 04c45b8..3f8d3e5 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -633,6 +633,7 @@
QualType *ParamTypes,
unsigned NumParamTypes,
bool Variadic, unsigned Quals,
+ RefQualifierKind RefQualifier,
const FunctionType::ExtInfo &Info);
/// \brief Build a new unprototyped function type.
@@ -3796,6 +3797,7 @@
ParamTypes.size(),
T->isVariadic(),
T->getTypeQuals(),
+ T->getRefQualifier(),
T->getExtInfo());
if (Result.isNull())
return QualType();
@@ -7178,7 +7180,7 @@
ParamTypes.data(),
ParamTypes.size(),
BD->isVariadic(),
- 0,
+ 0, RQ_None,
BExprFunctionType->getExtInfo());
CurBlock->FunctionType = FunctionType;
@@ -7373,9 +7375,10 @@
unsigned NumParamTypes,
bool Variadic,
unsigned Quals,
+ RefQualifierKind RefQualifier,
const FunctionType::ExtInfo &Info) {
return SemaRef.BuildFunctionType(T, ParamTypes, NumParamTypes, Variadic,
- Quals,
+ Quals, RefQualifier,
getDerived().getBaseLocation(),
getDerived().getBaseEntity(),
Info);
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index a722df7..b569f4b 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -2873,6 +2873,7 @@
EPI.Variadic = Record[Idx++];
EPI.TypeQuals = Record[Idx++];
+ EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]);
EPI.HasExceptionSpec = Record[Idx++];
EPI.HasAnyExceptionSpec = Record[Idx++];
EPI.NumExceptions = Record[Idx++];
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 1e296e8..e906407 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -176,6 +176,7 @@
Writer.AddTypeRef(T->getArgType(I), Record);
Record.push_back(T->isVariadic());
Record.push_back(T->getTypeQuals());
+ Record.push_back(static_cast<unsigned>(T->getRefQualifier()));
Record.push_back(T->hasExceptionSpec());
Record.push_back(T->hasAnyExceptionSpec());
Record.push_back(T->getNumExceptions());
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
new file mode 100644
index 0000000..a2533ca
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct/p6-0x.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+void f0() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+void f1() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+
+struct X {
+ void f0() &;
+ void f1() &&;
+ static void f2() &; // expected-error{{ref-qualifier '&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+ static void f3() &&; // expected-error{{ref-qualifier '&&' is only allowed on non-static member functions, member function pointers, and typedefs of function types}}
+};
+
+typedef void func_type_lvalue() &;
+typedef void func_type_rvalue() &&;
+
+func_type_lvalue f2; // expected-error{{nonmember function cannot have a ref-qualifier '&'}}
+func_type_rvalue f3; // expected-error{{nonmember function cannot have a ref-qualifier '&&'}}
+
+struct Y {
+ func_type_lvalue f0;
+ func_type_rvalue f1;
+};
+
+void (X::*mpf1)() & = &X::f0;
+void (X::*mpf2)() && = &X::f1;
+
diff --git a/test/CXX/special/class.ctor/p4-0x.cpp b/test/CXX/special/class.ctor/p4-0x.cpp
new file mode 100644
index 0000000..e3508e2
--- /dev/null
+++ b/test/CXX/special/class.ctor/p4-0x.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// A constructor shall not be declared with a ref-qualifier.
+struct X {
+ X() &; // expected-error{{ref-qualifier '&' is not allowed on a constructor}}
+ X(int) &&; // expected-error{{ref-qualifier '&&' is not allowed on a constructor}}
+};
diff --git a/test/CXX/special/class.dtor/p2-0x.cpp b/test/CXX/special/class.dtor/p2-0x.cpp
new file mode 100644
index 0000000..53a2e03
--- /dev/null
+++ b/test/CXX/special/class.dtor/p2-0x.cpp
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// A destructor shall not be declared with a ref-qualifier.
+struct X {
+ ~X() &; // expected-error{{ref-qualifier '&' is not allowed on a destructor}}
+};
+
+struct Y {
+ ~Y() &&; // expected-error{{ref-qualifier '&&' is not allowed on a destructor}}
+};