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 | |
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
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 7 | ||||
-rw-r--r-- | include/clang/AST/RecursiveASTVisitor.h | 2 | ||||
-rw-r--r-- | include/clang/Basic/DeclNodes.td | 2 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 188 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 2 |
7 files changed, 147 insertions, 69 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 069088124d..176c6badae 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -985,7 +985,7 @@ public: /// template<int Size> class array { }; /// @endcode class NonTypeTemplateParmDecl - : public VarDecl, protected TemplateParmPosition { + : public DeclaratorDecl, protected TemplateParmPosition { /// \brief The default template argument, if any, and whether or not /// it was inherited. llvm::PointerIntPair<Expr*, 1, bool> DefaultArgumentAndInherited; @@ -1007,7 +1007,7 @@ class NonTypeTemplateParmDecl NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, bool ParameterPack, TypeSourceInfo *TInfo) - : VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, SC_None, SC_None), + : DeclaratorDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo), TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false), ParameterPack(ParameterPack), ExpandedParameterPack(false), NumExpandedTypes(0) @@ -1040,6 +1040,9 @@ public: using TemplateParmPosition::setPosition; using TemplateParmPosition::getIndex; + SourceLocation getInnerLocStart() const; + SourceRange getSourceRange() const; + /// \brief Determine whether this template parameter has a default /// argument. bool hasDefaultArgument() const { diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 772a356723..0a98beae08 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1538,7 +1538,7 @@ DEF_TRAVERSE_DECL(ImplicitParamDecl, { DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, { // A non-type template parameter, e.g. "S" in template<int S> class Foo ... - TRY_TO(TraverseVarHelper(D)); + TRY_TO(TraverseDeclaratorHelper(D)); TRY_TO(TraverseStmt(D->getDefaultArgument())); }) diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index 3e60d864a9..f6c31f4877 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -42,7 +42,7 @@ def Named : Decl<1>; def Var : DDecl<Declarator>; def ImplicitParam : DDecl<Var>; def ParmVar : DDecl<Var>; - def NonTypeTemplateParm : DDecl<Var>; + def NonTypeTemplateParm : DDecl<Declarator>; def Template : DDecl<Named, 1>; def RedeclarableTemplate : DDecl<Template, 1>; def FunctionTemplate : DDecl<RedeclarableTemplate>; diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index e3820172fe..a73deeab3a 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -408,7 +408,7 @@ NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC, const QualType *ExpandedTypes, unsigned NumExpandedTypes, TypeSourceInfo **ExpandedTInfos) - : VarDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo, SC_None, SC_None), + : DeclaratorDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo), TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false), ParameterPack(true), ExpandedParameterPack(true), NumExpandedTypes(NumExpandedTypes) @@ -447,6 +447,17 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, ExpandedTInfos); } +SourceLocation NonTypeTemplateParmDecl::getInnerLocStart() const { + SourceLocation Start = getTypeSpecStartLoc(); + if (Start.isInvalid()) + Start = getLocation(); + return Start; +} + +SourceRange NonTypeTemplateParmDecl::getSourceRange() const { + return SourceRange(getOuterLocStart(), getLocation()); +} + SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { return hasDefaultArgument() ? getDefaultArgument()->getSourceRange().getBegin() 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"); diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 2c304326bf..56c33ca913 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1168,7 +1168,7 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { } void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { - VisitVarDecl(D); + VisitDeclaratorDecl(D); // TemplateParmPosition. D->setDepth(Record[Idx++]); D->setPosition(Record[Idx++]); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 3e57de11c8..b0ed8bc59f 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -1009,7 +1009,7 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { if (D->isExpandedParameterPack()) Record.push_back(D->getNumExpansionTypes()); - VisitVarDecl(D); + VisitDeclaratorDecl(D); // TemplateParmPosition. Record.push_back(D->getDepth()); Record.push_back(D->getPosition()); |