diff options
author | John McCall <rjmccall@apple.com> | 2011-02-09 01:13:10 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-02-09 01:13:10 +0000 |
commit | 76a40219ee5624d78aba167dce02bdbaa930955f (patch) | |
tree | 3de769c569e320b28ed2b8b89a975c9881d53296 /lib/Sema/SemaExpr.cpp | |
parent | 570729e71654f0564bf2ce6504f8629a96850914 (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.cpp | 188 |
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"); |