aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaType.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2012-02-12 18:42:33 +0000
committerDouglas Gregor <dgregor@apple.com>2012-02-12 18:42:33 +0000
commitf8af98286022f72157d84951b48fde5fb369ab29 (patch)
tree9c6f89ee5d11a63c74f5dd8d9a41476992a4b070 /lib/Sema/SemaType.cpp
parent6dc00f6e98a00bd1c332927c3e04918d7e8b0d4f (diff)
Within the body of a lambda expression, decltype((x)) for an
id-expression 'x' will compute the type based on the assumption that 'x' will be captured, even if it isn't captured, per C++11 [expr.prim.lambda]p18. There are two related refactors that go into implementing this: 1) Split out the check that determines whether we should capture a particular variable reference, along with the computation of the type of the field, from the actual act of capturing the variable. 2) Always compute the result of decltype() within Sema, rather than AST, because the decltype() computation is now context-sensitive. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150347 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaType.cpp')
-rw-r--r--lib/Sema/SemaType.cpp89
1 files changed, 88 insertions, 1 deletions
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 7d9a33af11..a235872d8f 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "clang/Basic/OpenCL.h"
@@ -4368,12 +4369,98 @@ QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) {
return Context.getTypeOfExprType(E);
}
+/// getDecltypeForExpr - Given an expr, will return the decltype for
+/// that expression, according to the rules in C++11
+/// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18.
+static QualType getDecltypeForExpr(Sema &S, Expr *E) {
+ if (E->isTypeDependent())
+ return S.Context.DependentTy;
+
+ // If e is an id expression or a class member access, decltype(e) is defined
+ // as the type of the entity named by e.
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
+ return VD->getType();
+ }
+ if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
+ return FD->getType();
+ }
+ // If e is a function call or an invocation of an overloaded operator,
+ // (parentheses around e are ignored), decltype(e) is defined as the
+ // return type of that function.
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E->IgnoreParens()))
+ return CE->getCallReturnType();
+
+ // C++11 [expr.lambda.prim]p18:
+ // Every occurrence of decltype((x)) where x is a possibly
+ // parenthesized id-expression that names an entity of automatic
+ // storage duration is treated as if x were transformed into an
+ // access to a corresponding data member of the closure type that
+ // would have been declared if x were an odr-use of the denoted
+ // entity.
+ using namespace sema;
+ if (S.getCurLambda()) {
+ if (isa<ParenExpr>(E)) {
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParens())) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
+ QualType T = Var->getType();
+ unsigned FunctionScopesIndex;
+ bool Nested;
+ // Determine whether we can capture this variable.
+ if (S.canCaptureVariable(Var, DRE->getLocation(),
+ /*Explicit=*/false, /*Diagnose=*/false,
+ T, FunctionScopesIndex, Nested)) {
+ // Outer lambda scopes may have an effect on the type of a
+ // capture. Walk the captures outside-in to determine
+ // whether they can add 'const' to a capture by copy.
+ if (FunctionScopesIndex == S.FunctionScopes.size())
+ --FunctionScopesIndex;
+ for (unsigned I = FunctionScopesIndex,
+ E = S.FunctionScopes.size();
+ I != E; ++I) {
+ LambdaScopeInfo *LSI
+ = dyn_cast<LambdaScopeInfo>(S.FunctionScopes[I]);
+ if (!LSI)
+ continue;
+
+ bool ByRef = false;
+ if (LSI->isCaptured(Var))
+ ByRef = LSI->getCapture(Var).isReferenceCapture();
+ else
+ ByRef = (LSI->ImpCaptureStyle
+ == CapturingScopeInfo::ImpCap_LambdaByref);
+
+ T = S.getLambdaCaptureFieldType(T, ByRef);
+ if (!ByRef && !LSI->Mutable)
+ T.addConst();
+ }
+
+ if (!T->isReferenceType())
+ T = S.Context.getLValueReferenceType(T);
+ return T;
+ }
+ }
+ }
+ }
+ }
+
+ QualType T = E->getType();
+
+ // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is
+ // defined as T&, otherwise decltype(e) is defined as T.
+ if (E->isLValue())
+ T = S.Context.getLValueReferenceType(T);
+
+ return T;
+}
+
QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) {
ExprResult ER = CheckPlaceholderExpr(E);
if (ER.isInvalid()) return QualType();
E = ER.take();
- return Context.getDecltypeType(E);
+ return Context.getDecltypeType(E, getDecltypeForExpr(*this, E));
}
QualType Sema::BuildUnaryTransformType(QualType BaseType,