Further fixes when thiscall is the default for methods.

The previous patches tried to deduce the correct function type. I now realize
this is not possible in general. Consider

class foo {
    template <typename T> static void bar(T v);
};
extern template void foo::bar(const void *);

We will only know that bar is static after a lookup, so we have to handle this
in the template instantiation code.

This patch reverts my previous two changes (but not the tests) and instead
handles the issue in DeduceTemplateArguments.

llvm-svn: 195154
This commit is contained in:
Rafael Espindola 2013-11-19 21:07:04 +00:00
parent 8aac4f6d7b
commit 92045bc37c
4 changed files with 160 additions and 162 deletions

View File

@ -6501,11 +6501,11 @@ bool Sema::CheckFunctionTemplateSpecialization(
// it will be a static member function until we know which template it
// specializes), so adjust it now assuming it specializes this template.
QualType FT = FD->getType();
const FunctionProtoType *FPT = FT->castAs<FunctionProtoType>();
FunctionDecl *TmplFD = FunTmpl->getTemplatedDecl();
if (FD->isConstexpr()) {
CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(TmplFD);
CXXMethodDecl *OldMD =
dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
if (OldMD && OldMD->isConst()) {
const FunctionProtoType *FPT = FT->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals |= Qualifiers::Const;
FT = Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(),
@ -6513,19 +6513,6 @@ bool Sema::CheckFunctionTemplateSpecialization(
}
}
// Ignore differences in calling convention and noreturn until decl
// merging.
const FunctionProtoType *TmplFT =
TmplFD->getType()->castAs<FunctionProtoType>();
if (FPT->getCallConv() != TmplFT->getCallConv() ||
FPT->getNoReturnAttr() != TmplFT->getNoReturnAttr()) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = EPI.ExtInfo.withCallingConv(TmplFT->getCallConv());
EPI.ExtInfo = EPI.ExtInfo.withNoReturn(TmplFT->getNoReturnAttr());
FT = Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(),
EPI);
}
// C++ [temp.expl.spec]p11:
// A trailing template-argument can be left unspecified in the
// template-id naming an explicit function template specialization

View File

@ -3538,6 +3538,23 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
TemplateParameterList *TemplateParams
= FunctionTemplate->getTemplateParameters();
QualType FunctionType = Function->getType();
if (!InOverloadResolution && !ArgFunctionType.isNull()) {
const FunctionProtoType *FunctionTypeP =
FunctionType->castAs<FunctionProtoType>();
CallingConv CC = FunctionTypeP->getCallConv();
bool NoReturn = FunctionTypeP->getNoReturnAttr();
const FunctionProtoType *ArgFunctionTypeP =
ArgFunctionType->getAs<FunctionProtoType>();
if (ArgFunctionTypeP->getCallConv() != CC ||
ArgFunctionTypeP->getNoReturnAttr() != NoReturn) {
FunctionType::ExtInfo EI =
ArgFunctionTypeP->getExtInfo().withCallingConv(CC);
EI = EI.withNoReturn(NoReturn);
ArgFunctionTypeP = cast<FunctionProtoType>(
Context.adjustFunctionType(ArgFunctionTypeP, EI));
ArgFunctionType = QualType(ArgFunctionTypeP, 0);
}
}
// Substitute any explicit template arguments.
LocalInstantiationScope InstScope(*this);

View File

