diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 6d40e00b21a7..e9977d42aa21 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -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(); - FunctionDecl *TmplFD = FunTmpl->getTemplatedDecl(); if (FD->isConstexpr()) { - CXXMethodDecl *OldMD = dyn_cast(TmplFD); + CXXMethodDecl *OldMD = + dyn_cast(FunTmpl->getTemplatedDecl()); if (OldMD && OldMD->isConst()) { + const FunctionProtoType *FPT = FT->castAs(); 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(); - 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 diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index b401db21a82c..56df8bab9ba7 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -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(); + CallingConv CC = FunctionTypeP->getCallConv(); + bool NoReturn = FunctionTypeP->getNoReturnAttr(); + const FunctionProtoType *ArgFunctionTypeP = + ArgFunctionType->getAs(); + if (ArgFunctionTypeP->getCallConv() != CC || + ArgFunctionTypeP->getNoReturnAttr() != NoReturn) { + FunctionType::ExtInfo EI = + ArgFunctionTypeP->getExtInfo().withCallingConv(CC); + EI = EI.withNoReturn(NoReturn); + ArgFunctionTypeP = cast( + Context.adjustFunctionType(ArgFunctionTypeP, EI)); + ArgFunctionType = QualType(ArgFunctionTypeP, 0); + } + } // Substitute any explicit template arguments. LocalInstantiationScope InstScope(*this); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 436b4b63ae0b..8e81b296cc1b 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -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 Stack; - - FunctionTypeUnwrapper(Sema &S, QualType T) : Original(T) { - while (true) { - const Type *Ty = T.getTypePtr(); - if (isa(Ty)) { - Fn = cast(Ty); - return; - } else if (isa(Ty)) { - T = cast(Ty)->getInnerType(); - Stack.push_back(Parens); - } else if (isa(Ty)) { - T = cast(Ty)->getPointeeType(); - Stack.push_back(Pointer); - } else if (isa(Ty)) { - T = cast(Ty)->getPointeeType(); - Stack.push_back(BlockPointer); - } else if (isa(Ty)) { - T = cast(Ty)->getPointeeType(); - Stack.push_back(MemberPointer); - } else if (isa(Ty)) { - T = cast(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(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(Old)->getInnerType(), I); - return C.getParenType(New); - } - - case Pointer: { - QualType New = wrap(C, cast(Old)->getPointeeType(), I); - return C.getPointerType(New); - } - - case BlockPointer: { - QualType New = wrap(C, cast(Old)->getPointeeType(),I); - return C.getBlockPointerType(New); - } - - case MemberPointer: { - const MemberPointerType *OldMPT = cast(Old); - QualType New = wrap(C, OldMPT->getPointeeType(), I); - return C.getMemberPointerType(New, OldMPT->getClass()); - } - - case Reference: { - const ReferenceType *OldRef = cast(Old); - QualType New = wrap(C, OldRef->getPointeeType(), I); - if (isa(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(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 Stack; + + FunctionTypeUnwrapper(Sema &S, QualType T) : Original(T) { + while (true) { + const Type *Ty = T.getTypePtr(); + if (isa(Ty)) { + Fn = cast(Ty); + return; + } else if (isa(Ty)) { + T = cast(Ty)->getInnerType(); + Stack.push_back(Parens); + } else if (isa(Ty)) { + T = cast(Ty)->getPointeeType(); + Stack.push_back(Pointer); + } else if (isa(Ty)) { + T = cast(Ty)->getPointeeType(); + Stack.push_back(BlockPointer); + } else if (isa(Ty)) { + T = cast(Ty)->getPointeeType(); + Stack.push_back(MemberPointer); + } else if (isa(Ty)) { + T = cast(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(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(Old)->getInnerType(), I); + return C.getParenType(New); + } + + case Pointer: { + QualType New = wrap(C, cast(Old)->getPointeeType(), I); + return C.getPointerType(New); + } + + case BlockPointer: { + QualType New = wrap(C, cast(Old)->getPointeeType(),I); + return C.getBlockPointerType(New); + } + + case MemberPointer: { + const MemberPointerType *OldMPT = cast(Old); + QualType New = wrap(C, OldMPT->getPointeeType(), I); + return C.getMemberPointerType(New, OldMPT->getClass()); + } + + case Reference: { + const ReferenceType *OldRef = cast(Old); + QualType New = wrap(C, OldRef->getPointeeType(), I); + if (isa(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) { diff --git a/clang/test/SemaCXX/decl-microsoft-call-conv.cpp b/clang/test/SemaCXX/decl-microsoft-call-conv.cpp index e47a5c2a5cfa..a1a6d0b28951 100644 --- a/clang/test/SemaCXX/decl-microsoft-call-conv.cpp +++ b/clang/test/SemaCXX/decl-microsoft-call-conv.cpp @@ -176,3 +176,10 @@ namespace test3 { void bah() {} void baz() { zed(bah); } } + +namespace test4 { + class foo { + template static void bar(T v); + }; + extern template void foo::bar(const void *); +}