Be sure to instantiate the parameters of a function, even when the

function's type is (strictly speaking) non-dependent. This ensures
that, e.g., default function arguments get instantiated properly.

And, since I couldn't resist, collapse the two implementations of
function-parameter instantiation into calls to a single, new function
(Sema::SubstParmVarDecl), since the two had nearly identical code (and
each had bugs the other didn't!). More importantly, factored out the
semantic analysis of a parameter declaration into
Sema::CheckParameter, which is called both by
Sema::ActOnParamDeclarator (when parameters are parsed) and when a
parameter is instantiated. Previously, we were missing some
Objective-C and address-space checks on instantiated function
parameters.

Fixes PR6733.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101029 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-04-12 07:48:19 +00:00
Родитель 1e46136c52
Коммит cb27b0f70d
6 изменённых файлов: 126 добавлений и 143 удалений

Просмотреть файл

@ -805,6 +805,11 @@ public:
bool &OverloadableAttrRequired);
void CheckMain(FunctionDecl *FD);
virtual DeclPtrTy ActOnParamDeclarator(Scope *S, Declarator &D);
ParmVarDecl *CheckParameter(DeclContext *DC,
TypeSourceInfo *TSInfo, QualType T,
IdentifierInfo *Name,
SourceLocation NameLoc,
VarDecl::StorageClass StorageClass);
virtual void ActOnObjCCatchParam(DeclPtrTy D);
virtual void ActOnParamDefaultArgument(DeclPtrTy param,
SourceLocation EqualLoc,
@ -3642,7 +3647,8 @@ public:
const MultiLevelTemplateArgumentList &TemplateArgs,
SourceLocation Loc,
DeclarationName Entity);
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
const MultiLevelTemplateArgumentList &TemplateArgs);
OwningExprResult SubstExpr(Expr *E,
const MultiLevelTemplateArgumentList &TemplateArgs);
@ -3710,8 +3716,6 @@ public:
DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC,
const MultiLevelTemplateArgumentList &TemplateArgs);
bool CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl *> &Params);
// Objective-C declarations.
virtual DeclPtrTy ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName,

Просмотреть файл

