aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeonard Chan <leonardchan@google.com>2019-05-02 20:38:14 +0000
committerLeonard Chan <leonardchan@google.com>2019-05-02 20:38:14 +0000
commitfae4e4715c9bc8ceb9b3714d5c08813363890b7f (patch)
tree8994356a0cce2feee0f0cd07cc2ebc180c7fe81c
parentc1150d547616902e07d68c5b51f466bac8ff1883 (diff)
[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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359826 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h3
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h6
-rw-r--r--include/clang/AST/Type.h37
-rw-r--r--include/clang/AST/TypeLoc.h38
-rw-r--r--include/clang/AST/TypeNodes.def1
-rw-r--r--include/clang/Parse/Parser.h1
-rw-r--r--include/clang/Sema/ParsedAttr.h23
-rw-r--r--include/clang/Sema/Sema.h2
-rw-r--r--include/clang/Serialization/ASTBitCodes.h5
-rw-r--r--lib/ARCMigrate/TransGCAttrs.cpp3
-rw-r--r--lib/AST/ASTContext.cpp19
-rw-r--r--lib/AST/ASTDiagnostic.cpp5
-rw-r--r--lib/AST/ASTStructuralEquivalence.cpp7
-rw-r--r--lib/AST/ItaniumMangle.cpp1
-rw-r--r--lib/AST/Type.cpp19
-rw-r--r--lib/AST/TypePrinter.cpp16
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp4
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp1
-rw-r--r--lib/Parse/ParseDecl.cpp40
-rw-r--r--lib/Sema/SemaExpr.cpp5
-rw-r--r--lib/Sema/SemaStmt.cpp8
-rw-r--r--lib/Sema/SemaType.cpp27
-rw-r--r--lib/Sema/TreeTransform.h27
-rw-r--r--lib/Serialization/ASTReader.cpp14
-rw-r--r--lib/Serialization/ASTWriter.cpp11
-rw-r--r--test/Frontend/macro_defined_type.cpp15
-rw-r--r--test/Sema/address_space_print_macro.c67
-rw-r--r--test/Sema/address_spaces.c2
-rw-r--r--test/SemaObjC/externally-retained.m6
-rw-r--r--test/SemaObjC/gc-attributes.m4
-rw-r--r--test/SemaObjC/mrc-weak.m2
-rw-r--r--test/SemaObjCXX/gc-attributes.mm4
-rw-r--r--tools/libclang/CIndex.cpp4
33 files changed, 407 insertions, 20 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 1cddb6fd29..a09157cad0 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -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;
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 22ef332dbb..6096c9c0f4 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -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())); })
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 12a0213fdd..0633924f10 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -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;
}
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h
index 3b3eb1b6c6..40d17f991f 100644
--- a/include/clang/AST/TypeLoc.h
+++ b/include/clang/AST/TypeLoc.h
@@ -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;
}
diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def
index d1e4300fea..58a5f880cb 100644
--- a/include/clang/AST/TypeNodes.def
+++ b/include/clang/AST/TypeNodes.def
@@ -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)
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index e831e226d4..cb0080f14b 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1152,6 +1152,7 @@ private:
Parser *Self;
CachedTokens Toks;
IdentifierInfo &AttrName;
+ IdentifierInfo *MacroII = nullptr;
SourceLocation AttrNameLoc;
SmallVector<Decl*, 2> Decls;
diff --git a/include/clang/Sema/ParsedAttr.h b/include/clang/Sema/ParsedAttr.h
index 2e0efe452a..a42e4547a9 100644
--- a/include/clang/Sema/ParsedAttr.h
+++ b/include/clang/Sema/ParsedAttr.h
@@ -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.
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 64b92d2e7a..0796e99858 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -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.
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 0365e3a696..790cdf106f 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -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
diff --git a/lib/ARCMigrate/TransGCAttrs.cpp b/lib/ARCMigrate/TransGCAttrs.cpp
index a73b526ca8..fdbe1d119a 100644
--- a/lib/ARCMigrate/TransGCAttrs.cpp
+++ b/lib/ARCMigrate/TransGCAttrs.cpp
@@ -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>()) {
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index d0a790cad4..6348885375 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -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,
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 61900aa4ac..15df865852 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -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)) {
diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp
index 71bbd82481..567945c16c 100644
--- a/lib/AST/ASTStructuralEquivalence.cpp
+++ b/lib/AST/ASTStructuralEquivalence.cpp
@@ -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()))
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 3357756466..930537a934 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -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:
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index adffe92f95..590e534fbd 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -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(),
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 82a2fa09c7..fed39cadcb 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -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,
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 3656602c3d..4c43c00cd5 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -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:
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 7a8d79ba3b..d7bb4a54c1 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -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;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 130cd9f206..4e5ca2ee8f 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -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;
+ }
+ }
}
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 9564c8f0cb..3507361412 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index feb0052d42..34a769b251 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -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
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 3b25595a33..65cf3f59b3 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -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 ||
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index a8ea6b01d1..dddb2476c7 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -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) {
diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp
index a6ff54568d..64af0fa8a1 100644
--- a/lib/Serialization/ASTReader.cpp
+++ b/lib/Serialization/ASTReader.cpp
@@ -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());
}
diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp
index 756411a8c5..accd8ccdfa 100644
--- a/lib/Serialization/ASTWriter.cpp
+++ b/lib/Serialization/ASTWriter.cpp
@@ -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);
diff --git a/test/Frontend/macro_defined_type.cpp b/test/Frontend/macro_defined_type.cpp
new file mode 100644
index 0000000000..4e60c84038
--- /dev/null
+++ b/test/Frontend/macro_defined_type.cpp
@@ -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}}
+}
diff --git a/test/Sema/address_space_print_macro.c b/test/Sema/address_space_print_macro.c
new file mode 100644
index 0000000000..9557149d7c
--- /dev/null
+++ b/test/Sema/address_space_print_macro.c
@@ -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}}
+}
diff --git a/test/Sema/address_spaces.c b/test/Sema/address_spaces.c
index a9046d86f1..5425ef75b6 100644
--- a/test/Sema/address_spaces.c
+++ b/test/Sema/address_spaces.c
@@ -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 {
diff --git a/test/SemaObjC/externally-retained.m b/test/SemaObjC/externally-retained.m
index 2708fc8eef..24c531ccf7 100644
--- a/test/SemaObjC/externally-retained.m
+++ b/test/SemaObjC/externally-retained.m
@@ -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))
diff --git a/test/SemaObjC/gc-attributes.m b/test/SemaObjC/gc-attributes.m
index 1023ba6eec..8bc5c6af33 100644
--- a/test/SemaObjC/gc-attributes.m
+++ b/test/SemaObjC/gc-attributes.m
@@ -9,7 +9,7 @@ void test_f0() {
A *a;
static __weak A *a2;
f0(&a);
- f0(&a2); // expected-warning{{passing 'A *__weak *' to parameter of type 'A *__strong *' discards qualifiers}}
+ f0(&a2); // expected-warning{{passing 'A *__weak *' to parameter of type 'A *__strong *' discards qualifiers}}
}
void f1(__weak A**); // expected-note{{passing argument to parameter here}}
@@ -18,7 +18,7 @@ void test_f1() {
A *a;
__strong A *a2;
f1(&a);
- f1(&a2); // expected-warning{{passing 'A *__strong *' to parameter of type 'A *__weak *' discards qualifiers}}
+ f1(&a2); // expected-warning{{passing 'A *__strong *' to parameter of type 'A *__weak *' discards qualifiers}}
}
// These qualifiers should silently expand to nothing in GC mode.
diff --git a/test/SemaObjC/mrc-weak.m b/test/SemaObjC/mrc-weak.m
index e961e0ab75..af7081b53f 100644
--- a/test/SemaObjC/mrc-weak.m
+++ b/test/SemaObjC/mrc-weak.m
@@ -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}}
}
diff --git a/test/SemaObjCXX/gc-attributes.mm b/test/SemaObjCXX/gc-attributes.mm
index 4549683bb2..ac5ee74c5f 100644
--- a/test/SemaObjCXX/gc-attributes.mm
+++ b/test/SemaObjCXX/gc-attributes.mm
@@ -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;
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index a5a8998f61..1144ec64f5 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -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());
}