mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-12 02:47:10 +00:00
[Attribute/Diagnostics] Print macro if definition is an attribute declaration
If an address_space attribute is defined in a macro, print the macro instead when diagnosing a warning or error for incompatible pointers with different address_spaces. We allow this for all attributes (not just address_space), and for multiple attributes declared in the same macro. Differential Revision: https://reviews.llvm.org/D51329 llvm-svn: 359826
This commit is contained in:
parent
206bc17ea0
commit
fc40cbd9d8
@ -1441,6 +1441,9 @@ public:
|
||||
|
||||
QualType getParenType(QualType NamedType) const;
|
||||
|
||||
QualType getMacroQualifiedType(QualType UnderlyingTy,
|
||||
const IdentifierInfo *MacroII) const;
|
||||
|
||||
QualType getElaboratedType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier *NNS, QualType NamedType,
|
||||
TagDecl *OwnedTagDecl = nullptr) const;
|
||||
|
@ -1065,6 +1065,9 @@ DEF_TRAVERSE_TYPE(AttributedType,
|
||||
|
||||
DEF_TRAVERSE_TYPE(ParenType, { TRY_TO(TraverseType(T->getInnerType())); })
|
||||
|
||||
DEF_TRAVERSE_TYPE(MacroQualifiedType,
|
||||
{ TRY_TO(TraverseType(T->getUnderlyingType())); })
|
||||
|
||||
DEF_TRAVERSE_TYPE(ElaboratedType, {
|
||||
if (T->getQualifier()) {
|
||||
TRY_TO(TraverseNestedNameSpecifier(T->getQualifier()));
|
||||
@ -1308,6 +1311,9 @@ DEF_TRAVERSE_TYPELOC(InjectedClassNameType, {})
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(ParenType, { TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(MacroQualifiedType,
|
||||
{ TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
|
||||
|
||||
DEF_TRAVERSE_TYPELOC(AttributedType,
|
||||
{ TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); })
|
||||
|
||||
|
@ -4184,6 +4184,41 @@ public:
|
||||
static bool classof(const Type *T) { return T->getTypeClass() == Typedef; }
|
||||
};
|
||||
|
||||
/// Sugar type that represents a type that was qualified by a qualifier written
|
||||
/// as a macro invocation.
|
||||
class MacroQualifiedType : public Type {
|
||||
friend class ASTContext; // ASTContext creates these.
|
||||
|
||||
QualType UnderlyingTy;
|
||||
const IdentifierInfo *MacroII;
|
||||
|
||||
MacroQualifiedType(QualType UnderlyingTy, QualType CanonTy,
|
||||
const IdentifierInfo *MacroII)
|
||||
: Type(MacroQualified, CanonTy, UnderlyingTy->isDependentType(),
|
||||
UnderlyingTy->isInstantiationDependentType(),
|
||||
UnderlyingTy->isVariablyModifiedType(),
|
||||
UnderlyingTy->containsUnexpandedParameterPack()),
|
||||
UnderlyingTy(UnderlyingTy), MacroII(MacroII) {
|
||||
assert(isa<AttributedType>(UnderlyingTy) &&
|
||||
"Expected a macro qualified type to only wrap attributed types.");
|
||||
}
|
||||
|
||||
public:
|
||||
const IdentifierInfo *getMacroIdentifier() const { return MacroII; }
|
||||
QualType getUnderlyingType() const { return UnderlyingTy; }
|
||||
|
||||
/// Return this attributed type's modified type with no qualifiers attached to
|
||||
/// it.
|
||||
QualType getModifiedType() const;
|
||||
|
||||
bool isSugared() const { return true; }
|
||||
QualType desugar() const;
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == MacroQualified;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a `typeof` (or __typeof__) expression (a GCC extension).
|
||||
class TypeOfExprType : public Type {
|
||||
Expr *TOExpr;
|
||||
@ -6805,6 +6840,8 @@ template <typename T> const T *Type::getAsAdjusted() const {
|
||||
Ty = P->desugar().getTypePtr();
|
||||
else if (const auto *A = dyn_cast<AdjustedType>(Ty))
|
||||
Ty = A->desugar().getTypePtr();
|
||||
else if (const auto *M = dyn_cast<MacroQualifiedType>(Ty))
|
||||
Ty = M->desugar().getTypePtr();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
@ -173,6 +173,9 @@ public:
|
||||
|
||||
TypeLoc IgnoreParens() const;
|
||||
|
||||
/// Strips MacroDefinitionTypeLocs from a type location.
|
||||
TypeLoc IgnoreMacroDefinitions() const;
|
||||
|
||||
/// Find a type with the location of an explicit type qualifier.
|
||||
///
|
||||
/// The result, if non-null, will be one of:
|
||||
@ -1080,6 +1083,39 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct MacroQualifiedLocInfo {
|
||||
SourceLocation ExpansionLoc;
|
||||
};
|
||||
|
||||
class MacroQualifiedTypeLoc
|
||||
: public ConcreteTypeLoc<UnqualTypeLoc, MacroQualifiedTypeLoc,
|
||||
MacroQualifiedType, MacroQualifiedLocInfo> {
|
||||
public:
|
||||
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
|
||||
setExpansionLoc(Loc);
|
||||
}
|
||||
|
||||
TypeLoc getInnerLoc() const { return getInnerTypeLoc(); }
|
||||
|
||||
const IdentifierInfo *getMacroIdentifier() const {
|
||||
return getTypePtr()->getMacroIdentifier();
|
||||
}
|
||||
|
||||
SourceLocation getExpansionLoc() const {
|
||||
return this->getLocalData()->ExpansionLoc;
|
||||
}
|
||||
|
||||
void setExpansionLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->ExpansionLoc = Loc;
|
||||
}
|
||||
|
||||
QualType getInnerType() const { return getTypePtr()->getUnderlyingType(); }
|
||||
|
||||
SourceRange getLocalSourceRange() const {
|
||||
return getInnerLoc().getLocalSourceRange();
|
||||
}
|
||||
};
|
||||
|
||||
struct ParenLocInfo {
|
||||
SourceLocation LParenLoc;
|
||||
SourceLocation RParenLoc;
|
||||
@ -2289,6 +2325,8 @@ inline T TypeLoc::getAsAdjusted() const {
|
||||
Cur = ETL.getNamedTypeLoc();
|
||||
else if (auto ATL = Cur.getAs<AdjustedTypeLoc>())
|
||||
Cur = ATL.getOriginalLoc();
|
||||
else if (auto MQL = Cur.getAs<MacroQualifiedTypeLoc>())
|
||||
Cur = MQL.getInnerLoc();
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ TYPE(FunctionNoProto, FunctionType)
|
||||
DEPENDENT_TYPE(UnresolvedUsing, Type)
|
||||
NON_CANONICAL_TYPE(Paren, Type)
|
||||
NON_CANONICAL_TYPE(Typedef, Type)
|
||||
NON_CANONICAL_TYPE(MacroQualified, Type)
|
||||
NON_CANONICAL_TYPE(Adjusted, Type)
|
||||
NON_CANONICAL_TYPE(Decayed, AdjustedType)
|
||||
NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type)
|
||||
|
@ -1152,6 +1152,7 @@ private:
|
||||
Parser *Self;
|
||||
CachedTokens Toks;
|
||||
IdentifierInfo &AttrName;
|
||||
IdentifierInfo *MacroII = nullptr;
|
||||
SourceLocation AttrNameLoc;
|
||||
SmallVector<Decl*, 2> Decls;
|
||||
|
||||
|
@ -167,6 +167,8 @@ public:
|
||||
private:
|
||||
IdentifierInfo *AttrName;
|
||||
IdentifierInfo *ScopeName;
|
||||
IdentifierInfo *MacroII = nullptr;
|
||||
SourceLocation MacroExpansionLoc;
|
||||
SourceRange AttrRange;
|
||||
SourceLocation ScopeLoc;
|
||||
SourceLocation EllipsisLoc;
|
||||
@ -547,6 +549,27 @@ public:
|
||||
return getPropertyDataBuffer().SetterId;
|
||||
}
|
||||
|
||||
/// Set the macro identifier info object that this parsed attribute was
|
||||
/// declared in if it was declared in a macro. Also set the expansion location
|
||||
/// of the macro.
|
||||
void setMacroIdentifier(IdentifierInfo *MacroName, SourceLocation Loc) {
|
||||
MacroII = MacroName;
|
||||
MacroExpansionLoc = Loc;
|
||||
}
|
||||
|
||||
/// Returns true if this attribute was declared in a macro.
|
||||
bool hasMacroIdentifier() const { return MacroII != nullptr; }
|
||||
|
||||
/// Return the macro identifier if this attribute was declared in a macro.
|
||||
/// nullptr is returned if it was not declared in a macro.
|
||||
IdentifierInfo *getMacroIdentifier() const { return MacroII; }
|
||||
|
||||
SourceLocation getMacroExpansionLoc() const {
|
||||
assert(hasMacroIdentifier() && "Can only get the macro expansion location "
|
||||
"if this attribute has a macro identifier.");
|
||||
return MacroExpansionLoc;
|
||||
}
|
||||
|
||||
/// Get an index into the attribute spelling list
|
||||
/// defined in Attr.td. This index is used by an attribute
|
||||
/// to pretty print itself.
|
||||
|
@ -3516,7 +3516,7 @@ public:
|
||||
// Check if there is an explicit attribute, but only look through parens.
|
||||
// The intent is to look for an attribute on the current declarator, but not
|
||||
// one that came from a typedef.
|
||||
bool hasExplicitCallingConv(QualType &T);
|
||||
bool hasExplicitCallingConv(QualType T);
|
||||
|
||||
/// Get the outermost AttributedType node that sets a calling convention.
|
||||
/// Valid types should not have multiple attributes with different CCs.
|
||||
|
@ -1173,7 +1173,10 @@ namespace serialization {
|
||||
TYPE_DEPENDENT_ADDRESS_SPACE = 47,
|
||||
|
||||
/// A dependentSizedVectorType record.
|
||||
TYPE_DEPENDENT_SIZED_VECTOR = 48
|
||||
TYPE_DEPENDENT_SIZED_VECTOR = 48,
|
||||
|
||||
/// A type defined in a macro.
|
||||
TYPE_MACRO_QUALIFIED = 49
|
||||
};
|
||||
|
||||
/// The type IDs for special types constructed by semantic
|
||||
|
@ -68,6 +68,9 @@ public:
|
||||
if (handleAttr(Attr, D))
|
||||
break;
|
||||
TL = Attr.getModifiedLoc();
|
||||
} else if (MacroQualifiedTypeLoc MDTL =
|
||||
TL.getAs<MacroQualifiedTypeLoc>()) {
|
||||
TL = MDTL.getInnerLoc();
|
||||
} else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
|
||||
TL = Arr.getElementLoc();
|
||||
} else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
|
||||
|
@ -2047,6 +2047,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
|
||||
case Type::Paren:
|
||||
return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr());
|
||||
|
||||
case Type::MacroQualified:
|
||||
return getTypeInfo(
|
||||
cast<MacroQualifiedType>(T)->getUnderlyingType().getTypePtr());
|
||||
|
||||
case Type::ObjCTypeParam:
|
||||
return getTypeInfo(cast<ObjCTypeParamType>(T)->desugar().getTypePtr());
|
||||
|
||||
@ -3929,7 +3933,7 @@ QualType ASTContext::getAttributedType(attr::Kind attrKind,
|
||||
|
||||
QualType canon = getCanonicalType(equivalentType);
|
||||
type = new (*this, TypeAlignment)
|
||||
AttributedType(canon, attrKind, modifiedType, equivalentType);
|
||||
AttributedType(canon, attrKind, modifiedType, equivalentType);
|
||||
|
||||
Types.push_back(type);
|
||||
AttributedTypes.InsertNode(type, insertPos);
|
||||
@ -4210,6 +4214,19 @@ ASTContext::getParenType(QualType InnerType) const {
|
||||
return QualType(T, 0);
|
||||
}
|
||||
|
||||
QualType
|
||||
ASTContext::getMacroQualifiedType(QualType UnderlyingTy,
|
||||
const IdentifierInfo *MacroII) const {
|
||||
QualType Canon = UnderlyingTy;
|
||||
if (!Canon.isCanonical())
|
||||
Canon = getCanonicalType(UnderlyingTy);
|
||||
|
||||
auto *newType = new (*this, TypeAlignment)
|
||||
MacroQualifiedType(UnderlyingTy, Canon, MacroII);
|
||||
Types.push_back(newType);
|
||||
return QualType(newType, 0);
|
||||
}
|
||||
|
||||
QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
|
||||
NestedNameSpecifier *NNS,
|
||||
const IdentifierInfo *Name,
|
||||
|
@ -41,6 +41,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
|
||||
QT = PT->desugar();
|
||||
continue;
|
||||
}
|
||||
// ... or a macro defined type ...
|
||||
if (const MacroQualifiedType *MDT = dyn_cast<MacroQualifiedType>(Ty)) {
|
||||
QT = MDT->desugar();
|
||||
continue;
|
||||
}
|
||||
// ...or a substituted template type parameter ...
|
||||
if (const SubstTemplateTypeParmType *ST =
|
||||
dyn_cast<SubstTemplateTypeParmType>(Ty)) {
|
||||
|
@ -595,6 +595,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||
return false;
|
||||
break;
|
||||
|
||||
case Type::MacroQualified:
|
||||
if (!IsStructurallyEquivalent(
|
||||
Context, cast<MacroQualifiedType>(T1)->getUnderlyingType(),
|
||||
cast<MacroQualifiedType>(T2)->getUnderlyingType()))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case Type::Typedef:
|
||||
if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
|
||||
cast<TypedefType>(T2)->getDecl()))
|
||||
|
@ -1941,6 +1941,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
|
||||
case Type::ObjCTypeParam:
|
||||
case Type::Atomic:
|
||||
case Type::Pipe:
|
||||
case Type::MacroQualified:
|
||||
llvm_unreachable("type is illegal as a nested name specifier");
|
||||
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
|
@ -973,6 +973,7 @@ public:
|
||||
|
||||
SUGARED_TYPE_CLASS(Typedef)
|
||||
SUGARED_TYPE_CLASS(ObjCTypeParam)
|
||||
SUGARED_TYPE_CLASS(MacroQualified)
|
||||
|
||||
QualType VisitAdjustedType(const AdjustedType *T) {
|
||||
QualType originalType = recurse(T->getOriginalType());
|
||||
@ -1735,6 +1736,10 @@ namespace {
|
||||
return Visit(T->getModifiedType());
|
||||
}
|
||||
|
||||
Type *VisitMacroQualifiedType(const MacroQualifiedType *T) {
|
||||
return Visit(T->getUnderlyingType());
|
||||
}
|
||||
|
||||
Type *VisitAdjustedType(const AdjustedType *T) {
|
||||
return Visit(T->getOriginalType());
|
||||
}
|
||||
@ -3160,6 +3165,20 @@ QualType TypedefType::desugar() const {
|
||||
return getDecl()->getUnderlyingType();
|
||||
}
|
||||
|
||||
QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); }
|
||||
|
||||
QualType MacroQualifiedType::getModifiedType() const {
|
||||
// Step over MacroQualifiedTypes from the same macro to find the type
|
||||
// ultimately qualified by the macro qualifier.
|
||||
QualType Inner = cast<AttributedType>(getUnderlyingType())->getModifiedType();
|
||||
while (auto *InnerMQT = dyn_cast<MacroQualifiedType>(Inner)) {
|
||||
if (InnerMQT->getMacroIdentifier() != getMacroIdentifier())
|
||||
break;
|
||||
Inner = InnerMQT->getModifiedType();
|
||||
}
|
||||
return Inner;
|
||||
}
|
||||
|
||||
TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
|
||||
: Type(TypeOfExpr, can, E->isTypeDependent(),
|
||||
E->isInstantiationDependent(),
|
||||
|
@ -259,6 +259,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
|
||||
case Type::Paren:
|
||||
case Type::PackExpansion:
|
||||
case Type::SubstTemplateTypeParm:
|
||||
case Type::MacroQualified:
|
||||
CanPrefixQualifiers = false;
|
||||
break;
|
||||
|
||||
@ -963,6 +964,21 @@ void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) {
|
||||
printTypeSpec(T->getDecl(), OS);
|
||||
}
|
||||
|
||||
void TypePrinter::printMacroQualifiedBefore(const MacroQualifiedType *T,
|
||||
raw_ostream &OS) {
|
||||
StringRef MacroName = T->getMacroIdentifier()->getName();
|
||||
OS << MacroName << " ";
|
||||
|
||||
// Since this type is meant to print the macro instead of the whole attribute,
|
||||
// we trim any attributes and go directly to the original modified type.
|
||||
printBefore(T->getModifiedType(), OS);
|
||||
}
|
||||
|
||||
void TypePrinter::printMacroQualifiedAfter(const MacroQualifiedType *T,
|
||||
raw_ostream &OS) {
|
||||
printAfter(T->getModifiedType(), OS);
|
||||
}
|
||||
|
||||
void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) {}
|
||||
|
||||
void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T,
|
||||
|
@ -2844,6 +2844,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
|
||||
case Type::Paren:
|
||||
T = cast<ParenType>(T)->getInnerType();
|
||||
break;
|
||||
case Type::MacroQualified:
|
||||
T = cast<MacroQualifiedType>(T)->getUnderlyingType();
|
||||
break;
|
||||
case Type::SubstTemplateTypeParm:
|
||||
T = cast<SubstTemplateTypeParmType>(T)->getReplacementType();
|
||||
break;
|
||||
@ -3023,6 +3026,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) {
|
||||
case Type::DeducedTemplateSpecialization:
|
||||
case Type::Elaborated:
|
||||
case Type::Paren:
|
||||
case Type::MacroQualified:
|
||||
case Type::SubstTemplateTypeParm:
|
||||
case Type::TypeOfExpr:
|
||||
case Type::TypeOf:
|
||||
|
@ -2149,6 +2149,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) {
|
||||
case Type::Attributed:
|
||||
case Type::SubstTemplateTypeParm:
|
||||
case Type::PackExpansion:
|
||||
case Type::MacroQualified:
|
||||
// Keep walking after single level desugaring.
|
||||
type = type.getSingleStepDesugaredType(getContext());
|
||||
break;
|
||||
|
@ -85,6 +85,23 @@ static bool isAttributeLateParsed(const IdentifierInfo &II) {
|
||||
#undef CLANG_ATTR_LATE_PARSED_LIST
|
||||
}
|
||||
|
||||
/// Check if the a start and end source location expand to the same macro.
|
||||
bool FindLocsWithCommonFileID(Preprocessor &PP, SourceLocation StartLoc,
|
||||
SourceLocation EndLoc) {
|
||||
if (!StartLoc.isMacroID() || !EndLoc.isMacroID())
|
||||
return false;
|
||||
|
||||
SourceManager &SM = PP.getSourceManager();
|
||||
if (SM.getFileID(StartLoc) != SM.getFileID(EndLoc))
|
||||
return false;
|
||||
|
||||
bool AttrStartIsInMacro =
|
||||
Lexer::isAtStartOfMacroExpansion(StartLoc, SM, PP.getLangOpts());
|
||||
bool AttrEndIsInMacro =
|
||||
Lexer::isAtEndOfMacroExpansion(EndLoc, SM, PP.getLangOpts());
|
||||
return AttrStartIsInMacro && AttrEndIsInMacro;
|
||||
}
|
||||
|
||||
/// ParseGNUAttributes - Parse a non-empty attributes list.
|
||||
///
|
||||
/// [GNU] attributes:
|
||||
@ -133,7 +150,10 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
|
||||
assert(Tok.is(tok::kw___attribute) && "Not a GNU attribute list!");
|
||||
|
||||
while (Tok.is(tok::kw___attribute)) {
|
||||
ConsumeToken();
|
||||
SourceLocation AttrTokLoc = ConsumeToken();
|
||||
unsigned OldNumAttrs = attrs.size();
|
||||
unsigned OldNumLateAttrs = LateAttrs ? LateAttrs->size() : 0;
|
||||
|
||||
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
|
||||
"attribute")) {
|
||||
SkipUntil(tok::r_paren, StopAtSemi); // skip until ) or ;
|
||||
@ -201,6 +221,24 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs,
|
||||
SkipUntil(tok::r_paren, StopAtSemi);
|
||||
if (endLoc)
|
||||
*endLoc = Loc;
|
||||
|
||||
// If this was declared in a macro, attach the macro IdentifierInfo to the
|
||||
// parsed attribute.
|
||||
if (FindLocsWithCommonFileID(PP, AttrTokLoc, Loc)) {
|
||||
auto &SM = PP.getSourceManager();
|
||||
CharSourceRange ExpansionRange = SM.getExpansionRange(AttrTokLoc);
|
||||
StringRef FoundName =
|
||||
Lexer::getSourceText(ExpansionRange, SM, PP.getLangOpts());
|
||||
IdentifierInfo *MacroII = PP.getIdentifierInfo(FoundName);
|
||||
|
||||
for (unsigned i = OldNumAttrs; i < attrs.size(); ++i)
|
||||
attrs[i].setMacroIdentifier(MacroII, ExpansionRange.getBegin());
|
||||
|
||||
if (LateAttrs) {
|
||||
for (unsigned i = OldNumLateAttrs; i < LateAttrs->size(); ++i)
|
||||
(*LateAttrs)[i]->MacroII = MacroII;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4096,6 +4096,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T,
|
||||
case Type::Attributed:
|
||||
case Type::SubstTemplateTypeParm:
|
||||
case Type::PackExpansion:
|
||||
case Type::MacroQualified:
|
||||
// Keep walking after single level desugaring.
|
||||
T = T.getSingleStepDesugaredType(Context);
|
||||
break;
|
||||
@ -13695,8 +13696,8 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
|
||||
// Look for an explicit signature in that function type.
|
||||
FunctionProtoTypeLoc ExplicitSignature;
|
||||
|
||||
if ((ExplicitSignature =
|
||||
Sig->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>())) {
|
||||
if ((ExplicitSignature = Sig->getTypeLoc()
|
||||
.getAsAdjusted<FunctionProtoTypeLoc>())) {
|
||||
|
||||
// Check whether that explicit signature was synthesized by
|
||||
// GetTypeForDeclarator. If so, don't save that as part of the
|
||||
|
@ -3385,10 +3385,10 @@ bool LocalTypedefNameReferencer::VisitRecordType(const RecordType *RT) {
|
||||
}
|
||||
|
||||
TypeLoc Sema::getReturnTypeLoc(FunctionDecl *FD) const {
|
||||
TypeLoc TL = FD->getTypeSourceInfo()->getTypeLoc().IgnoreParens();
|
||||
while (auto ATL = TL.getAs<AttributedTypeLoc>())
|
||||
TL = ATL.getModifiedLoc().IgnoreParens();
|
||||
return TL.castAs<FunctionProtoTypeLoc>().getReturnLoc();
|
||||
return FD->getTypeSourceInfo()
|
||||
->getTypeLoc()
|
||||
.getAsAdjusted<FunctionProtoTypeLoc>()
|
||||
.getReturnLoc();
|
||||
}
|
||||
|
||||
/// Deduce the return type for a function from a returned expression, per
|
||||
|
@ -5643,6 +5643,9 @@ namespace {
|
||||
assert(Chunk.Kind == DeclaratorChunk::Pipe);
|
||||
TL.setKWLoc(Chunk.Loc);
|
||||
}
|
||||
void VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) {
|
||||
TL.setExpansionLoc(Chunk.Loc);
|
||||
}
|
||||
|
||||
void VisitTypeLoc(TypeLoc TL) {
|
||||
llvm_unreachable("unsupported TypeLoc kind in declarator!");
|
||||
@ -5721,6 +5724,9 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State,
|
||||
CurrTL = ATL.getValueLoc().getUnqualifiedLoc();
|
||||
}
|
||||
|
||||
while (MacroQualifiedTypeLoc TL = CurrTL.getAs<MacroQualifiedTypeLoc>())
|
||||
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
|
||||
|
||||
while (AttributedTypeLoc TL = CurrTL.getAs<AttributedTypeLoc>()) {
|
||||
fillAttributedTypeLoc(TL, State);
|
||||
CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc();
|
||||
@ -6981,12 +6987,16 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sema::hasExplicitCallingConv(QualType &T) {
|
||||
QualType R = T.IgnoreParens();
|
||||
while (const AttributedType *AT = dyn_cast<AttributedType>(R)) {
|
||||
bool Sema::hasExplicitCallingConv(QualType T) {
|
||||
const AttributedType *AT;
|
||||
|
||||
// Stop if we'd be stripping off a typedef sugar node to reach the
|
||||
// AttributedType.
|
||||
while ((AT = T->getAs<AttributedType>()) &&
|
||||
AT->getAs<TypedefType>() == T->getAs<TypedefType>()) {
|
||||
if (AT->isCallingConv())
|
||||
return true;
|
||||
R = AT->getModifiedType().IgnoreParens();
|
||||
T = AT->getModifiedType();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -7571,6 +7581,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
|
||||
distributeFunctionTypeAttr(state, attr, type);
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle attributes that are defined in a macro. We do not want this to be
|
||||
// applied to ObjC builtin attributes.
|
||||
if (isa<AttributedType>(type) && attr.hasMacroIdentifier() &&
|
||||
!type.getQualifiers().hasObjCLifetime() &&
|
||||
!type.getQualifiers().hasObjCGCAttr()) {
|
||||
const IdentifierInfo *MacroII = attr.getMacroIdentifier();
|
||||
type = state.getSema().Context.getMacroQualifiedType(type, MacroII);
|
||||
}
|
||||
}
|
||||
|
||||
if (!state.getSema().getLangOpts().OpenCL ||
|
||||
|
@ -883,6 +883,12 @@ public:
|
||||
return SemaRef.Context.getTypeDeclType(Typedef);
|
||||
}
|
||||
|
||||
/// Build a new MacroDefined type.
|
||||
QualType RebuildMacroQualifiedType(QualType T,
|
||||
const IdentifierInfo *MacroII) {
|
||||
return SemaRef.Context.getMacroQualifiedType(T, MacroII);
|
||||
}
|
||||
|
||||
/// Build a new class/struct/union type.
|
||||
QualType RebuildRecordType(RecordDecl *Record) {
|
||||
return SemaRef.Context.getTypeDeclType(Record);
|
||||
@ -6193,6 +6199,27 @@ TreeTransform<Derived>::TransformParenType(TypeLocBuilder &TLB,
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
QualType
|
||||
TreeTransform<Derived>::TransformMacroQualifiedType(TypeLocBuilder &TLB,
|
||||
MacroQualifiedTypeLoc TL) {
|
||||
QualType Inner = getDerived().TransformType(TLB, TL.getInnerLoc());
|
||||
if (Inner.isNull())
|
||||
return QualType();
|
||||
|
||||
QualType Result = TL.getType();
|
||||
if (getDerived().AlwaysRebuild() || Inner != TL.getInnerLoc().getType()) {
|
||||
Result =
|
||||
getDerived().RebuildMacroQualifiedType(Inner, TL.getMacroIdentifier());
|
||||
if (Result.isNull())
|
||||
return QualType();
|
||||
}
|
||||
|
||||
MacroQualifiedTypeLoc NewTL = TLB.push<MacroQualifiedTypeLoc>(Result);
|
||||
NewTL.setExpansionLoc(TL.getExpansionLoc());
|
||||
return Result;
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
QualType TreeTransform<Derived>::TransformDependentNameType(
|
||||
TypeLocBuilder &TLB, DependentNameTypeLoc TL) {
|
||||
|
@ -6200,6 +6200,16 @@ QualType ASTReader::readTypeRecord(unsigned Index) {
|
||||
return Context.getParenType(InnerType);
|
||||
}
|
||||
|
||||
case TYPE_MACRO_QUALIFIED: {
|
||||
if (Record.size() != 2) {
|
||||
Error("incorrect encoding of macro defined type");
|
||||
return QualType();
|
||||
}
|
||||
QualType UnderlyingTy = readType(*Loc.F, Record, Idx);
|
||||
IdentifierInfo *MacroII = GetIdentifierInfo(*Loc.F, Record, Idx);
|
||||
return Context.getMacroQualifiedType(UnderlyingTy, MacroII);
|
||||
}
|
||||
|
||||
case TYPE_PACK_EXPANSION: {
|
||||
if (Record.size() != 2) {
|
||||
Error("incorrect encoding of pack expansion type");
|
||||
@ -6521,6 +6531,10 @@ void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void TypeLocReader::VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) {
|
||||
TL.setExpansionLoc(ReadSourceLocation());
|
||||
}
|
||||
|
||||
void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) {
|
||||
TL.setCaretLoc(ReadSourceLocation());
|
||||
}
|
||||
|
@ -516,6 +516,12 @@ void ASTTypeWriter::VisitParenType(const ParenType *T) {
|
||||
Code = TYPE_PAREN;
|
||||
}
|
||||
|
||||
void ASTTypeWriter::VisitMacroQualifiedType(const MacroQualifiedType *T) {
|
||||
Record.AddTypeRef(T->getUnderlyingType());
|
||||
Record.AddIdentifierRef(T->getMacroIdentifier());
|
||||
Code = TYPE_MACRO_QUALIFIED;
|
||||
}
|
||||
|
||||
void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) {
|
||||
Record.push_back(T->getKeyword());
|
||||
Record.AddNestedNameSpecifier(T->getQualifier());
|
||||
@ -802,6 +808,10 @@ void TypeLocWriter::VisitParenTypeLoc(ParenTypeLoc TL) {
|
||||
Record.AddSourceLocation(TL.getRParenLoc());
|
||||
}
|
||||
|
||||
void TypeLocWriter::VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) {
|
||||
Record.AddSourceLocation(TL.getExpansionLoc());
|
||||
}
|
||||
|
||||
void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) {
|
||||
Record.AddSourceLocation(TL.getElaboratedKeywordLoc());
|
||||
Record.AddNestedNameSpecifierLoc(TL.getQualifierLoc());
|
||||
@ -1219,6 +1229,7 @@ void ASTWriter::WriteBlockInfoBlock() {
|
||||
RECORD(TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION);
|
||||
RECORD(TYPE_DEPENDENT_SIZED_ARRAY);
|
||||
RECORD(TYPE_PAREN);
|
||||
RECORD(TYPE_MACRO_QUALIFIED);
|
||||
RECORD(TYPE_PACK_EXPANSION);
|
||||
RECORD(TYPE_ATTRIBUTED);
|
||||
RECORD(TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK);
|
||||
|
15
clang/test/Frontend/macro_defined_type.cpp
Normal file
15
clang/test/Frontend/macro_defined_type.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
#define NODEREF __attribute__((noderef))
|
||||
|
||||
void Func() {
|
||||
int NODEREF i; // expected-warning{{'noderef' can only be used on an array or pointer type}}
|
||||
int NODEREF *i_ptr;
|
||||
|
||||
// There should be no difference whether a macro defined type is used or not.
|
||||
auto __attribute__((noderef)) *auto_i_ptr = i_ptr;
|
||||
auto __attribute__((noderef)) auto_i = i; // expected-warning{{'noderef' can only be used on an array or pointer type}}
|
||||
|
||||
auto NODEREF *auto_i_ptr2 = i_ptr;
|
||||
auto NODEREF auto_i2 = i; // expected-warning{{'noderef' can only be used on an array or pointer type}}
|
||||
}
|
67
clang/test/Sema/address_space_print_macro.c
Normal file
67
clang/test/Sema/address_space_print_macro.c
Normal file
@ -0,0 +1,67 @@
|
||||
// RUN: %clang_cc1 %s -fsyntax-only -verify
|
||||
|
||||
#define AS1 __attribute__((address_space(1)))
|
||||
#define AS2 __attribute__((address_space(2), annotate("foo")))
|
||||
#define AS_ND __attribute__((address_space(2), noderef))
|
||||
|
||||
#define AS(i) address_space(i)
|
||||
#define AS3 __attribute__((AS(3)))
|
||||
#define AS5 __attribute__((address_space(5))) char
|
||||
|
||||
void normal_case() {
|
||||
int *p = 0;
|
||||
__attribute__((address_space(1))) int *q = p; // expected-error{{initializing '__attribute__((address_space(1))) int *' with an expression of type 'int *' changes address space of pointer}}
|
||||
}
|
||||
|
||||
char *cmp(AS1 char *x, AS2 char *y) {
|
||||
return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('AS1 char *' and 'AS2 char *') which are pointers to non-overlapping address spaces}}
|
||||
}
|
||||
|
||||
__attribute__((address_space(1))) char test_array[10];
|
||||
void test3(void) {
|
||||
extern void test3_helper(char *p); // expected-note{{passing argument to parameter 'p' here}}
|
||||
test3_helper(test_array); // expected-error{{passing '__attribute__((address_space(1))) char *' to parameter of type 'char *' changes address space of pointer}}
|
||||
}
|
||||
|
||||
char AS2 *test4_array;
|
||||
void test4(void) {
|
||||
extern void test3_helper(char *p); // expected-note{{passing argument to parameter 'p' here}}
|
||||
test3_helper(test4_array); // expected-error{{passing 'AS2 char *' to parameter of type 'char *' changes address space of pointer}}
|
||||
}
|
||||
|
||||
void func() {
|
||||
char AS1 *x;
|
||||
char AS3 *x2;
|
||||
AS5 *x3;
|
||||
char *y;
|
||||
y = x; // expected-error{{assigning 'AS1 char *' to 'char *' changes address space of pointer}}
|
||||
y = x2; // expected-error{{assigning 'AS3 char *' to 'char *' changes address space of pointer}}
|
||||
y = x3; // expected-error{{assigning '__attribute__((address_space(5))) char *' to 'char *' changes address space of pointer}}
|
||||
}
|
||||
|
||||
void multiple_attrs(AS_ND int *x) {
|
||||
__attribute__((address_space(2))) int *y = x; // expected-warning{{casting to dereferenceable pointer removes 'noderef' attribute}}
|
||||
}
|
||||
|
||||
void override_macro_name() {
|
||||
#define ATTRS __attribute__((noderef)) // expected-note{{previous definition is here}}
|
||||
ATTRS
|
||||
#define ATTRS __attribute__((address_space(1))) // expected-warning{{'ATTRS' macro redefined}}
|
||||
ATTRS
|
||||
int *x;
|
||||
|
||||
int AS_ND *y = x; // expected-error{{initializing 'AS_ND int *' with an expression of type 'ATTRS int *' changes address space of pointer}}
|
||||
}
|
||||
|
||||
void partial_macro_declaration() {
|
||||
#define ATTRS2 __attribute__((noderef))
|
||||
ATTRS2 __attribute__((address_space(1))) int *x;
|
||||
|
||||
int AS_ND *y = x; // expected-error{{initializing 'AS_ND int *' with an expression of type 'ATTRS2 int __attribute__((address_space(1))) *' changes address space of pointer}}
|
||||
|
||||
// The attribute not wrapped with a macro should be printed regularly.
|
||||
#define ATTRS3 __attribute__((address_space(1)))
|
||||
ATTRS3 __attribute__((noderef)) int *x2;
|
||||
|
||||
int AS_ND *y2 = x2; // expected-error{{initializing 'AS_ND int *' with an expression of type 'ATTRS3 int * __attribute__((noderef))' changes address space of pointer}}
|
||||
}
|
@ -71,7 +71,7 @@ __attribute__((address_space("12"))) int *i; // expected-error {{'address_space'
|
||||
|
||||
// Clang extension doesn't forbid operations on pointers to different address spaces.
|
||||
char* cmp(_AS1 char *x, _AS2 char *y) {
|
||||
return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('__attribute__((address_space(1))) char *' and '__attribute__((address_space(2))) char *') which are pointers to non-overlapping address spaces}}
|
||||
return x < y ? x : y; // expected-error{{conditional operator with the second and third operands of type ('_AS1 char *' and '_AS2 char *') which are pointers to non-overlapping address spaces}}
|
||||
}
|
||||
|
||||
struct SomeStruct {
|
||||
|
@ -68,6 +68,12 @@ void (^blk)(ObjCTy *, ObjCTy *) =
|
||||
second = 0; // expected-error{{variable declared with 'objc_externally_retained' cannot be modified in ARC}}
|
||||
};
|
||||
|
||||
void (^blk2)(ObjCTy *, ObjCTy *) =
|
||||
^(__strong ObjCTy *first, ObjCTy *second) __attribute__((objc_externally_retained)) {
|
||||
first = 0;
|
||||
second = 0; // expected-error{{variable declared with 'objc_externally_retained' cannot be modified in ARC}}
|
||||
};
|
||||
|
||||
void test8(EXT_RET ObjCTy *x) {} // expected-warning{{'objc_externally_retained' attribute only applies to variables}}
|
||||
|
||||
#pragma clang attribute ext_ret.push(__attribute__((objc_externally_retained)), apply_to=any(function, block, objc_method))
|
||||
|
@ -62,6 +62,6 @@ void test_unsafe_unretained_cast(id *value) {
|
||||
|
||||
void test_cast_qualifier_inference(__weak id *value) {
|
||||
__weak id *a = (id*) value;
|
||||
__unsafe_unretained id *b = (id*) value; // expected-error {{initializing 'id *' with an expression of type '__weak id *' changes retain/release properties of pointer}}
|
||||
__unsafe_unretained id *b = (id *)value; // expected-error {{initializing '__unsafe_unretained id *' with an expression of type '__weak id *' changes retain/release properties of pointer}}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
@interface A
|
||||
@end
|
||||
|
||||
void f0(__strong A**); // expected-note{{candidate function not viable: 1st argument ('A *__weak *') has __weak ownership, but parameter has __strong ownership}}
|
||||
void f0(__strong A **); // expected-note{{candidate function not viable: 1st argument ('A *__weak *') has __weak ownership, but parameter has __strong ownership}}
|
||||
|
||||
void test_f0() {
|
||||
A *a;
|
||||
@ -12,7 +12,7 @@ void test_f0() {
|
||||
f0(&a2); // expected-error{{no matching function}}
|
||||
}
|
||||
|
||||
void f1(__weak A**); // expected-note{{candidate function not viable: 1st argument ('A *__strong *') has __strong ownership, but parameter has __weak ownership}}
|
||||
void f1(__weak A **); // expected-note{{candidate function not viable: 1st argument ('A *__strong *') has __strong ownership, but parameter has __weak ownership}}
|
||||
|
||||
void test_f1() {
|
||||
A *a;
|
||||
|
@ -1614,6 +1614,10 @@ bool CursorVisitor::VisitParenTypeLoc(ParenTypeLoc TL) {
|
||||
return Visit(TL.getInnerLoc());
|
||||
}
|
||||
|
||||
bool CursorVisitor::VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) {
|
||||
return Visit(TL.getInnerLoc());
|
||||
}
|
||||
|
||||
bool CursorVisitor::VisitPointerTypeLoc(PointerTypeLoc TL) {
|
||||
return Visit(TL.getPointeeLoc());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user