@ -4118,55 +4118,23 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
}
}
// Parameters can not be abstract class types.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
if (!CurContext->isRecord() &&
RequireNonAbstractType(D.getIdentifierLoc(), parmDeclType,
diag::err_abstract_type_in_decl,
AbstractParamType))
D.setInvalidType(true);
QualType T = adjustParameterType(parmDeclType);
// Temporarily put parameter variables in the translation unit, not
// the enclosing context. This prevents them from accidentally
// looking like class members in C++.
DeclContext *DC = Context.getTranslationUnitDecl();
ParmVarDecl *New
= ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II,
T, TInfo, StorageClass, 0);
ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(),
TInfo, parmDeclType, II,
D.getIdentifierLoc(), StorageClass);
if (D.isInvalidType())
New->setInvalidDecl();
// Parameter declarators cannot be interface types. All ObjC objects are
// passed by reference.
if (T->isObjCInterfaceType()) {
Diag(D.getIdentifierLoc(),
diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
New->setInvalidDecl();
}
New->setInvalidDecl();
// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
<< D.getCXXScopeSpec().getRange();
New->setInvalidDecl();
}
// ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
// duration shall not be qualified by an address-space qualifier."
// Since all parameters have automatic store duration, they can not have
// an address space.
if (T.getAddressSpace() != 0) {
Diag(D.getIdentifierLoc(),
diag::err_arg_with_address_space);
New->setInvalidDecl();
}
// Add the parameter declaration into this scope.
S->AddDecl(DeclPtrTy::make(New));
if (II)
@ -4180,6 +4148,43 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
return DeclPtrTy::make(New);
}
ParmVarDecl *Sema::CheckParameter(DeclContext *DC,
TypeSourceInfo *TSInfo, QualType T,
IdentifierInfo *Name,
SourceLocation NameLoc,
VarDecl::StorageClass StorageClass) {
ParmVarDecl *New = ParmVarDecl::Create(Context, DC, NameLoc, Name,
adjustParameterType(T), TSInfo,
StorageClass, 0);
// Parameters can not be abstract class types.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
if (!CurContext->isRecord() &&
RequireNonAbstractType(NameLoc, T, diag::err_abstract_type_in_decl,
AbstractParamType))
New->setInvalidDecl();
// Parameter declarators cannot be interface types. All ObjC objects are
// passed by reference.
if (T->isObjCInterfaceType()) {
Diag(NameLoc,
diag::err_object_cannot_be_passed_returned_by_value) << 1 << T;
New->setInvalidDecl();
}
// ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
// duration shall not be qualified by an address-space qualifier."
// Since all parameters have automatic store duration, they can not have
// an address space.
if (T.getAddressSpace() != 0) {
Diag(NameLoc, diag::err_arg_with_address_space);
New->setInvalidDecl();
}
return New;
}
void Sema::ActOnObjCCatchParam(DeclPtrTy D) {
ParmVarDecl *Param = cast<ParmVarDecl>(D.getAs<Decl>());
Param->setDeclContext(CurContext);

Просмотреть файл

@ -807,47 +807,12 @@ TemplateInstantiator::TransformFunctionTypeParams(FunctionProtoTypeLoc TL,
TransformFunctionTypeParams(TL, PTypes, PVars))
return true;
// Check instantiated parameters.
if (SemaRef.CheckInstantiatedParams(PVars))
return true;
return false;
}
ParmVarDecl *
TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = getDerived().TransformType(OldDI);
if (!NewDI)
return 0;
// TODO: do we have to clone this decl if the types match and
// there's no default argument?
ParmVarDecl *NewParm
= ParmVarDecl::Create(SemaRef.Context,
OldParm->getDeclContext(),
OldParm->getLocation(),
OldParm->getIdentifier(),
NewDI->getType(),
NewDI,
OldParm->getStorageClass(),
/* DefArg */ NULL);
// Maybe adjust new parameter type.
NewParm->setType(SemaRef.adjustParameterType(NewParm->getType()));
// Mark the (new) default argument as uninstantiated (if any).
if (OldParm->hasUninstantiatedDefaultArg()) {
Expr *Arg = OldParm->getUninstantiatedDefaultArg();
NewParm->setUninstantiatedDefaultArg(Arg);
} else if (Expr *Arg = OldParm->getDefaultArg())
NewParm->setUninstantiatedDefaultArg(Arg);
NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
return NewParm;
return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs);
}
QualType
@ -1009,6 +974,40 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
return TLB.getTypeSourceInfo(Context, Result);
}
ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
TypeSourceInfo *NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(),
OldParm->getDeclName());
if (!NewDI)
return 0;
if (NewDI->getType()->isVoidType()) {
Diag(OldParm->getLocation(), diag::err_param_with_void_type);
return 0;
}
ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(),
NewDI, NewDI->getType(),
OldParm->getIdentifier(),
OldParm->getLocation(),
OldParm->getStorageClass());
if (!NewParm)
return 0;
// Mark the (new) default argument as uninstantiated (if any).
if (OldParm->hasUninstantiatedDefaultArg()) {
Expr *Arg = OldParm->getUninstantiatedDefaultArg();
NewParm->setUninstantiatedDefaultArg(Arg);
} else if (Expr *Arg = OldParm->getDefaultArg())
NewParm->setUninstantiatedDefaultArg(Arg);
NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
return NewParm;
}
/// \brief Perform substitution on the base class specifiers of the
/// given class template specialization.
///

Просмотреть файл

