aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2011-02-09 01:13:10 +0000
committerJohn McCall <rjmccall@apple.com>2011-02-09 01:13:10 +0000
commit76a40219ee5624d78aba167dce02bdbaa930955f (patch)
tree3de769c569e320b28ed2b8b89a975c9881d53296 /lib/Sema/SemaExpr.cpp
parent570729e71654f0564bf2ce6504f8629a96850914 (diff)
NonTypeTemplateParmDecl is just a DeclaratorDecl, not a VarDecl.
Also, reorganize and make very explicit the logic for determining the value kind and type of a referenced declaration. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125150 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r--lib/Sema/SemaExpr.cpp188
1 files changed, 126 insertions, 62 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 3c07318158..429804d6e9 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -820,7 +820,7 @@ static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc,
ValueDecl *value) {
// Only variables ever require capture.
VarDecl *var = dyn_cast<VarDecl>(value);
- if (!var || isa<NonTypeTemplateParmDecl>(var)) return CR_NoCapture;
+ if (!var) return CR_NoCapture;
// Fast path: variables from the current context never require capture.
DeclContext *DC = S.CurContext;
@@ -949,38 +949,25 @@ static ExprResult BuildBlockDeclRefExpr(Sema &S, ValueDecl *vd,
ExprResult
Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
- SourceLocation Loc, const CXXScopeSpec *SS) {
+ SourceLocation Loc,
+ const CXXScopeSpec *SS) {
DeclarationNameInfo NameInfo(D->getDeclName(), Loc);
return BuildDeclRefExpr(D, Ty, VK, NameInfo, SS);
}
-/// BuildDeclRefExpr - Build a DeclRefExpr.
+/// BuildDeclRefExpr - Build an expression that references a
+/// declaration that does not require a closure capture.
ExprResult
-Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty,
- ExprValueKind VK,
+Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
const DeclarationNameInfo &NameInfo,
const CXXScopeSpec *SS) {
- if (Context.getCanonicalType(Ty) == Context.UndeducedAutoTy) {
+ if (Ty == Context.UndeducedAutoTy) {
Diag(NameInfo.getLoc(),
diag::err_auto_variable_cannot_appear_in_own_initializer)
<< D->getDeclName();
return ExprError();
}
- if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (isa<NonTypeTemplateParmDecl>(VD)) {
- // Non-type template parameters can be referenced anywhere they are
- // visible.
- Ty = Ty.getNonLValueExprType(Context);
-
- // This ridiculousness brought to you by 'extern void x;' and the
- // GNU compiler collection.
- } else if (!getLangOptions().CPlusPlus && !Ty.hasQualifiers() &&
- Ty->isVoidType()) {
- VK = VK_RValue;
- }
- }
-
MarkDeclarationReferenced(NameInfo.getLoc(), D);
Expr *E = DeclRefExpr::Create(Context,
@@ -1694,24 +1681,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S,
Diag(Var->getLocation(), diag::note_global_declared_at);
}
}
- } else if (FunctionDecl *Func = R.getAsSingle<FunctionDecl>()) {
- if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) {
- // C99 DR 316 says that, if a function type comes from a
- // function definition (without a prototype), that type is only
- // used for checking compatibility. Therefore, when referencing
- // the function, we pretend that we don't have the full function
- // type.
- if (DiagnoseUseOfDecl(Func, NameLoc))
- return ExprError();
-
- QualType T = Func->getType();
- QualType NoProtoType = T;
- if (const FunctionProtoType *Proto = T->getAs<FunctionProtoType>())
- NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType(),
- Proto->getExtInfo());
- // Note that functions are r-values in C.
- return BuildDeclRefExpr(Func, NoProtoType, VK_RValue, NameLoc, &SS);
- }
}
// Check whether this might be a C++ implicit instance member access.
@@ -2325,21 +2294,6 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
return Owned(ULE);
}
-static ExprValueKind getValueKindForDecl(ASTContext &Context,
- const ValueDecl *D) {
- // FIXME: It's not clear to me why NonTypeTemplateParmDecl is a VarDecl.
- if (isa<VarDecl>(D) && !isa<NonTypeTemplateParmDecl>(D)) return VK_LValue;
- if (isa<FieldDecl>(D)) return VK_LValue;
- if (isa<IndirectFieldDecl>(D)) return VK_LValue;
- if (!Context.getLangOptions().CPlusPlus) return VK_RValue;
- if (isa<FunctionDecl>(D)) {
- if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance())
- return VK_RValue;
- return VK_LValue;
- }
- return Expr::getValueKindForType(D->getType());
-}
-
/// \brief Complete semantic analysis for a reference to the given declaration.
ExprResult
Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
@@ -2402,15 +2356,6 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
case CR_Error:
return ExprError();
- case CR_NoCapture: {
- ExprValueKind VK = getValueKindForDecl(Context, VD);
-
- // If this reference is not in a block or if the referenced
- // variable is within the block, create a normal DeclRefExpr.
- return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), VK,
- NameInfo, &SS);
- }
-
case CR_Capture:
assert(!SS.isSet() && "referenced local variable with scope specifier?");
return BuildBlockDeclRefExpr(*this, VD, NameInfo, /*byref*/ false);
@@ -2418,6 +2363,125 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
case CR_CaptureByRef:
assert(!SS.isSet() && "referenced local variable with scope specifier?");
return BuildBlockDeclRefExpr(*this, VD, NameInfo, /*byref*/ true);
+
+ case CR_NoCapture: {
+ // If this reference is not in a block or if the referenced
+ // variable is within the block, create a normal DeclRefExpr.
+
+ QualType type = VD->getType();
+ ExprValueKind valueKind;
+
+ switch (D->getKind()) {
+ // Ignore all the non-ValueDecl kinds.
+#define ABSTRACT_DECL(kind)
+#define VALUE(type, base)
+#define DECL(type, base) \
+ case Decl::type:
+#include "clang/AST/DeclNodes.inc"
+ llvm_unreachable("invalid value decl kind");
+ return ExprError();
+
+ // These shouldn't make it here.
+ case Decl::ObjCAtDefsField:
+ case Decl::ObjCIvar:
+ llvm_unreachable("forming non-member reference to ivar?");
+ return ExprError();
+
+ // Enum constants are always r-values and never references.
+ // Unresolved using declarations are dependent.
+ case Decl::EnumConstant:
+ case Decl::UnresolvedUsingValue:
+ valueKind = VK_RValue;
+ break;
+
+ // Fields and indirect fields that got here must be for
+ // pointer-to-member expressions; we just call them l-values for
+ // internal consistency, because this subexpression doesn't really
+ // exist in the high-level semantics.
+ case Decl::Field:
+ case Decl::IndirectField:
+ assert(getLangOptions().CPlusPlus &&
+ "building reference to field in C?");
+
+ // These can't have reference type in well-formed programs, but
+ // for internal consistency we do this anyway.
+ type = type.getNonReferenceType();
+ valueKind = VK_LValue;
+ break;
+
+ // Non-type template parameters are either l-values or r-values
+ // depending on the type.
+ case Decl::NonTypeTemplateParm: {
+ if (const ReferenceType *reftype = type->getAs<ReferenceType>()) {
+ type = reftype->getPointeeType();
+ valueKind = VK_LValue; // even if the parameter is an r-value reference
+ break;
+ }
+
+ // For non-references, we need to strip qualifiers just in case
+ // the template parameter was declared as 'const int' or whatever.
+ valueKind = VK_RValue;
+ type = type.getUnqualifiedType();
+ break;
+ }
+
+ case Decl::Var:
+ // In C, "extern void blah;" is valid and is an r-value.
+ if (!getLangOptions().CPlusPlus &&
+ !type.hasQualifiers() &&
+ type->isVoidType()) {
+ valueKind = VK_RValue;
+ break;
+ }
+ // fallthrough
+
+ case Decl::ImplicitParam:
+ case Decl::ParmVar:
+ // These are always l-values.
+ valueKind = VK_LValue;
+ type = type.getNonReferenceType();
+ break;
+
+ case Decl::Function: {
+ // Functions are l-values in C++.
+ if (getLangOptions().CPlusPlus) {
+ valueKind = VK_LValue;
+ break;
+ }
+
+ // C99 DR 316 says that, if a function type comes from a
+ // function definition (without a prototype), that type is only
+ // used for checking compatibility. Therefore, when referencing
+ // the function, we pretend that we don't have the full function
+ // type.
+ if (!cast<FunctionDecl>(VD)->hasPrototype())
+ if (const FunctionProtoType *proto = type->getAs<FunctionProtoType>())
+ type = Context.getFunctionNoProtoType(proto->getResultType(),
+ proto->getExtInfo());
+
+ // Functions are r-values in C.
+ valueKind = VK_RValue;
+ break;
+ }
+
+ case Decl::CXXMethod:
+ // C++ methods are l-values if static, r-values if non-static.
+ if (cast<CXXMethodDecl>(VD)->isStatic()) {
+ valueKind = VK_LValue;
+ break;
+ }
+ // fallthrough
+
+ case Decl::CXXConversion:
+ case Decl::CXXDestructor:
+ case Decl::CXXConstructor:
+ valueKind = VK_RValue;
+ break;
+ }
+
+ return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS);
+ }
+
}
llvm_unreachable("unknown capture result");