@ -2506,136 +2506,6 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D,
IsCXXInstanceMethod);
}
namespace {
/// A helper class to unwrap a type down to a function for the
/// purposes of applying attributes there.
///
/// Use:
/// FunctionTypeUnwrapper unwrapped(SemaRef, T);
/// if (unwrapped.isFunctionType()) {
/// const FunctionType *fn = unwrapped.get();
/// // change fn somehow
/// T = unwrapped.wrap(fn);
/// }
struct FunctionTypeUnwrapper {
enum WrapKind {
Desugar,
Parens,
Pointer,
BlockPointer,
Reference,
MemberPointer
};
QualType Original;
const FunctionType *Fn;
SmallVector<unsigned char /*WrapKind*/, 8> Stack;
FunctionTypeUnwrapper(Sema &S, QualType T) : Original(T) {
while (true) {
const Type *Ty = T.getTypePtr();
if (isa<FunctionType>(Ty)) {
Fn = cast<FunctionType>(Ty);
return;
} else if (isa<ParenType>(Ty)) {
T = cast<ParenType>(Ty)->getInnerType();
Stack.push_back(Parens);
} else if (isa<PointerType>(Ty)) {
T = cast<PointerType>(Ty)->getPointeeType();
Stack.push_back(Pointer);
} else if (isa<BlockPointerType>(Ty)) {
T = cast<BlockPointerType>(Ty)->getPointeeType();
Stack.push_back(BlockPointer);
} else if (isa<MemberPointerType>(Ty)) {
T = cast<MemberPointerType>(Ty)->getPointeeType();
Stack.push_back(MemberPointer);
} else if (isa<ReferenceType>(Ty)) {
T = cast<ReferenceType>(Ty)->getPointeeType();
Stack.push_back(Reference);
} else {
const Type *DTy = Ty->getUnqualifiedDesugaredType();
if (Ty == DTy) {
Fn = 0;
return;
}
T = QualType(DTy, 0);
Stack.push_back(Desugar);
}
}
}
bool isFunctionType() const { return (Fn != 0); }
const FunctionType *get() const { return Fn; }
QualType wrap(Sema &S, const FunctionType *New) {
// If T wasn't modified from the unwrapped type, do nothing.
if (New == get()) return Original;
Fn = New;
return wrap(S.Context, Original, 0);
}
private:
QualType wrap(ASTContext &C, QualType Old, unsigned I) {
if (I == Stack.size())
return C.getQualifiedType(Fn, Old.getQualifiers());
// Build up the inner type, applying the qualifiers from the old
// type to the new type.
SplitQualType SplitOld = Old.split();
// As a special case, tail-recurse if there are no qualifiers.
if (SplitOld.Quals.empty())
return wrap(C, SplitOld.Ty, I);
return C.getQualifiedType(wrap(C, SplitOld.Ty, I), SplitOld.Quals);
}
QualType wrap(ASTContext &C, const Type *Old, unsigned I) {
if (I == Stack.size()) return QualType(Fn, 0);
switch (static_cast<WrapKind>(Stack[I++])) {
case Desugar:
// This is the point at which we potentially lose source
// information.
return wrap(C, Old->getUnqualifiedDesugaredType(), I);
case Parens: {
QualType New = wrap(C, cast<ParenType>(Old)->getInnerType(), I);
return C.getParenType(New);
}
case Pointer: {
QualType New = wrap(C, cast<PointerType>(Old)->getPointeeType(), I);
return C.getPointerType(New);
}
case BlockPointer: {
QualType New = wrap(C, cast<BlockPointerType>(Old)->getPointeeType(),I);
return C.getBlockPointerType(New);
}
case MemberPointer: {
const MemberPointerType *OldMPT = cast<MemberPointerType>(Old);
QualType New = wrap(C, OldMPT->getPointeeType(), I);
return C.getMemberPointerType(New, OldMPT->getClass());
}
case Reference: {
const ReferenceType *OldRef = cast<ReferenceType>(Old);
QualType New = wrap(C, OldRef->getPointeeType(), I);
if (isa<LValueReferenceType>(OldRef))
return C.getLValueReferenceType(New, OldRef->isSpelledAsLValue());
else
return C.getRValueReferenceType(New);
}
}
llvm_unreachable("unknown wrapping kind");
}
};
}
static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
QualType declSpecType,
TypeSourceInfo *TInfo) {
@ -3240,27 +3110,14 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// top-level template type arguments.
bool FreeFunction;
if (!D.getCXXScopeSpec().isSet()) {
const DeclSpec &Spec = D.getDeclSpec();
FreeFunction = (D.getContext() != Declarator::MemberContext &&
D.getContext() != Declarator::LambdaExprContext) ||
Spec.isFriendSpecified() ||
Spec.getStorageClassSpec() == DeclSpec::SCS_typedef;
FreeFunction = ((D.getContext() != Declarator::MemberContext &&
D.getContext() != Declarator::LambdaExprContext) ||
D.getDeclSpec().isFriendSpecified());
} else {
DeclContext *DC = S.computeDeclContext(D.getCXXScopeSpec());
FreeFunction = (DC && !DC->isRecord());
}
if (!S.getCallingConvAttributedType(T)) {
CallingConv CC =
Context.getDefaultCallingConvention(FnTy->isVariadic(), !FreeFunction);
if (CC != FnTy->getCallConv()) {
FunctionType::ExtInfo EI = FnTy->getExtInfo().withCallingConv(CC);
FnTy = cast<FunctionProtoType>(S.Context.adjustFunctionType(FnTy, EI));
FunctionTypeUnwrapper Unwrapped(S, T);
T = Unwrapped.wrap(S, FnTy);
}
}
// C++11 [dcl.fct]p6 (w/DR1417):
// An attempt to specify a function type with a cv-qualifier-seq or a
// ref-qualifier (including by typedef-name) is ill-formed unless it is:
@ -4361,6 +4218,136 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state,
return true;
}
namespace {
/// A helper class to unwrap a type down to a function for the
/// purposes of applying attributes there.
///
/// Use:
/// FunctionTypeUnwrapper unwrapped(SemaRef, T);
/// if (unwrapped.isFunctionType()) {
/// const FunctionType *fn = unwrapped.get();
/// // change fn somehow
/// T = unwrapped.wrap(fn);
/// }
struct FunctionTypeUnwrapper {
enum WrapKind {
Desugar,
Parens,
Pointer,
BlockPointer,
Reference,
MemberPointer
};
QualType Original;
const FunctionType *Fn;
SmallVector<unsigned char /*WrapKind*/, 8> Stack;
FunctionTypeUnwrapper(Sema &S, QualType T) : Original(T) {
while (true) {
const Type *Ty = T.getTypePtr();
if (isa<FunctionType>(Ty)) {
Fn = cast<FunctionType>(Ty);
return;
} else if (isa<ParenType>(Ty)) {
T = cast<ParenType>(Ty)->getInnerType();
Stack.push_back(Parens);
} else if (isa<PointerType>(Ty)) {
T = cast<PointerType>(Ty)->getPointeeType();
Stack.push_back(Pointer);
} else if (isa<BlockPointerType>(Ty)) {
T = cast<BlockPointerType>(Ty)->getPointeeType();
Stack.push_back(BlockPointer);
} else if (isa<MemberPointerType>(Ty)) {
T = cast<MemberPointerType>(Ty)->getPointeeType();
Stack.push_back(MemberPointer);
} else if (isa<ReferenceType>(Ty)) {
T = cast<ReferenceType>(Ty)->getPointeeType();
Stack.push_back(Reference);
} else {
const Type *DTy = Ty->getUnqualifiedDesugaredType();
if (Ty == DTy) {
Fn = 0;
return;
}
T = QualType(DTy, 0);
Stack.push_back(Desugar);
}
}
}
bool isFunctionType() const { return (Fn != 0); }
const FunctionType *get() const { return Fn; }
QualType wrap(Sema &S, const FunctionType *New) {
// If T wasn't modified from the unwrapped type, do nothing.
if (New == get()) return Original;
Fn = New;
return wrap(S.Context, Original, 0);
}
private:
QualType wrap(ASTContext &C, QualType Old, unsigned I) {
if (I == Stack.size())
return C.getQualifiedType(Fn, Old.getQualifiers());
// Build up the inner type, applying the qualifiers from the old
// type to the new type.
SplitQualType SplitOld = Old.split();
// As a special case, tail-recurse if there are no qualifiers.
if (SplitOld.Quals.empty())
return wrap(C, SplitOld.Ty, I);
return C.getQualifiedType(wrap(C, SplitOld.Ty, I), SplitOld.Quals);
}
QualType wrap(ASTContext &C, const Type *Old, unsigned I) {
if (I == Stack.size()) return QualType(Fn, 0);
switch (static_cast<WrapKind>(Stack[I++])) {
case Desugar:
// This is the point at which we potentially lose source
// information.
return wrap(C, Old->getUnqualifiedDesugaredType(), I);
case Parens: {
QualType New = wrap(C, cast<ParenType>(Old)->getInnerType(), I);
return C.getParenType(New);
}
case Pointer: {
QualType New = wrap(C, cast<PointerType>(Old)->getPointeeType(), I);
return C.getPointerType(New);
}
case BlockPointer: {
QualType New = wrap(C, cast<BlockPointerType>(Old)->getPointeeType(),I);
return C.getBlockPointerType(New);
}
case MemberPointer: {
const MemberPointerType *OldMPT = cast<MemberPointerType>(Old);
QualType New = wrap(C, OldMPT->getPointeeType(), I);
return C.getMemberPointerType(New, OldMPT->getClass());
}
case Reference: {
const ReferenceType *OldRef = cast<ReferenceType>(Old);
QualType New = wrap(C, OldRef->getPointeeType(), I);
if (isa<LValueReferenceType>(OldRef))
return C.getLValueReferenceType(New, OldRef->isSpelledAsLValue());
else
return C.getRValueReferenceType(New);
}
}
llvm_unreachable("unknown wrapping kind");
}
};
}
static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
AttributeList &Attr,
QualType &Type) {

View File

@ -176,3 +176,10 @@ namespace test3 {
void bah() {}
void baz() { zed(bah); }
}
namespace test4 {
class foo {
template <typename T> static void bar(T v);
};
extern template void foo::bar(const void *);
}