@ -1343,41 +1343,7 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
}
ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
QualType T;
TypeSourceInfo *DI = D->getTypeSourceInfo();
if (DI) {
DI = SemaRef.SubstType(DI, TemplateArgs, D->getLocation(),
D->getDeclName());
if (DI) T = DI->getType();
} else {
T = SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(),
D->getDeclName());
DI = 0;
}
if (T.isNull())
return 0;
T = SemaRef.adjustParameterType(T);
// Allocate the parameter
ParmVarDecl *Param
= ParmVarDecl::Create(SemaRef.Context,
SemaRef.Context.getTranslationUnitDecl(),
D->getLocation(),
D->getIdentifier(), T, DI, D->getStorageClass(), 0);
// Mark the default argument as being uninstantiated.
if (D->hasUninstantiatedDefaultArg())
Param->setUninstantiatedDefaultArg(D->getUninstantiatedDefaultArg());
else if (Expr *Arg = D->getDefaultArg())
Param->setUninstantiatedDefaultArg(Arg);
// Note: we don't try to instantiate function parameters until after
// we've instantiated the function's type. Therefore, we don't have
// to check for 'void' parameter types here.
SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Param);
return Param;
return SemaRef.SubstParmVarDecl(D, TemplateArgs);
}
Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl(
@ -1797,29 +1763,6 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
return false;
}
bool
Sema::CheckInstantiatedParams(llvm::SmallVectorImpl<ParmVarDecl*> &Params) {
bool Invalid = false;
for (unsigned i = 0, i_end = Params.size(); i != i_end; ++i)
if (ParmVarDecl *PInst = Params[i]) {
if (PInst->isInvalidDecl())
Invalid = true;
else if (PInst->getType()->isVoidType()) {
Diag(PInst->getLocation(), diag::err_param_with_void_type);
PInst->setInvalidDecl();
Invalid = true;
}
else if (RequireNonAbstractType(PInst->getLocation(),
PInst->getType(),
diag::err_abstract_type_in_decl,
Sema::AbstractParamType)) {
PInst->setInvalidDecl();
Invalid = true;
}
}
return Invalid;
}
TypeSourceInfo*
TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params) {
@ -1833,13 +1776,26 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
if (!NewTInfo)
return 0;
// Get parameters from the new type info.
TypeLoc NewTL = NewTInfo->getTypeLoc();
FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
assert(NewProtoLoc && "Missing prototype?");
for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i)
Params.push_back(NewProtoLoc->getArg(i));
if (NewTInfo != OldTInfo) {
// Get parameters from the new type info.
TypeLoc NewTL = NewTInfo->getTypeLoc();
FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
assert(NewProtoLoc && "Missing prototype?");
for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i)
Params.push_back(NewProtoLoc->getArg(i));
} else {
// The function type itself was not dependent and therefore no
// substitution occurred. However, we still need to instantiate
// the function parameters themselves.
TypeLoc OldTL = OldTInfo->getTypeLoc();
FunctionProtoTypeLoc *OldProtoLoc = cast<FunctionProtoTypeLoc>(&OldTL);
for (unsigned i = 0, i_end = OldProtoLoc->getNumArgs(); i != i_end; ++i) {
ParmVarDecl *Parm = VisitParmVarDecl(OldProtoLoc->getArg(i));
if (!Parm)
return 0;
Params.push_back(Parm);
}
}
return NewTInfo;
}

Просмотреть файл

@ -0,0 +1,19 @@
// RUN: %clang_cc1 -ast-dump %s 2>&1 | FileCheck %s
// This is a wacky test to ensure that we're actually instantiating
// the default rguments of the constructor when the function type is
// otherwise non-dependent.
namespace PR6733 {
template <class T>
class bar {
public: enum { kSomeConst = 128 };
bar(int x = kSomeConst) {}
};
// CHECK: void f()
void f() {
// CHECK: bar<int> tmp =
// CHECK: CXXDefaultArgExpr{{.*}}'int'
bar<int> tmp;
}
}

Просмотреть файл

@ -5,7 +5,7 @@ public:
void f(T x); // expected-error{{argument may not have 'void' type}}
void g(T*);
static int h(T, T); // expected-error 2{{argument may not have 'void' type}}
static int h(T, T); // expected-error {{argument may not have 'void' type}}
};
int identity(int x) { return x; }