forked from OSchip/llvm-project
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:
parent
8aac4f6d7b
commit
92045bc37c
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 *);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue