diff options
author | John McCall <rjmccall@apple.com> | 2010-12-19 02:44:49 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-12-19 02:44:49 +0000 |
commit | e6a365d772a6b455f1e23ac9ae5f40d65a55a18c (patch) | |
tree | 5e0509d9e019e04d66281b725054c5fe3e136bc4 /lib/Sema/SemaType.cpp | |
parent | f45fbad13ee1f143a2cb6e806fefe22b48f68940 (diff) |
Motions towards simplifying how we deal with attribute-qualified function types.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122162 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaType.cpp')
-rw-r--r-- | lib/Sema/SemaType.cpp | 175 |
1 files changed, 148 insertions, 27 deletions
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 2eb2c0b7cf..09b187b0d0 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1891,9 +1891,142 @@ static void HandleObjCGCTypeAttribute(QualType &Type, Type = S.Context.getObjCGCQualType(Type, GCAttr); } +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; + llvm::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.second.empty()) + return wrap(C, SplitOld.first, I); + return C.getQualifiedType(wrap(C, SplitOld.first, I), SplitOld.second); + } + + 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"); + return QualType(); + } + }; +} + /// Process an individual function attribute. Returns true if the /// attribute does not make sense to apply to this type. -bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { +static bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { + FunctionTypeUnwrapper Unwrapped(S, Type); + if (Attr.getKind() == AttributeList::AT_noreturn) { // Complain immediately if the arg count is wrong. if (Attr.getNumArgs() != 0) { @@ -1902,15 +2035,13 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { return false; } - // Delay if this is not a function or pointer to block. - if (!Type->isFunctionPointerType() - && !Type->isBlockPointerType() - && !Type->isFunctionType() - && !Type->isMemberFunctionPointerType()) + // Delay if this is not a function type. + if (!Unwrapped.isFunctionType()) return true; - + // Otherwise we can process right away. - Type = S.Context.getNoReturnType(Type); + FunctionType::ExtInfo EI = Unwrapped.get()->getExtInfo().withNoReturn(true); + Type = Unwrapped.wrap(S, S.Context.adjustFunctionType(Unwrapped.get(), EI)); return false; } @@ -1920,11 +2051,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { return false; } - // Delay if this is not a function or pointer to block. - if (!Type->isFunctionPointerType() - && !Type->isBlockPointerType() - && !Type->isFunctionType() - && !Type->isMemberFunctionPointerType()) + // Delay if this is not a function type. + if (!Unwrapped.isFunctionType()) return true; // Otherwise we can process right away. @@ -1950,7 +2078,9 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { return false; } - Type = S.Context.getRegParmType(Type, NumParams.getZExtValue()); + FunctionType::ExtInfo EI = + Unwrapped.get()->getExtInfo().withRegParm(NumParams.getZExtValue()); + Type = Unwrapped.wrap(S, S.Context.adjustFunctionType(Unwrapped.get(), EI)); return false; } @@ -1961,19 +2091,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { return false; } - QualType T = Type; - if (const PointerType *PT = Type->getAs<PointerType>()) - T = PT->getPointeeType(); - else if (const BlockPointerType *BPT = Type->getAs<BlockPointerType>()) - T = BPT->getPointeeType(); - else if (const MemberPointerType *MPT = Type->getAs<MemberPointerType>()) - T = MPT->getPointeeType(); - else if (const ReferenceType *RT = Type->getAs<ReferenceType>()) - T = RT->getPointeeType(); - const FunctionType *Fn = T->getAs<FunctionType>(); - // Delay if the type didn't work out to a function. - if (!Fn) return true; + if (!Unwrapped.isFunctionType()) return true; // TODO: diagnose uses of these conventions on the wrong target. CallingConv CC; @@ -1986,6 +2105,7 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { default: llvm_unreachable("unexpected attribute kind"); return false; } + const FunctionType *Fn = Unwrapped.get(); CallingConv CCOld = Fn->getCallConv(); if (S.Context.getCanonicalCallConv(CC) == S.Context.getCanonicalCallConv(CCOld)) { @@ -2020,7 +2140,8 @@ bool ProcessFnAttr(Sema &S, QualType &Type, const AttributeList &Attr) { } } - Type = S.Context.getCallConvType(Type, CC); + FunctionType::ExtInfo EI = Unwrapped.get()->getExtInfo().withCallingConv(CC); + Type = Unwrapped.wrap(S, S.Context.adjustFunctionType(Unwrapped.get(), EI)); return false; } |