r241545 - C++ support for Objective-C lightweight generics.
Douglas Gregor
dgregor at apple.com
Mon Jul 6 20:58:15 PDT 2015
Author: dgregor
Date: Mon Jul 6 22:58:14 2015
New Revision: 241545
URL: http://llvm.org/viewvc/llvm-project?rev=241545&view=rev
Log:
C++ support for Objective-C lightweight generics.
Teach C++'s tentative parsing to handle specializations of Objective-C
class types (e.g., NSArray<NSString *>) as well as Objective-C
protocol qualifiers (id<NSCopying>) by extending type-annotation
tokens to handle this case. As part of this, remove Objective-C
protocol qualifiers from the declaration specifiers, which never
really made sense: instead, provide Sema entry points to make them
part of the type annotation token. Among other things, this properly
diagnoses bogus types such as "<NSCopying> id" which should have been
written as "id <NSCopying>".
Implements template instantiation support for, e.g., NSArray<T>*
in C++. Note that parameterized classes are not templates in the C++
sense, so that cannot (for example) be used as a template argument for
a template template parameter. Part of rdar://problem/6294649.
Added:
cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm
Modified:
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/include/clang/AST/TypeLoc.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/include/clang/Sema/DeclSpec.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/Type.cpp
cfe/trunk/lib/AST/TypeLoc.cpp
cfe/trunk/lib/Lex/PPMacroExpansion.cpp
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseExprCXX.cpp
cfe/trunk/lib/Parse/ParseInit.cpp
cfe/trunk/lib/Parse/ParseObjc.cpp
cfe/trunk/lib/Parse/Parser.cpp
cfe/trunk/lib/Sema/DeclSpec.cpp
cfe/trunk/lib/Sema/SemaDeclObjC.cpp
cfe/trunk/lib/Sema/SemaType.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/test/Index/annotate-parameterized-classes.m
cfe/trunk/test/Index/annotate-tokens.m
cfe/trunk/test/Parser/placeholder-recovery.m
cfe/trunk/test/SemaObjC/parameterized_classes.m
cfe/trunk/test/SemaObjC/protocol-archane.m
cfe/trunk/tools/libclang/CIndex.cpp
cfe/trunk/tools/libclang/CursorVisitor.h
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Jul 6 22:58:14 2015
@@ -4730,7 +4730,11 @@ class ObjCObjectPointerType : public Typ
QualType PointeeType;
ObjCObjectPointerType(QualType Canonical, QualType Pointee)
- : Type(ObjCObjectPointer, Canonical, false, false, false, false),
+ : Type(ObjCObjectPointer, Canonical,
+ Pointee->isDependentType(),
+ Pointee->isInstantiationDependentType(),
+ Pointee->isVariablyModifiedType(),
+ Pointee->containsUnexpandedParameterPack()),
PointeeType(Pointee) {}
friend class ASTContext; // ASTContext creates these.
Modified: cfe/trunk/include/clang/AST/TypeLoc.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TypeLoc.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TypeLoc.h (original)
+++ cfe/trunk/include/clang/AST/TypeLoc.h Mon Jul 6 22:58:14 2015
@@ -177,6 +177,9 @@ public:
memcpy(getOpaqueData(), Other.getOpaqueData(), Size);
}
+ /// Copies the other type loc into this one.
+ void copy(TypeLoc other);
+
friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) {
return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data;
}
@@ -253,6 +256,10 @@ public:
// do nothing
}
+ void copyLocal(TypeLoc other) {
+ // do nothing
+ }
+
TypeLoc getNextTypeLoc() const {
return getUnqualifiedLoc();
}
@@ -343,6 +350,20 @@ public:
return size;
}
+ void copyLocal(Derived other) {
+ // Some subclasses have no data to copy.
+ if (asDerived()->getLocalDataSize() == 0) return;
+
+ // Copy the fixed-sized local data.
+ memcpy(getLocalData(), other.getLocalData(), sizeof(LocalData));
+
+ // Copy the variable-sized local data. We need to do this
+ // separately because the padding in the source and the padding in
+ // the destination might be different.
+ memcpy(getExtraLocalData(), other.getExtraLocalData(),
+ asDerived()->getExtraLocalDataSize());
+ }
+
TypeLoc getNextTypeLoc() const {
return getNextTypeLoc(asDerived()->getInnerType());
}
@@ -892,6 +913,11 @@ public:
return *(this->getTypePtr()->qual_begin() + i);
}
+
+ ArrayRef<SourceLocation> getProtocolLocs() const {
+ return llvm::makeArrayRef(getProtocolLocArray(), getNumProtocols());
+ }
+
bool hasBaseTypeAsWritten() const {
return getLocalData()->HasBaseTypeAsWritten;
}
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jul 6 22:58:14 2015
@@ -7817,6 +7817,6 @@ def err_objc_type_arg_not_id_compatible
"type argument %0 is neither an Objective-C object nor a block type">;
def err_objc_type_arg_does_not_match_bound : Error<
- "type argument %0 does not satisy the bound (%1) of type parameter %2">;
+ "type argument %0 does not satisfy the bound (%1) of type parameter %2">;
} // end of sema component.
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Jul 6 22:58:14 2015
@@ -1267,19 +1267,45 @@ private:
bool WarnOnDeclarations,
bool ForObjCContainer,
SourceLocation &LAngleLoc,
- SourceLocation &EndProtoLoc);
- bool ParseObjCProtocolQualifiers(DeclSpec &DS);
- void ParseObjCTypeArgsOrProtocolQualifiers(DeclSpec &DS,
- bool warnOnIncompleteProtocols);
+ SourceLocation &EndProtoLoc,
+ bool consumeLastToken);
+
+ /// Parse the first angle-bracket-delimited clause for an
+ /// Objective-C object or object pointer type, which may be either
+ /// type arguments or protocol qualifiers.
+ void parseObjCTypeArgsOrProtocolQualifiers(
+ SourceLocation &typeArgsLAngleLoc,
+ SmallVectorImpl<ParsedType> &typeArgs,
+ SourceLocation &typeArgsRAngleLoc,
+ SourceLocation &protocolLAngleLoc,
+ SmallVectorImpl<Decl *> &protocols,
+ SmallVectorImpl<SourceLocation> &protocolLocs,
+ SourceLocation &protocolRAngleLoc,
+ bool consumeLastToken,
+ bool warnOnIncompleteProtocols);
/// Parse either Objective-C type arguments or protocol qualifiers; if the
/// former, also parse protocol qualifiers afterward.
- void ParseObjCTypeArgsAndProtocolQualifiers(DeclSpec &DS);
+ void parseObjCTypeArgsAndProtocolQualifiers(
+ SourceLocation &typeArgsLAngleLoc,
+ SmallVectorImpl<ParsedType> &typeArgs,
+ SourceLocation &typeArgsRAngleLoc,
+ SourceLocation &protocolLAngleLoc,
+ SmallVectorImpl<Decl *> &protocols,
+ SmallVectorImpl<SourceLocation> &protocolLocs,
+ SourceLocation &protocolRAngleLoc,
+ bool consumeLastToken);
+
+ /// Parse a protocol qualifier type such as '<NSCopying>', which is
+ /// an anachronistic way of writing 'id<NSCopying>'.
+ TypeResult parseObjCProtocolQualifierType(SourceLocation &rAngleLoc);
/// Parse Objective-C type arguments and protocol qualifiers, extending the
/// current type with the parsed result.
- TypeResult ParseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
- ParsedType type);
+ TypeResult parseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
+ ParsedType type,
+ bool consumeLastToken,
+ SourceLocation &endLoc);
void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey,
Decl *CDecl);
Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Mon Jul 6 22:58:14 2015
@@ -373,22 +373,6 @@ private:
// Scope specifier for the type spec, if applicable.
CXXScopeSpec TypeScope;
- /// List of Objective-C type arguments, e.g., in \c NSArray<NSView *>.
- ArrayRef<ParsedType> ObjCTypeArgs;
-
- /// Location of the '<' that starts a list of Objective-C type arguments.
- SourceLocation ObjCTypeArgsLAngleLoc;
- /// Location of the '>' that ends a list of Objective-C type arguments.
- SourceLocation ObjCTypeArgsRAngleLoc;
-
- // List of protocol qualifiers for objective-c classes. Used for
- // protocol-qualified interfaces "NString<foo>" and protocol-qualified id
- // "id<foo>".
- Decl * const *ProtocolQualifiers;
- unsigned NumProtocolQualifiers;
- SourceLocation ProtocolLAngleLoc;
- SourceLocation *ProtocolLocs;
-
// SourceLocation info. These are null if the item wasn't specified or if
// the setting was synthesized.
SourceRange Range;
@@ -450,17 +434,10 @@ public:
Constexpr_specified(false),
Concept_specified(false),
Attrs(attrFactory),
- ProtocolQualifiers(nullptr),
- NumProtocolQualifiers(0),
- ProtocolLocs(nullptr),
writtenBS(),
ObjCQualifiers(nullptr) {
}
- ~DeclSpec() {
- delete [] ObjCTypeArgs.data();
- delete [] ProtocolQualifiers;
- delete [] ProtocolLocs;
- }
+
// storage-class-specifier
SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
TSCS getThreadStorageClassSpec() const {
@@ -499,6 +476,8 @@ public:
bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; }
bool isTypeAltiVecBool() const { return TypeAltiVecBool; }
bool isTypeSpecOwned() const { return TypeSpecOwned; }
+ bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
+
ParsedType getRepAsType() const {
assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
return TypeRep;
@@ -760,38 +739,6 @@ public:
Attrs.takeAllFrom(attrs);
}
- /// Determine whether the declaration specifiers contain Objective-C
- /// type arguments.
- bool hasObjCTypeArgs() const { return !ObjCTypeArgs.empty(); }
-
- ArrayRef<ParsedType> getObjCTypeArgs() const { return ObjCTypeArgs; }
- SourceLocation getObjCTypeArgsLAngleLoc() const {
- return ObjCTypeArgsLAngleLoc;
- }
- SourceLocation getObjCTypeArgsRAngleLoc() const {
- return ObjCTypeArgsRAngleLoc;
- }
- SourceRange getObjCTypeArgsRange() const {
- return SourceRange(ObjCTypeArgsLAngleLoc, ObjCTypeArgsRAngleLoc);
- }
-
- void setObjCTypeArgs(SourceLocation lAngleLoc,
- ArrayRef<ParsedType> args,
- SourceLocation rAngleLoc);
-
- typedef Decl * const *ProtocolQualifierListTy;
- ProtocolQualifierListTy getProtocolQualifiers() const {
- return ProtocolQualifiers;
- }
- SourceLocation *getProtocolLocs() const { return ProtocolLocs; }
- unsigned getNumProtocolQualifiers() const {
- return NumProtocolQualifiers;
- }
- SourceLocation getProtocolLAngleLoc() const { return ProtocolLAngleLoc; }
- void setProtocolQualifiers(Decl * const *Protos, unsigned NP,
- SourceLocation *ProtoLocs,
- SourceLocation LAngleLoc);
-
/// Finish - This does final analysis of the declspec, issuing diagnostics for
/// things like "_Imaginary" (lacking an FP type). After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jul 6 22:58:14 2015
@@ -7191,17 +7191,54 @@ public:
/// Given a list of identifiers (and their locations), resolve the
/// names to either Objective-C protocol qualifiers or type
- /// arguments, as appropriate. The result will be attached to the
- /// given declaration specifiers.
+ /// arguments, as appropriate.
void actOnObjCTypeArgsOrProtocolQualifiers(
Scope *S,
- DeclSpec &DS,
SourceLocation lAngleLoc,
ArrayRef<IdentifierInfo *> identifiers,
ArrayRef<SourceLocation> identifierLocs,
SourceLocation rAngleLoc,
+ SourceLocation &typeArgsLAngleLoc,
+ SmallVectorImpl<ParsedType> &typeArgs,
+ SourceLocation &typeArgsRAngleLoc,
+ SourceLocation &protocolLAngleLoc,
+ SmallVectorImpl<Decl *> &protocols,
+ SourceLocation &protocolRAngleLoc,
bool warnOnIncompleteProtocols);
+ /// Build a an Objective-C protocol-qualified 'id' type where no
+ /// base type was specified.
+ TypeResult actOnObjCProtocolQualifierType(
+ SourceLocation lAngleLoc,
+ ArrayRef<Decl *> protocols,
+ ArrayRef<SourceLocation> protocolLocs,
+ SourceLocation rAngleLoc);
+
+ /// Build a specialized and/or protocol-qualified Objective-C type.
+ TypeResult actOnObjCTypeArgsAndProtocolQualifiers(
+ Scope *S,
+ SourceLocation Loc,
+ ParsedType BaseType,
+ SourceLocation TypeArgsLAngleLoc,
+ ArrayRef<ParsedType> TypeArgs,
+ SourceLocation TypeArgsRAngleLoc,
+ SourceLocation ProtocolLAngleLoc,
+ ArrayRef<Decl *> Protocols,
+ ArrayRef<SourceLocation> ProtocolLocs,
+ SourceLocation ProtocolRAngleLoc);
+
+ /// Build an Objective-C object pointer type.
+ QualType BuildObjCObjectType(QualType BaseType,
+ SourceLocation Loc,
+ SourceLocation TypeArgsLAngleLoc,
+ ArrayRef<TypeSourceInfo *> TypeArgs,
+ SourceLocation TypeArgsRAngleLoc,
+ SourceLocation ProtocolLAngleLoc,
+ ArrayRef<ObjCProtocolDecl *> Protocols,
+ ArrayRef<SourceLocation> ProtocolLocs,
+ SourceLocation ProtocolRAngleLoc,
+ bool FailOnError = false);
+
/// Ensure attributes are consistent with type.
/// \param [in, out] Attributes The attributes to check; they will
/// be modified to be consistent with \p PropertyTy.
Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Jul 6 22:58:14 2015
@@ -469,7 +469,10 @@ const RecordType *Type::getAsUnionType()
ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
ArrayRef<QualType> typeArgs,
ArrayRef<ObjCProtocolDecl *> protocols)
- : Type(ObjCObject, Canonical, false, false, false, false),
+ : Type(ObjCObject, Canonical, Base->isDependentType(),
+ Base->isInstantiationDependentType(),
+ Base->isVariablyModifiedType(),
+ Base->containsUnexpandedParameterPack()),
BaseType(Base)
{
ObjCObjectTypeBits.NumTypeArgs = typeArgs.size();
@@ -484,6 +487,16 @@ ObjCObjectType::ObjCObjectType(QualType
if (!protocols.empty())
memcpy(getProtocolStorage(), protocols.data(),
protocols.size() * sizeof(ObjCProtocolDecl*));
+
+ for (auto typeArg : typeArgs) {
+ if (typeArg->isDependentType())
+ setDependent();
+ else if (typeArg->isInstantiationDependentType())
+ setInstantiationDependent();
+
+ if (typeArg->containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+ }
}
bool ObjCObjectType::isSpecialized() const {
Modified: cfe/trunk/lib/AST/TypeLoc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypeLoc.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TypeLoc.cpp (original)
+++ cfe/trunk/lib/AST/TypeLoc.cpp Mon Jul 6 22:58:14 2015
@@ -19,6 +19,8 @@
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+static const unsigned TypeLocMaxDataAlign = llvm::alignOf<void *>();
+
//===----------------------------------------------------------------------===//
// TypeLoc Implementation
//===----------------------------------------------------------------------===//
@@ -125,6 +127,46 @@ void TypeLoc::initializeImpl(ASTContext
}
}
+namespace {
+ class TypeLocCopier : public TypeLocVisitor<TypeLocCopier> {
+ TypeLoc Source;
+ public:
+ TypeLocCopier(TypeLoc source) : Source(source) { }
+
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ void Visit##CLASS##TypeLoc(CLASS##TypeLoc dest) { \
+ dest.copyLocal(Source.castAs<CLASS##TypeLoc>()); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ };
+}
+
+
+void TypeLoc::copy(TypeLoc other) {
+ assert(getFullDataSize() == other.getFullDataSize());
+
+ // If both data pointers are aligned to the maximum alignment, we
+ // can memcpy because getFullDataSize() accurately reflects the
+ // layout of the data.
+ if (reinterpret_cast<uintptr_t>(Data)
+ == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(Data),
+ TypeLocMaxDataAlign) &&
+ reinterpret_cast<uintptr_t>(other.Data)
+ == llvm::RoundUpToAlignment(reinterpret_cast<uintptr_t>(other.Data),
+ TypeLocMaxDataAlign)) {
+ memcpy(Data, other.Data, getFullDataSize());
+ return;
+ }
+
+ // Copy each of the pieces.
+ TypeLoc TL(getType(), Data);
+ do {
+ TypeLocCopier(other).Visit(TL);
+ other = other.getNextTypeLoc();
+ } while ((TL = TL.getNextTypeLoc()));
+}
+
SourceLocation TypeLoc::getBeginLoc() const {
TypeLoc Cur = *this;
TypeLoc LeftMost = Cur;
Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Mon Jul 6 22:58:14 2015
@@ -1106,6 +1106,7 @@ static bool HasFeature(const Preprocesso
.Case("arc_cf_code_audited", true)
.Case("objc_bridge_id", true)
.Case("objc_bridge_id_on_typedefs", true)
+ .Case("objc_generics", LangOpts.ObjC2)
// C11 features
.Case("c_alignas", LangOpts.C11)
.Case("c_alignof", LangOpts.C11)
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jul 6 22:58:14 2015
@@ -2144,8 +2144,7 @@ void Parser::ParseSpecifierQualifierList
if (isTypeSpecifier(DSC) && !DS.hasTypeSpecifier()) {
Diag(Tok, diag::err_expected_type);
DS.SetTypeSpecError();
- } else if (Specs == DeclSpec::PQ_None && !DS.getNumProtocolQualifiers() &&
- !DS.hasAttributes()) {
+ } else if (Specs == DeclSpec::PQ_None && !DS.hasAttributes()) {
Diag(Tok, diag::err_typename_requires_specqual);
if (!DS.hasTypeSpecifier())
DS.SetTypeSpecError();
@@ -2886,13 +2885,6 @@ void Parser::ParseDeclarationSpecifiers(
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeToken(); // The typename
- // Objective-C supports type arguments and protocol references
- // following an Objective-C object pointer type. Handle either
- // one of them.
- if (Tok.is(tok::less) && getLangOpts().ObjC1) {
- ParseObjCTypeArgsAndProtocolQualifiers(DS);
- }
-
continue;
}
@@ -2999,10 +2991,17 @@ void Parser::ParseDeclarationSpecifiers(
ConsumeToken(); // The identifier
// Objective-C supports type arguments and protocol references
- // following an Objective-C object pointer type. Handle either
- // one of them.
+ // following an Objective-C object or object pointer
+ // type. Handle either one of them.
if (Tok.is(tok::less) && getLangOpts().ObjC1) {
- ParseObjCTypeArgsAndProtocolQualifiers(DS);
+ SourceLocation NewEndLoc;
+ TypeResult NewTypeRep = parseObjCTypeArgsAndProtocolQualifiers(
+ Loc, TypeRep, /*consumeLastToken=*/true,
+ NewEndLoc);
+ if (NewTypeRep.isUsable()) {
+ DS.UpdateTypeRep(NewTypeRep.get());
+ DS.SetRangeEnd(NewEndLoc);
+ }
}
// Need to support trailing type qualifiers (e.g. "id<p> const").
@@ -3420,10 +3419,19 @@ void Parser::ParseDeclarationSpecifiers(
if (DS.hasTypeSpecifier() || !getLangOpts().ObjC1)
goto DoneWithDeclSpec;
- if (!ParseObjCProtocolQualifiers(DS))
- Diag(Loc, diag::warn_objc_protocol_qualifier_missing_id)
- << FixItHint::CreateInsertion(Loc, "id")
- << SourceRange(Loc, DS.getSourceRange().getEnd());
+ SourceLocation StartLoc = Tok.getLocation();
+ SourceLocation EndLoc;
+ TypeResult Type = parseObjCProtocolQualifierType(EndLoc);
+ if (Type.isUsable()) {
+ if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, StartLoc,
+ PrevSpec, DiagID, Type.get(),
+ Actions.getASTContext().getPrintingPolicy()))
+ Diag(StartLoc, DiagID) << PrevSpec;
+
+ DS.SetRangeEnd(EndLoc);
+ } else {
+ DS.SetTypeSpecError();
+ }
// Need to support trailing type qualifiers (e.g. "id<p> const").
// If a type specifier follows, it will be diagnosed elsewhere.
Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Mon Jul 6 22:58:14 2015
@@ -1805,13 +1805,6 @@ void Parser::ParseCXXSimpleTypeSpecifier
DS.SetRangeEnd(Tok.getAnnotationEndLoc());
ConsumeToken();
- // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
- // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
- // Objective-C interface. If we don't have Objective-C or a '<', this is
- // just a normal reference to a typedef name.
- if (Tok.is(tok::less) && getLangOpts().ObjC1)
- ParseObjCProtocolQualifiers(DS);
-
DS.Finish(Diags, PP, Policy);
return;
}
Modified: cfe/trunk/lib/Parse/ParseInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseInit.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseInit.cpp (original)
+++ cfe/trunk/lib/Parse/ParseInit.cpp Mon Jul 6 22:58:14 2015
@@ -274,8 +274,11 @@ ExprResult Parser::ParseInitializerWithP
// Parse type arguments and protocol qualifiers.
if (Tok.is(tok::less)) {
+ SourceLocation NewEndLoc;
TypeResult NewReceiverType
- = ParseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType);
+ = parseObjCTypeArgsAndProtocolQualifiers(IILoc, ReceiverType,
+ /*consumeLastToken=*/true,
+ NewEndLoc);
if (!NewReceiverType.isUsable()) {
SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Mon Jul 6 22:58:14 2015
@@ -267,7 +267,8 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
- LAngleLoc, EndProtoLoc))
+ LAngleLoc, EndProtoLoc,
+ /*consumeLastToken=*/true))
return nullptr;
Decl *CategoryType =
@@ -293,8 +294,11 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
// Parse a class interface.
IdentifierInfo *superClassId = nullptr;
SourceLocation superClassLoc;
- DeclSpec superClassDS(AttrFactory);
-
+ SourceLocation typeArgsLAngleLoc;
+ SmallVector<ParsedType, 4> typeArgs;
+ SourceLocation typeArgsRAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
if (Tok.is(tok::colon)) { // a super class is specified.
ConsumeToken();
@@ -315,51 +319,50 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
// Type arguments for the superclass or protocol conformances.
if (Tok.is(tok::less)) {
- ParseObjCTypeArgsOrProtocolQualifiers(superClassDS,
+ parseObjCTypeArgsOrProtocolQualifiers(typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ LAngleLoc,
+ protocols,
+ protocolLocs,
+ EndProtoLoc,
+ /*consumeLastToken=*/true,
/*warnOnIncompleteProtocols=*/true);
}
}
// Next, we need to check for any protocol references.
- SmallVector<Decl *, 8> ProtocolRefs;
- SmallVector<SourceLocation, 8> ProtocolLocs;
if (LAngleLoc.isValid()) {
- // We already parsed the protocols named when we thought we had a
- // type parameter list. Translate them into actual protocol references.
- for (const auto &pair : ProtocolIdents) {
- ProtocolLocs.push_back(pair.second);
- }
- Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
- /*ForObjCContainer=*/true,
- &ProtocolIdents[0], ProtocolIdents.size(),
- ProtocolRefs);
- } else if (auto protocols = superClassDS.getProtocolQualifiers()) {
- // We already parsed the protocols named when we thought we had a
- // type argument list (for a specialized superclass). Treat them
- // as actual protocol references.
- unsigned numProtocols = superClassDS.getNumProtocolQualifiers();
- ProtocolRefs.append(protocols, protocols + numProtocols);
- ProtocolLocs.append(superClassDS.getProtocolLocs(),
- superClassDS.getProtocolLocs() + numProtocols);
- LAngleLoc = superClassDS.getProtocolLAngleLoc();
- EndProtoLoc = superClassDS.getLocEnd();
- } else if (Tok.is(tok::less) &&
- ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, true, true,
- LAngleLoc, EndProtoLoc)) {
+ if (!ProtocolIdents.empty()) {
+ // We already parsed the protocols named when we thought we had a
+ // type parameter list. Translate them into actual protocol references.
+ for (const auto &pair : ProtocolIdents) {
+ protocolLocs.push_back(pair.second);
+ }
+ Actions.FindProtocolDeclaration(/*WarnOnDeclarations=*/true,
+ /*ForObjCContainer=*/true,
+ &ProtocolIdents[0], ProtocolIdents.size(),
+ protocols);
+ }
+ } else if (protocols.empty() && Tok.is(tok::less) &&
+ ParseObjCProtocolReferences(protocols, protocolLocs, true, true,
+ LAngleLoc, EndProtoLoc,
+ /*consumeLastToken=*/true)) {
return nullptr;
}
if (Tok.isNot(tok::less))
- Actions.ActOnTypedefedProtocols(ProtocolRefs, superClassId, superClassLoc);
+ Actions.ActOnTypedefedProtocols(protocols, superClassId, superClassLoc);
Decl *ClsType =
Actions.ActOnStartClassInterface(getCurScope(), AtLoc, nameId, nameLoc,
typeParameterList, superClassId,
superClassLoc,
- superClassDS.getObjCTypeArgs(),
- superClassDS.getObjCTypeArgsRange(),
- ProtocolRefs.data(), ProtocolRefs.size(),
- ProtocolLocs.data(),
+ typeArgs,
+ SourceRange(typeArgsLAngleLoc,
+ typeArgsRAngleLoc),
+ protocols.data(), protocols.size(),
+ protocolLocs.data(),
EndProtoLoc, attrs.getList());
if (Tok.is(tok::l_brace))
@@ -1515,7 +1518,8 @@ bool Parser::
ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &Protocols,
SmallVectorImpl<SourceLocation> &ProtocolLocs,
bool WarnOnDeclarations, bool ForObjCContainer,
- SourceLocation &LAngleLoc, SourceLocation &EndLoc) {
+ SourceLocation &LAngleLoc, SourceLocation &EndLoc,
+ bool consumeLastToken) {
assert(Tok.is(tok::less) && "expected <");
LAngleLoc = ConsumeToken(); // the "<"
@@ -1545,7 +1549,7 @@ ParseObjCProtocolReferences(SmallVectorI
}
// Consume the '>'.
- if (ParseGreaterThanInTemplateList(EndLoc, /*ConsumeLastToken=*/true,
+ if (ParseGreaterThanInTemplateList(EndLoc, consumeLastToken,
/*ObjCGenericList=*/false))
return true;
@@ -1556,30 +1560,43 @@ ParseObjCProtocolReferences(SmallVectorI
return false;
}
-/// \brief Parse the Objective-C protocol qualifiers that follow a typename
-/// in a decl-specifier-seq, starting at the '<'.
-bool Parser::ParseObjCProtocolQualifiers(DeclSpec &DS) {
+TypeResult Parser::parseObjCProtocolQualifierType(SourceLocation &rAngleLoc) {
assert(Tok.is(tok::less) && "Protocol qualifiers start with '<'");
assert(getLangOpts().ObjC1 && "Protocol qualifiers only exist in Objective-C");
- SourceLocation LAngleLoc, EndProtoLoc;
- SmallVector<Decl *, 8> ProtocolDecl;
- SmallVector<SourceLocation, 8> ProtocolLocs;
- bool Result = ParseObjCProtocolReferences(ProtocolDecl, ProtocolLocs, false,
- false, LAngleLoc, EndProtoLoc);
- DS.setProtocolQualifiers(ProtocolDecl.data(), ProtocolDecl.size(),
- ProtocolLocs.data(), LAngleLoc);
- if (EndProtoLoc.isValid())
- DS.SetRangeEnd(EndProtoLoc);
- return Result;
+
+ SourceLocation lAngleLoc;
+ SmallVector<Decl *, 8> protocols;
+ SmallVector<SourceLocation, 8> protocolLocs;
+ (void)ParseObjCProtocolReferences(protocols, protocolLocs, false, false,
+ lAngleLoc, rAngleLoc,
+ /*consumeLastToken=*/true);
+ TypeResult result = Actions.actOnObjCProtocolQualifierType(lAngleLoc,
+ protocols,
+ protocolLocs,
+ rAngleLoc);
+ if (result.isUsable()) {
+ Diag(lAngleLoc, diag::warn_objc_protocol_qualifier_missing_id)
+ << FixItHint::CreateInsertion(lAngleLoc, "id")
+ << SourceRange(lAngleLoc, rAngleLoc);
+ }
+
+ return result;
}
/// Parse Objective-C type arguments or protocol qualifiers.
///
/// objc-type-arguments:
-/// '<' type-name (',' type-name)* '>'
+/// '<' type-name '...'[opt] (',' type-name '...'[opt])* '>'
///
-void Parser::ParseObjCTypeArgsOrProtocolQualifiers(
- DeclSpec &DS,
+void Parser::parseObjCTypeArgsOrProtocolQualifiers(
+ SourceLocation &typeArgsLAngleLoc,
+ SmallVectorImpl<ParsedType> &typeArgs,
+ SourceLocation &typeArgsRAngleLoc,
+ SourceLocation &protocolLAngleLoc,
+ SmallVectorImpl<Decl *> &protocols,
+ SmallVectorImpl<SourceLocation> &protocolLocs,
+ SourceLocation &protocolRAngleLoc,
+ bool consumeLastToken,
bool warnOnIncompleteProtocols) {
assert(Tok.is(tok::less) && "Not at the start of type args or protocols");
SourceLocation lAngleLoc = ConsumeToken();
@@ -1588,7 +1605,7 @@ void Parser::ParseObjCTypeArgsOrProtocol
// identifiers, which might be types or might be protocols.
bool allSingleIdentifiers = true;
SmallVector<IdentifierInfo *, 4> identifiers;
- SmallVector<SourceLocation, 4> identifierLocs;
+ SmallVectorImpl<SourceLocation> &identifierLocs = protocolLocs;
// Parse a list of comma-separated identifiers, bailing out if we
// see something different.
@@ -1626,23 +1643,27 @@ void Parser::ParseObjCTypeArgsOrProtocol
if (allSingleIdentifiers) {
// Parse the closing '>'.
SourceLocation rAngleLoc;
- (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+ (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
/*ObjCGenericList=*/true);
// Let Sema figure out what we parsed.
Actions.actOnObjCTypeArgsOrProtocolQualifiers(getCurScope(),
- DS,
lAngleLoc,
identifiers,
identifierLocs,
rAngleLoc,
+ typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ protocolLAngleLoc,
+ protocols,
+ protocolRAngleLoc,
warnOnIncompleteProtocols);
return;
}
// We syntactically matched a type argument, so commit to parsing
// type arguments.
- SmallVector<ParsedType, 4> typeArgs;
// Convert the identifiers into type arguments.
bool invalid = false;
@@ -1650,7 +1671,19 @@ void Parser::ParseObjCTypeArgsOrProtocol
ParsedType typeArg
= Actions.getTypeName(*identifiers[i], identifierLocs[i], getCurScope());
if (typeArg) {
- typeArgs.push_back(typeArg);
+ DeclSpec DS(AttrFactory);
+ const char *prevSpec = nullptr;
+ unsigned diagID;
+ DS.SetTypeSpecType(TST_typename, identifierLocs[i], prevSpec, diagID,
+ typeArg, Actions.getASTContext().getPrintingPolicy());
+
+ // Form a declarator to turn this into a type.
+ Declarator D(DS, Declarator::TypeNameContext);
+ TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D);
+ if (fullTypeArg.isUsable())
+ typeArgs.push_back(fullTypeArg.get());
+ else
+ invalid = true;
} else {
invalid = true;
}
@@ -1659,6 +1692,14 @@ void Parser::ParseObjCTypeArgsOrProtocol
// Continue parsing type-names.
do {
TypeResult typeArg = ParseTypeName();
+
+ // Consume the '...' for a pack expansion.
+ SourceLocation ellipsisLoc;
+ TryConsumeToken(tok::ellipsis, ellipsisLoc);
+ if (typeArg.isUsable() && ellipsisLoc.isValid()) {
+ typeArg = Actions.ActOnPackExpansion(typeArg.get(), ellipsisLoc);
+ }
+
if (typeArg.isUsable()) {
typeArgs.push_back(typeArg.get());
} else {
@@ -1668,53 +1709,105 @@ void Parser::ParseObjCTypeArgsOrProtocol
// Parse the closing '>'.
SourceLocation rAngleLoc;
- (void)ParseGreaterThanInTemplateList(rAngleLoc, /*ConsumeLastToken=*/true,
+ (void)ParseGreaterThanInTemplateList(rAngleLoc, consumeLastToken,
/*ObjCGenericList=*/true);
- if (invalid)
+ if (invalid) {
+ typeArgs.clear();
return;
+ }
- // Update the DeclSpec appropriately.
- DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
+ // Record left/right angle locations.
+ typeArgsLAngleLoc = lAngleLoc;
+ typeArgsRAngleLoc = rAngleLoc;
}
-void Parser::ParseObjCTypeArgsAndProtocolQualifiers(DeclSpec &DS) {
+void Parser::parseObjCTypeArgsAndProtocolQualifiers(
+ SourceLocation &typeArgsLAngleLoc,
+ SmallVectorImpl<ParsedType> &typeArgs,
+ SourceLocation &typeArgsRAngleLoc,
+ SourceLocation &protocolLAngleLoc,
+ SmallVectorImpl<Decl *> &protocols,
+ SmallVectorImpl<SourceLocation> &protocolLocs,
+ SourceLocation &protocolRAngleLoc,
+ bool consumeLastToken) {
assert(Tok.is(tok::less));
- ParseObjCTypeArgsOrProtocolQualifiers(DS,
+ // Parse the first angle-bracket-delimited clause.
+ parseObjCTypeArgsOrProtocolQualifiers(typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ protocolLAngleLoc,
+ protocols,
+ protocolLocs,
+ protocolRAngleLoc,
+ consumeLastToken,
/*warnOnIncompleteProtocols=*/false);
// An Objective-C object pointer followed by type arguments
// can then be followed again by a set of protocol references, e.g.,
// \c NSArray<NSView><NSTextDelegate>
- if (Tok.is(tok::less)) {
- if (DS.getProtocolQualifiers()) {
+ if ((consumeLastToken && Tok.is(tok::less)) ||
+ (!consumeLastToken && NextToken().is(tok::less))) {
+ // If we aren't consuming the last token, the prior '>' is still hanging
+ // there. Consume it before we parse the protocol qualifiers.
+ if (!consumeLastToken)
+ ConsumeToken();
+
+ if (!protocols.empty()) {
+ SkipUntilFlags skipFlags = SkipUntilFlags();
+ if (!consumeLastToken)
+ skipFlags = skipFlags | StopBeforeMatch;
Diag(Tok, diag::err_objc_type_args_after_protocols)
- << SourceRange(DS.getProtocolLAngleLoc(), DS.getLocEnd());
- SkipUntil(tok::greater, tok::greatergreater);
+ << SourceRange(protocolLAngleLoc, protocolRAngleLoc);
+ SkipUntil(tok::greater, tok::greatergreater, skipFlags);
} else {
- ParseObjCProtocolQualifiers(DS);
+ ParseObjCProtocolReferences(protocols, protocolLocs,
+ /*WarnOnDeclarations=*/false,
+ /*ForObjCContainer=*/false,
+ protocolLAngleLoc, protocolRAngleLoc,
+ consumeLastToken);
}
}
}
-TypeResult Parser::ParseObjCTypeArgsAndProtocolQualifiers(SourceLocation loc,
- ParsedType type) {
+TypeResult Parser::parseObjCTypeArgsAndProtocolQualifiers(
+ SourceLocation loc,
+ ParsedType type,
+ bool consumeLastToken,
+ SourceLocation &endLoc) {
assert(Tok.is(tok::less));
-
- // Create declaration specifiers and set the type as the type specifier.
- DeclSpec DS(AttrFactory);
- const char *prevSpec = nullptr;
- unsigned diagID;
- DS.SetTypeSpecType(TST_typename, loc, prevSpec, diagID, type,
- Actions.getASTContext().getPrintingPolicy());
+ SourceLocation typeArgsLAngleLoc;
+ SmallVector<ParsedType, 4> typeArgs;
+ SourceLocation typeArgsRAngleLoc;
+ SourceLocation protocolLAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
+ SourceLocation protocolRAngleLoc;
// Parse type arguments and protocol qualifiers.
- ParseObjCTypeArgsAndProtocolQualifiers(DS);
+ parseObjCTypeArgsAndProtocolQualifiers(typeArgsLAngleLoc, typeArgs,
+ typeArgsRAngleLoc, protocolLAngleLoc,
+ protocols, protocolLocs,
+ protocolRAngleLoc, consumeLastToken);
+
+ // Compute the location of the last token.
+ if (consumeLastToken)
+ endLoc = PrevTokLocation;
+ else
+ endLoc = Tok.getLocation();
- // Form a declarator to turn this into a type.
- Declarator D(DS, Declarator::TypeNameContext);
- return Actions.ActOnTypeName(getCurScope(), D);
+ return Actions.actOnObjCTypeArgsAndProtocolQualifiers(
+ getCurScope(),
+ loc,
+ type,
+ typeArgsLAngleLoc,
+ typeArgs,
+ typeArgsRAngleLoc,
+ protocolLAngleLoc,
+ protocols,
+ protocolLocs,
+ protocolRAngleLoc);
}
void Parser::HelperActionsForIvarDeclarations(Decl *interfaceDecl, SourceLocation atLoc,
@@ -1926,7 +2019,8 @@ Parser::ParseObjCAtProtocolDeclaration(S
SmallVector<SourceLocation, 8> ProtocolLocs;
if (Tok.is(tok::less) &&
ParseObjCProtocolReferences(ProtocolRefs, ProtocolLocs, false, true,
- LAngleLoc, EndProtoLoc))
+ LAngleLoc, EndProtoLoc,
+ /*consumeLastToken=*/true))
return DeclGroupPtrTy();
Decl *ProtoType =
@@ -2020,9 +2114,14 @@ Parser::ParseObjCAtImplementationDeclara
rparenLoc = ConsumeParen();
if (Tok.is(tok::less)) { // we have illegal '<' try to recover
Diag(Tok, diag::err_unexpected_protocol_qualifier);
- AttributeFactory attr;
- DeclSpec DS(attr);
- (void)ParseObjCProtocolQualifiers(DS);
+ SourceLocation protocolLAngleLoc, protocolRAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
+ (void)ParseObjCProtocolReferences(protocols, protocolLocs,
+ /*warnOnIncompleteProtocols=*/false,
+ /*ForObjCContainer=*/false,
+ protocolLAngleLoc, protocolRAngleLoc,
+ /*consumeLastToken=*/true);
}
ObjCImpDecl = Actions.ActOnStartCategoryImplementation(
AtLoc, nameId, nameLoc, categoryId,
@@ -2050,10 +2149,15 @@ Parser::ParseObjCAtImplementationDeclara
ParseObjCClassInstanceVariables(ObjCImpDecl, tok::objc_private, AtLoc);
else if (Tok.is(tok::less)) { // we have illegal '<' try to recover
Diag(Tok, diag::err_unexpected_protocol_qualifier);
- // try to recover.
- AttributeFactory attr;
- DeclSpec DS(attr);
- (void)ParseObjCProtocolQualifiers(DS);
+
+ SourceLocation protocolLAngleLoc, protocolRAngleLoc;
+ SmallVector<Decl *, 4> protocols;
+ SmallVector<SourceLocation, 4> protocolLocs;
+ (void)ParseObjCProtocolReferences(protocols, protocolLocs,
+ /*warnOnIncompleteProtocols=*/false,
+ /*ForObjCContainer=*/false,
+ protocolLAngleLoc, protocolRAngleLoc,
+ /*consumeLastToken=*/true);
}
}
assert(ObjCImpDecl);
@@ -2873,8 +2977,11 @@ ExprResult Parser::ParseObjCMessageExpre
// Parse type arguments and protocol qualifiers.
if (Tok.is(tok::less)) {
+ SourceLocation NewEndLoc;
TypeResult NewReceiverType
- = ParseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType);
+ = parseObjCTypeArgsAndProtocolQualifiers(NameLoc, ReceiverType,
+ /*consumeLastToken=*/true,
+ NewEndLoc);
if (!NewReceiverType.isUsable()) {
SkipUntil(tok::r_square, StopAtSemi);
return ExprError();
Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Mon Jul 6 22:58:14 2015
@@ -1413,14 +1413,35 @@ Parser::TryAnnotateName(bool IsAddressOf
// It's not something we know about. Leave it unannotated.
break;
- case Sema::NC_Type:
- Tok.setKind(tok::annot_typename);
- setTypeAnnotation(Tok, Classification.getType());
- Tok.setAnnotationEndLoc(NameLoc);
+ case Sema::NC_Type: {
+ SourceLocation BeginLoc = NameLoc;
if (SS.isNotEmpty())
- Tok.setLocation(SS.getBeginLoc());
+ BeginLoc = SS.getBeginLoc();
+
+ /// An Objective-C object type followed by '<' is a specialization of
+ /// a parameterized class type or a protocol-qualified type.
+ ParsedType Ty = Classification.getType();
+ if (getLangOpts().ObjC1 && NextToken().is(tok::less) &&
+ (Ty.get()->isObjCObjectType() ||
+ Ty.get()->isObjCObjectPointerType())) {
+ // Consume the name.
+ SourceLocation IdentifierLoc = ConsumeToken();
+ SourceLocation NewEndLoc;
+ TypeResult NewType
+ = parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty,
+ /*consumeLastToken=*/false,
+ NewEndLoc);
+ if (NewType.isUsable())
+ Ty = NewType.get();
+ }
+
+ Tok.setKind(tok::annot_typename);
+ setTypeAnnotation(Tok, Ty);
+ Tok.setAnnotationEndLoc(Tok.getLocation());
+ Tok.setLocation(BeginLoc);
PP.AnnotateCachedTokens(Tok);
return ANK_Success;
+ }
case Sema::NC_Expression:
Tok.setKind(tok::annot_primary_expr);
@@ -1627,13 +1648,33 @@ bool Parser::TryAnnotateTypeOrScopeToken
// A FixIt was applied as a result of typo correction
if (CorrectedII)
Tok.setIdentifierInfo(CorrectedII);
+
+ SourceLocation BeginLoc = Tok.getLocation();
+ if (SS.isNotEmpty()) // it was a C++ qualified type name.
+ BeginLoc = SS.getBeginLoc();
+
+ /// An Objective-C object type followed by '<' is a specialization of
+ /// a parameterized class type or a protocol-qualified type.
+ if (getLangOpts().ObjC1 && NextToken().is(tok::less) &&
+ (Ty.get()->isObjCObjectType() ||
+ Ty.get()->isObjCObjectPointerType())) {
+ // Consume the name.
+ SourceLocation IdentifierLoc = ConsumeToken();
+ SourceLocation NewEndLoc;
+ TypeResult NewType
+ = parseObjCTypeArgsAndProtocolQualifiers(IdentifierLoc, Ty,
+ /*consumeLastToken=*/false,
+ NewEndLoc);
+ if (NewType.isUsable())
+ Ty = NewType.get();
+ }
+
// This is a typename. Replace the current token in-place with an
// annotation type token.
Tok.setKind(tok::annot_typename);
setTypeAnnotation(Tok, Ty);
Tok.setAnnotationEndLoc(Tok.getLocation());
- if (SS.isNotEmpty()) // it was a C++ qualified type name.
- Tok.setLocation(SS.getBeginLoc());
+ Tok.setLocation(BeginLoc);
// In case the tokens were cached, have Preprocessor replace
// them with the annotation token.
Modified: cfe/trunk/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Sema/DeclSpec.cpp Mon Jul 6 22:58:14 2015
@@ -893,7 +893,6 @@ bool DeclSpec::SetConstexprSpec(SourceLo
return false;
}
-
bool DeclSpec::SetConceptSpec(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID) {
if (Concept_specified) {
@@ -906,30 +905,6 @@ bool DeclSpec::SetConceptSpec(SourceLoca
return false;
}
-void DeclSpec::setObjCTypeArgs(SourceLocation lAngleLoc,
- ArrayRef<ParsedType> args,
- SourceLocation rAngleLoc) {
- ParsedType *argsCopy = new ParsedType[args.size()];
- memcpy(argsCopy, args.data(), args.size() * sizeof(ParsedType));
- ObjCTypeArgs = llvm::makeArrayRef(argsCopy, args.size());
- ObjCTypeArgsLAngleLoc = lAngleLoc;
- ObjCTypeArgsRAngleLoc = rAngleLoc;
-}
-
-void DeclSpec::setProtocolQualifiers(Decl * const *Protos,
- unsigned NP,
- SourceLocation *ProtoLocs,
- SourceLocation LAngleLoc) {
- if (NP == 0) return;
- Decl **ProtoQuals = new Decl*[NP];
- memcpy(ProtoQuals, Protos, sizeof(Decl*)*NP);
- ProtocolQualifiers = ProtoQuals;
- ProtocolLocs = new SourceLocation[NP];
- memcpy(ProtocolLocs, ProtoLocs, sizeof(SourceLocation)*NP);
- NumProtocolQualifiers = NP;
- ProtocolLAngleLoc = LAngleLoc;
-}
-
void DeclSpec::SaveWrittenBuiltinSpecs() {
writtenBS.Sign = getTypeSpecSign();
writtenBS.Width = getTypeSpecWidth();
Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Mon Jul 6 22:58:14 2015
@@ -560,29 +560,19 @@ ActOnSuperClassOfClassInterface(Scope *S
// Handle type arguments on the superclass.
TypeSourceInfo *SuperClassTInfo = nullptr;
- if (!SuperTypeArgs.empty()) {
- // Form declaration specifiers naming this superclass type with
- // type arguments.
- AttributeFactory attrFactory;
- DeclSpec DS(attrFactory);
- const char* prevSpec; // unused
- unsigned diagID; // unused
- TypeSourceInfo *parsedTSInfo
- = Context.getTrivialTypeSourceInfo(SuperClassType, SuperLoc);
- ParsedType parsedType = CreateParsedType(SuperClassType, parsedTSInfo);
-
- DS.SetTypeSpecType(DeclSpec::TST_typename, SuperLoc, prevSpec, diagID,
- parsedType, Context.getPrintingPolicy());
- DS.SetRangeStart(SuperLoc);
- DS.SetRangeEnd(SuperLoc);
- DS.setObjCTypeArgs(SuperTypeArgsRange.getBegin(),
- SuperTypeArgs,
- SuperTypeArgsRange.getEnd());
-
- // Form the declarator.
- Declarator D(DS, Declarator::TypeNameContext);
-
- TypeResult fullSuperClassType = ActOnTypeName(S, D);
+ if (!SuperTypeArgs.empty()) {
+ TypeResult fullSuperClassType = actOnObjCTypeArgsAndProtocolQualifiers(
+ S,
+ SuperLoc,
+ CreateParsedType(SuperClassType,
+ nullptr),
+ SuperTypeArgsRange.getBegin(),
+ SuperTypeArgs,
+ SuperTypeArgsRange.getEnd(),
+ SourceLocation(),
+ { },
+ { },
+ SourceLocation());
if (!fullSuperClassType.isUsable())
return;
@@ -1230,21 +1220,26 @@ class ObjCTypeArgOrProtocolValidatorCCC
void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
Scope *S,
- DeclSpec &DS,
SourceLocation lAngleLoc,
ArrayRef<IdentifierInfo *> identifiers,
ArrayRef<SourceLocation> identifierLocs,
SourceLocation rAngleLoc,
+ SourceLocation &typeArgsLAngleLoc,
+ SmallVectorImpl<ParsedType> &typeArgs,
+ SourceLocation &typeArgsRAngleLoc,
+ SourceLocation &protocolLAngleLoc,
+ SmallVectorImpl<Decl *> &protocols,
+ SourceLocation &protocolRAngleLoc,
bool warnOnIncompleteProtocols) {
// Local function that updates the declaration specifiers with
// protocol information.
- SmallVector<ObjCProtocolDecl *, 4> protocols;
unsigned numProtocolsResolved = 0;
auto resolvedAsProtocols = [&] {
assert(numProtocolsResolved == identifiers.size() && "Unresolved protocols");
for (unsigned i = 0, n = protocols.size(); i != n; ++i) {
- ObjCProtocolDecl *&proto = protocols[i];
+ ObjCProtocolDecl *&proto
+ = reinterpret_cast<ObjCProtocolDecl *&>(protocols[i]);
// For an objc container, delay protocol reference checking until after we
// can set the objc decl as the availability context, otherwise check now.
if (!warnOnIncompleteProtocols) {
@@ -1268,12 +1263,9 @@ void Sema::actOnObjCTypeArgsOrProtocolQu
}
}
- DS.setProtocolQualifiers((Decl * const *)(protocols.data()),
- protocols.size(),
- const_cast<SourceLocation *>(identifierLocs.data()),
- lAngleLoc);
- if (rAngleLoc.isValid())
- DS.SetRangeEnd(rAngleLoc);
+ protocolLAngleLoc = lAngleLoc;
+ protocolRAngleLoc = rAngleLoc;
+ assert(protocols.size() == identifierLocs.size());
};
// Attempt to resolve all of the identifiers as protocols.
@@ -1370,20 +1362,24 @@ void Sema::actOnObjCTypeArgsOrProtocolQu
// Local function that updates the declaration specifiers with
// type argument information.
auto resolvedAsTypeDecls = [&] {
+ // We did not resolve these as protocols.
+ protocols.clear();
+
assert(numTypeDeclsResolved == identifiers.size() && "Unresolved type decl");
// Map type declarations to type arguments.
- SmallVector<ParsedType, 4> typeArgs;
for (unsigned i = 0, n = identifiers.size(); i != n; ++i) {
// Map type reference to a type.
TypeResult type = resolveTypeReference(typeDecls[i], identifierLocs[i]);
- if (!type.isUsable())
+ if (!type.isUsable()) {
+ typeArgs.clear();
return;
+ }
typeArgs.push_back(type.get());
}
- // Record the Objective-C type arguments.
- DS.setObjCTypeArgs(lAngleLoc, typeArgs, rAngleLoc);
+ typeArgsLAngleLoc = lAngleLoc;
+ typeArgsRAngleLoc = rAngleLoc;
};
// If all of the identifiers can be resolved as type names or
@@ -1432,6 +1428,8 @@ void Sema::actOnObjCTypeArgsOrProtocolQu
<< identifiers[0]
<< SourceRange(identifierLocs[0]);
+ protocols.clear();
+ typeArgs.clear();
return;
}
@@ -1483,6 +1481,8 @@ void Sema::actOnObjCTypeArgsOrProtocolQu
: lookupKind == LookupObjCProtocolName ? diag::err_undeclared_protocol
: diag::err_unknown_typename))
<< identifiers[i];
+ protocols.clear();
+ typeArgs.clear();
return;
}
Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Jul 6 22:58:14 2015
@@ -740,14 +740,18 @@ static void diagnoseAndRemoveTypeQualifi
/// Apply Objective-C type arguments to the given type.
static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
- ArrayRef<ParsedType> typeArgs,
- SourceRange typeArgsRange) {
+ ArrayRef<TypeSourceInfo *> typeArgs,
+ SourceRange typeArgsRange,
+ bool failOnError = false) {
// We can only apply type arguments to an Objective-C class type.
const auto *objcObjectType = type->getAs<ObjCObjectType>();
if (!objcObjectType || !objcObjectType->getInterface()) {
S.Diag(loc, diag::err_objc_type_args_non_class)
<< type
<< typeArgsRange;
+
+ if (failOnError)
+ return QualType();
return type;
}
@@ -758,6 +762,10 @@ static QualType applyObjCTypeArgs(Sema &
S.Diag(loc, diag::err_objc_type_args_non_parameterized_class)
<< objcClass->getDeclName()
<< FixItHint::CreateRemoval(typeArgsRange);
+
+ if (failOnError)
+ return QualType();
+
return type;
}
@@ -766,26 +774,20 @@ static QualType applyObjCTypeArgs(Sema &
S.Diag(loc, diag::err_objc_type_args_specialized_class)
<< type
<< FixItHint::CreateRemoval(typeArgsRange);
- return type;
- }
- // Make sure that we have the right number of type arguments.
- if (typeArgs.size() != typeParams->size()) {
- S.Diag(loc, diag::err_objc_type_args_wrong_arity)
- << (typeArgs.size() < typeParams->size())
- << objcClass->getDeclName()
- << (unsigned)typeArgs.size()
- << (unsigned)typeParams->size();
- S.Diag(objcClass->getLocation(), diag::note_previous_decl)
- << objcClass;
+ if (failOnError)
+ return QualType();
+
return type;
}
// Check the type arguments.
SmallVector<QualType, 4> finalTypeArgs;
+ unsigned numTypeParams = typeParams->size();
+ bool anyPackExpansions = false;
for (unsigned i = 0, n = typeArgs.size(); i != n; ++i) {
- TypeSourceInfo *typeArgInfo = nullptr;
- QualType typeArg = S.GetTypeFromParser(typeArgs[i], &typeArgInfo);
+ TypeSourceInfo *typeArgInfo = typeArgs[i];
+ QualType typeArg = typeArgInfo->getType();
// Type arguments cannot explicitly specify nullability.
if (auto nullability = AttributedType::stripOuterNullability(typeArg)) {
@@ -801,10 +803,42 @@ static QualType applyObjCTypeArgs(Sema &
finalTypeArgs.push_back(typeArg);
+ if (typeArg->getAs<PackExpansionType>())
+ anyPackExpansions = true;
+
+ // Find the corresponding type parameter, if there is one.
+ ObjCTypeParamDecl *typeParam = nullptr;
+ if (!anyPackExpansions) {
+ if (i < numTypeParams) {
+ typeParam = typeParams->begin()[i];
+ } else {
+ // Too many arguments.
+ S.Diag(loc, diag::err_objc_type_args_wrong_arity)
+ << false
+ << objcClass->getDeclName()
+ << (unsigned)typeArgs.size()
+ << numTypeParams;
+ S.Diag(objcClass->getLocation(), diag::note_previous_decl)
+ << objcClass;
+
+ if (failOnError)
+ return QualType();
+
+ return type;
+ }
+ }
+
// Objective-C object pointer types must be substitutable for the bounds.
if (const auto *typeArgObjC = typeArg->getAs<ObjCObjectPointerType>()) {
+ // If we don't have a type parameter to match against, assume
+ // everything is fine. There was a prior pack expansion that
+ // means we won't be able to match anything.
+ if (!typeParam) {
+ assert(anyPackExpansions && "Too many arguments?");
+ continue;
+ }
+
// Retrieve the bound.
- ObjCTypeParamDecl *typeParam = typeParams->begin()[i];
QualType bound = typeParam->getUnderlyingType();
const auto *boundObjC = bound->getAs<ObjCObjectPointerType>();
@@ -826,13 +860,23 @@ static QualType applyObjCTypeArgs(Sema &
S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here)
<< typeParam->getDeclName();
+ if (failOnError)
+ return QualType();
+
return type;
}
// Block pointer types are permitted for unqualified 'id' bounds.
if (typeArg->isBlockPointerType()) {
+ // If we don't have a type parameter to match against, assume
+ // everything is fine. There was a prior pack expansion that
+ // means we won't be able to match anything.
+ if (!typeParam) {
+ assert(anyPackExpansions && "Too many arguments?");
+ continue;
+ }
+
// Retrieve the bound.
- ObjCTypeParamDecl *typeParam = typeParams->begin()[i];
QualType bound = typeParam->getUnderlyingType();
if (bound->isBlockCompatibleObjCPointerType(S.Context))
continue;
@@ -844,6 +888,9 @@ static QualType applyObjCTypeArgs(Sema &
S.Diag(typeParam->getLocation(), diag::note_objc_type_param_here)
<< typeParam->getDeclName();
+ if (failOnError)
+ return QualType();
+
return type;
}
@@ -857,6 +904,26 @@ static QualType applyObjCTypeArgs(Sema &
diag::err_objc_type_arg_not_id_compatible)
<< typeArg
<< typeArgInfo->getTypeLoc().getSourceRange();
+
+ if (failOnError)
+ return QualType();
+
+ return type;
+ }
+
+ // Make sure we didn't have the wrong number of arguments.
+ if (!anyPackExpansions && finalTypeArgs.size() != numTypeParams) {
+ S.Diag(loc, diag::err_objc_type_args_wrong_arity)
+ << (typeArgs.size() < typeParams->size())
+ << objcClass->getDeclName()
+ << (unsigned)finalTypeArgs.size()
+ << (unsigned)numTypeParams;
+ S.Diag(objcClass->getLocation(), diag::note_previous_decl)
+ << objcClass;
+
+ if (failOnError)
+ return QualType();
+
return type;
}
@@ -868,7 +935,8 @@ static QualType applyObjCTypeArgs(Sema &
static QualType applyObjCProtocolQualifiers(
Sema &S, SourceLocation loc, SourceRange range, QualType type,
ArrayRef<ObjCProtocolDecl *> protocols,
- const SourceLocation *protocolLocs) {
+ const SourceLocation *protocolLocs,
+ bool failOnError = false) {
ASTContext &ctx = S.Context;
if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){
// FIXME: Check for protocols to which the class type is already
@@ -902,9 +970,185 @@ static QualType applyObjCProtocolQualifi
S.Diag(loc, diag::err_invalid_protocol_qualifiers)
<< range;
+
+ if (failOnError)
+ return QualType();
+
return type;
}
+QualType Sema::BuildObjCObjectType(QualType BaseType,
+ SourceLocation Loc,
+ SourceLocation TypeArgsLAngleLoc,
+ ArrayRef<TypeSourceInfo *> TypeArgs,
+ SourceLocation TypeArgsRAngleLoc,
+ SourceLocation ProtocolLAngleLoc,
+ ArrayRef<ObjCProtocolDecl *> Protocols,
+ ArrayRef<SourceLocation> ProtocolLocs,
+ SourceLocation ProtocolRAngleLoc,
+ bool FailOnError) {
+ QualType Result = BaseType;
+ if (!TypeArgs.empty()) {
+ Result = applyObjCTypeArgs(*this, Loc, Result, TypeArgs,
+ SourceRange(TypeArgsLAngleLoc,
+ TypeArgsRAngleLoc),
+ FailOnError);
+ if (FailOnError && Result.isNull())
+ return QualType();
+ }
+
+ if (!Protocols.empty()) {
+ Result = applyObjCProtocolQualifiers(*this, Loc,
+ SourceRange(ProtocolLAngleLoc,
+ ProtocolRAngleLoc),
+ Result, Protocols,
+ ProtocolLocs.data(),
+ FailOnError);
+ if (FailOnError && Result.isNull())
+ return QualType();
+ }
+
+ return Result;
+}
+
+TypeResult Sema::actOnObjCProtocolQualifierType(
+ SourceLocation lAngleLoc,
+ ArrayRef<Decl *> protocols,
+ ArrayRef<SourceLocation> protocolLocs,
+ SourceLocation rAngleLoc) {
+ // Form id<protocol-list>.
+ QualType Result = Context.getObjCObjectType(
+ Context.ObjCBuiltinIdTy, { },
+ llvm::makeArrayRef(
+ (ObjCProtocolDecl * const *)protocols.data(),
+ protocols.size()));
+ Result = Context.getObjCObjectPointerType(Result);
+
+ TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
+ TypeLoc ResultTL = ResultTInfo->getTypeLoc();
+
+ auto ObjCObjectPointerTL = ResultTL.castAs<ObjCObjectPointerTypeLoc>();
+ ObjCObjectPointerTL.setStarLoc(SourceLocation()); // implicit
+
+ auto ObjCObjectTL = ObjCObjectPointerTL.getPointeeLoc()
+ .castAs<ObjCObjectTypeLoc>();
+ ObjCObjectTL.setHasBaseTypeAsWritten(false);
+ ObjCObjectTL.getBaseLoc().initialize(Context, SourceLocation());
+
+ // No type arguments.
+ ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation());
+ ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation());
+
+ // Fill in protocol qualifiers.
+ ObjCObjectTL.setProtocolLAngleLoc(lAngleLoc);
+ ObjCObjectTL.setProtocolRAngleLoc(rAngleLoc);
+ for (unsigned i = 0, n = protocols.size(); i != n; ++i)
+ ObjCObjectTL.setProtocolLoc(i, protocolLocs[i]);
+
+ // We're done. Return the completed type to the parser.
+ return CreateParsedType(Result, ResultTInfo);
+}
+
+TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers(
+ Scope *S,
+ SourceLocation Loc,
+ ParsedType BaseType,
+ SourceLocation TypeArgsLAngleLoc,
+ ArrayRef<ParsedType> TypeArgs,
+ SourceLocation TypeArgsRAngleLoc,
+ SourceLocation ProtocolLAngleLoc,
+ ArrayRef<Decl *> Protocols,
+ ArrayRef<SourceLocation> ProtocolLocs,
+ SourceLocation ProtocolRAngleLoc) {
+ TypeSourceInfo *BaseTypeInfo = nullptr;
+ QualType T = GetTypeFromParser(BaseType, &BaseTypeInfo);
+ if (T.isNull())
+ return true;
+
+ // Handle missing type-source info.
+ if (!BaseTypeInfo)
+ BaseTypeInfo = Context.getTrivialTypeSourceInfo(T, Loc);
+
+ // Extract type arguments.
+ SmallVector<TypeSourceInfo *, 4> ActualTypeArgInfos;
+ for (unsigned i = 0, n = TypeArgs.size(); i != n; ++i) {
+ TypeSourceInfo *TypeArgInfo = nullptr;
+ QualType TypeArg = GetTypeFromParser(TypeArgs[i], &TypeArgInfo);
+ if (TypeArg.isNull()) {
+ ActualTypeArgInfos.clear();
+ break;
+ }
+
+ assert(TypeArgInfo && "No type source info?");
+ ActualTypeArgInfos.push_back(TypeArgInfo);
+ }
+
+ // Build the object type.
+ QualType Result = BuildObjCObjectType(
+ T,
+ BaseTypeInfo->getTypeLoc().getSourceRange().getBegin(),
+ TypeArgsLAngleLoc,
+ ActualTypeArgInfos,
+ TypeArgsRAngleLoc,
+ ProtocolLAngleLoc,
+ llvm::makeArrayRef((ObjCProtocolDecl **)Protocols.data(),
+ Protocols.size()),
+ ProtocolLocs,
+ ProtocolRAngleLoc,
+ /*FailOnError=*/false);
+
+ if (Result == T)
+ return BaseType;
+
+ // Create source information for this type.
+ TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result);
+ TypeLoc ResultTL = ResultTInfo->getTypeLoc();
+
+ // For id<Proto1, Proto2> or Class<Proto1, Proto2>, we'll have an
+ // object pointer type. Fill in source information for it.
+ if (auto ObjCObjectPointerTL = ResultTL.getAs<ObjCObjectPointerTypeLoc>()) {
+ // The '*' is implicit.
+ ObjCObjectPointerTL.setStarLoc(SourceLocation());
+ ResultTL = ObjCObjectPointerTL.getPointeeLoc();
+ }
+
+ auto ObjCObjectTL = ResultTL.castAs<ObjCObjectTypeLoc>();
+
+ // Type argument information.
+ if (ObjCObjectTL.getNumTypeArgs() > 0) {
+ assert(ObjCObjectTL.getNumTypeArgs() == ActualTypeArgInfos.size());
+ ObjCObjectTL.setTypeArgsLAngleLoc(TypeArgsLAngleLoc);
+ ObjCObjectTL.setTypeArgsRAngleLoc(TypeArgsRAngleLoc);
+ for (unsigned i = 0, n = ActualTypeArgInfos.size(); i != n; ++i)
+ ObjCObjectTL.setTypeArgTInfo(i, ActualTypeArgInfos[i]);
+ } else {
+ ObjCObjectTL.setTypeArgsLAngleLoc(SourceLocation());
+ ObjCObjectTL.setTypeArgsRAngleLoc(SourceLocation());
+ }
+
+ // Protocol qualifier information.
+ if (ObjCObjectTL.getNumProtocols() > 0) {
+ assert(ObjCObjectTL.getNumProtocols() == Protocols.size());
+ ObjCObjectTL.setProtocolLAngleLoc(ProtocolLAngleLoc);
+ ObjCObjectTL.setProtocolRAngleLoc(ProtocolRAngleLoc);
+ for (unsigned i = 0, n = Protocols.size(); i != n; ++i)
+ ObjCObjectTL.setProtocolLoc(i, ProtocolLocs[i]);
+ } else {
+ ObjCObjectTL.setProtocolLAngleLoc(SourceLocation());
+ ObjCObjectTL.setProtocolRAngleLoc(SourceLocation());
+ }
+
+ // Base type.
+ ObjCObjectTL.setHasBaseTypeAsWritten(true);
+ if (ObjCObjectTL.getType() == T)
+ ObjCObjectTL.getBaseLoc().initializeFullCopy(BaseTypeInfo->getTypeLoc());
+ else
+ ObjCObjectTL.getBaseLoc().initialize(Context, Loc);
+
+ // We're done. Return the completed type to the parser.
+ return CreateParsedType(Result, ResultTInfo);
+}
+
/// \brief Convert the specified declspec to the appropriate type
/// object.
/// \param state Specifies the declarator containing the declaration specifier
@@ -968,16 +1212,6 @@ static QualType ConvertDeclSpecToType(Ty
Result = Context.Char32Ty;
break;
case DeclSpec::TST_unspecified:
- // "<proto1,proto2>" is an objc qualified ID with a missing id.
- if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, { },
- llvm::makeArrayRef(
- (ObjCProtocolDecl*const*)PQ,
- DS.getNumProtocolQualifiers()));
- Result = Context.getObjCObjectPointerType(Result);
- break;
- }
-
// If this is a missing declspec in a block literal return context, then it
// is inferred from the return statements inside the block.
// The declspec is always missing in a lambda expr context; it is either
@@ -1161,21 +1395,6 @@ static QualType ConvertDeclSpecToType(Ty
declarator.setInvalidType(true);
}
}
- } else {
- // Apply Objective-C type arguments.
- if (DS.hasObjCTypeArgs()) {
- Result = applyObjCTypeArgs(S, DeclLoc, Result, DS.getObjCTypeArgs(),
- DS.getObjCTypeArgsRange());
- }
-
- // Apply Objective-C protocol qualifiers.
- if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- Result = applyObjCProtocolQualifiers(
- S, DeclLoc, DS.getSourceRange(), Result,
- llvm::makeArrayRef((ObjCProtocolDecl * const *)PQ,
- DS.getNumProtocolQualifiers()),
- DS.getProtocolLocs());
- }
}
// TypeQuals handled by caller.
@@ -4282,47 +4501,14 @@ namespace {
TL.setNameEndLoc(DS.getLocEnd());
}
void VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) {
- // Handle the base type, which might not have been written explicitly.
- if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
- TL.setHasBaseTypeAsWritten(false);
- TL.getBaseLoc().initialize(Context, SourceLocation());
- } else {
- TL.setHasBaseTypeAsWritten(true);
- Visit(TL.getBaseLoc());
- }
-
- // Type arguments.
- if (TL.getNumTypeArgs() > 0) {
- assert(TL.getNumTypeArgs() == DS.getObjCTypeArgs().size());
- TL.setTypeArgsLAngleLoc(DS.getObjCTypeArgsLAngleLoc());
- TL.setTypeArgsRAngleLoc(DS.getObjCTypeArgsRAngleLoc());
- for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) {
- TypeSourceInfo *typeArgInfo = nullptr;
- (void)Sema::GetTypeFromParser(DS.getObjCTypeArgs()[i], &typeArgInfo);
- TL.setTypeArgTInfo(i, typeArgInfo);
- }
- } else {
- TL.setTypeArgsLAngleLoc(SourceLocation());
- TL.setTypeArgsRAngleLoc(SourceLocation());
- }
-
- // Protocol qualifiers.
- if (DS.getProtocolQualifiers()) {
- assert(TL.getNumProtocols() > 0);
- assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
- TL.setProtocolLAngleLoc(DS.getProtocolLAngleLoc());
- TL.setProtocolRAngleLoc(DS.getSourceRange().getEnd());
- for (unsigned i = 0, e = DS.getNumProtocolQualifiers(); i != e; ++i)
- TL.setProtocolLoc(i, DS.getProtocolLocs()[i]);
- } else {
- assert(TL.getNumProtocols() == 0);
- TL.setProtocolLAngleLoc(SourceLocation());
- TL.setProtocolRAngleLoc(SourceLocation());
- }
+ TypeSourceInfo *RepTInfo = nullptr;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo);
+ TL.copy(RepTInfo->getTypeLoc());
}
void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
- TL.setStarLoc(SourceLocation());
- Visit(TL.getPointeeLoc());
+ TypeSourceInfo *RepTInfo = nullptr;
+ Sema::GetTypeFromParser(DS.getRepAsType(), &RepTInfo);
+ TL.copy(RepTInfo->getTypeLoc());
}
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
TypeSourceInfo *TInfo = nullptr;
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Mon Jul 6 22:58:14 2015
@@ -685,6 +685,27 @@ public:
QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType,
SourceLocation Sigil);
+ /// \brief Build an Objective-C object type.
+ ///
+ /// By default, performs semantic analysis when building the object type.
+ /// Subclasses may override this routine to provide different behavior.
+ QualType RebuildObjCObjectType(QualType BaseType,
+ SourceLocation Loc,
+ SourceLocation TypeArgsLAngleLoc,
+ ArrayRef<TypeSourceInfo *> TypeArgs,
+ SourceLocation TypeArgsRAngleLoc,
+ SourceLocation ProtocolLAngleLoc,
+ ArrayRef<ObjCProtocolDecl *> Protocols,
+ ArrayRef<SourceLocation> ProtocolLocs,
+ SourceLocation ProtocolRAngleLoc);
+
+ /// \brief Build a new Objective-C object pointer type given the pointee type.
+ ///
+ /// By default, directly builds the pointer type, with no additional semantic
+ /// analysis.
+ QualType RebuildObjCObjectPointerType(QualType PointeeType,
+ SourceLocation Star);
+
/// \brief Build a new array type given the element type, size
/// modifier, size of the array (if known), size expression, and index type
/// qualifiers.
@@ -5606,18 +5627,153 @@ template<typename Derived>
QualType
TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
ObjCObjectTypeLoc TL) {
- // ObjCObjectType is never dependent.
- TLB.pushFullCopy(TL);
- return TL.getType();
+ // Transform base type.
+ QualType BaseType = getDerived().TransformType(TLB, TL.getBaseLoc());
+ if (BaseType.isNull())
+ return QualType();
+
+ bool AnyChanged = BaseType != TL.getBaseLoc().getType();
+
+ // Transform type arguments.
+ SmallVector<TypeSourceInfo *, 4> NewTypeArgInfos;
+ for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) {
+ TypeSourceInfo *TypeArgInfo = TL.getTypeArgTInfo(i);
+ TypeLoc TypeArgLoc = TypeArgInfo->getTypeLoc();
+ QualType TypeArg = TypeArgInfo->getType();
+ if (auto PackExpansionLoc = TypeArgLoc.getAs<PackExpansionTypeLoc>()) {
+ AnyChanged = true;
+
+ // We have a pack expansion. Instantiate it.
+ const auto *PackExpansion = PackExpansionLoc.getType()
+ ->castAs<PackExpansionType>();
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(),
+ Unexpanded);
+ assert(!Unexpanded.empty() && "Pack expansion without parameter packs?");
+
+ // Determine whether the set of unexpanded parameter packs can
+ // and should be expanded.
+ TypeLoc PatternLoc = PackExpansionLoc.getPatternLoc();
+ bool Expand = false;
+ bool RetainExpansion = false;
+ Optional<unsigned> NumExpansions = PackExpansion->getNumExpansions();
+ if (getDerived().TryExpandParameterPacks(
+ PackExpansionLoc.getEllipsisLoc(), PatternLoc.getSourceRange(),
+ Unexpanded, Expand, RetainExpansion, NumExpansions))
+ return QualType();
+
+ if (!Expand) {
+ // We can't expand this pack expansion into separate arguments yet;
+ // just substitute into the pattern and create a new pack expansion
+ // type.
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1);
+
+ TypeLocBuilder TypeArgBuilder;
+ TypeArgBuilder.reserve(PatternLoc.getFullDataSize());
+ QualType NewPatternType = getDerived().TransformType(TypeArgBuilder,
+ PatternLoc);
+ if (NewPatternType.isNull())
+ return QualType();
+
+ QualType NewExpansionType = SemaRef.Context.getPackExpansionType(
+ NewPatternType, NumExpansions);
+ auto NewExpansionLoc = TLB.push<PackExpansionTypeLoc>(NewExpansionType);
+ NewExpansionLoc.setEllipsisLoc(PackExpansionLoc.getEllipsisLoc());
+ NewTypeArgInfos.push_back(
+ TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewExpansionType));
+ continue;
+ }
+
+ // Substitute into the pack expansion pattern for each slice of the
+ // pack.
+ for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), ArgIdx);
+
+ TypeLocBuilder TypeArgBuilder;
+ TypeArgBuilder.reserve(PatternLoc.getFullDataSize());
+
+ QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder,
+ PatternLoc);
+ if (NewTypeArg.isNull())
+ return QualType();
+
+ NewTypeArgInfos.push_back(
+ TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg));
+ }
+
+ continue;
+ }
+
+ TypeLocBuilder TypeArgBuilder;
+ TypeArgBuilder.reserve(TypeArgLoc.getFullDataSize());
+ QualType NewTypeArg = getDerived().TransformType(TypeArgBuilder, TypeArgLoc);
+ if (NewTypeArg.isNull())
+ return QualType();
+
+ // If nothing changed, just keep the old TypeSourceInfo.
+ if (NewTypeArg == TypeArg) {
+ NewTypeArgInfos.push_back(TypeArgInfo);
+ continue;
+ }
+
+ NewTypeArgInfos.push_back(
+ TypeArgBuilder.getTypeSourceInfo(SemaRef.Context, NewTypeArg));
+ AnyChanged = true;
+ }
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() || AnyChanged) {
+ // Rebuild the type.
+ Result = getDerived().RebuildObjCObjectType(
+ BaseType,
+ TL.getLocStart(),
+ TL.getTypeArgsLAngleLoc(),
+ NewTypeArgInfos,
+ TL.getTypeArgsRAngleLoc(),
+ TL.getProtocolLAngleLoc(),
+ llvm::makeArrayRef(TL.getTypePtr()->qual_begin(),
+ TL.getNumProtocols()),
+ TL.getProtocolLocs(),
+ TL.getProtocolRAngleLoc());
+
+ if (Result.isNull())
+ return QualType();
+ }
+
+ ObjCObjectTypeLoc NewT = TLB.push<ObjCObjectTypeLoc>(Result);
+ assert(TL.hasBaseTypeAsWritten() && "Can't be dependent");
+ NewT.setHasBaseTypeAsWritten(true);
+ NewT.setTypeArgsLAngleLoc(TL.getTypeArgsLAngleLoc());
+ for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i)
+ NewT.setTypeArgTInfo(i, NewTypeArgInfos[i]);
+ NewT.setTypeArgsRAngleLoc(TL.getTypeArgsRAngleLoc());
+ NewT.setProtocolLAngleLoc(TL.getProtocolLAngleLoc());
+ for (unsigned i = 0, n = TL.getNumProtocols(); i != n; ++i)
+ NewT.setProtocolLoc(i, TL.getProtocolLoc(i));
+ NewT.setProtocolRAngleLoc(TL.getProtocolRAngleLoc());
+ return Result;
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
ObjCObjectPointerTypeLoc TL) {
- // ObjCObjectPointerType is never dependent.
- TLB.pushFullCopy(TL);
- return TL.getType();
+ QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc());
+ if (PointeeType.isNull())
+ return QualType();
+
+ QualType Result = TL.getType();
+ if (getDerived().AlwaysRebuild() ||
+ PointeeType != TL.getPointeeLoc().getType()) {
+ Result = getDerived().RebuildObjCObjectPointerType(PointeeType,
+ TL.getStarLoc());
+ if (Result.isNull())
+ return QualType();
+ }
+
+ ObjCObjectPointerTypeLoc NewT = TLB.push<ObjCObjectPointerTypeLoc>(Result);
+ NewT.setStarLoc(TL.getStarLoc());
+ return Result;
}
//===----------------------------------------------------------------------===//
@@ -10494,6 +10650,31 @@ TreeTransform<Derived>::RebuildMemberPoi
}
template<typename Derived>
+QualType TreeTransform<Derived>::RebuildObjCObjectType(
+ QualType BaseType,
+ SourceLocation Loc,
+ SourceLocation TypeArgsLAngleLoc,
+ ArrayRef<TypeSourceInfo *> TypeArgs,
+ SourceLocation TypeArgsRAngleLoc,
+ SourceLocation ProtocolLAngleLoc,
+ ArrayRef<ObjCProtocolDecl *> Protocols,
+ ArrayRef<SourceLocation> ProtocolLocs,
+ SourceLocation ProtocolRAngleLoc) {
+ return SemaRef.BuildObjCObjectType(BaseType, Loc, TypeArgsLAngleLoc,
+ TypeArgs, TypeArgsRAngleLoc,
+ ProtocolLAngleLoc, Protocols, ProtocolLocs,
+ ProtocolRAngleLoc,
+ /*FailOnError=*/true);
+}
+
+template<typename Derived>
+QualType TreeTransform<Derived>::RebuildObjCObjectPointerType(
+ QualType PointeeType,
+ SourceLocation Star) {
+ return SemaRef.Context.getObjCObjectPointerType(PointeeType);
+}
+
+template<typename Derived>
QualType
TreeTransform<Derived>::RebuildArrayType(QualType ElementType,
ArrayType::ArraySizeModifier SizeMod,
Modified: cfe/trunk/test/Index/annotate-parameterized-classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-parameterized-classes.m?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/test/Index/annotate-parameterized-classes.m (original)
+++ cfe/trunk/test/Index/annotate-parameterized-classes.m Mon Jul 6 22:58:14 2015
@@ -17,19 +17,15 @@ typedef A<id<NSObject>, NSObject *> ASpe
// RUN: c-index-test -test-annotate-tokens=%s:7:1:9:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-INTERFACE-DECL %s
// CHECK-INTERFACE-DECL: Identifier: "T" [7:14 - 7:15] TemplateTypeParameter=T:7:14
-// FIXME: Should be a type reference
-// CHECK-INTERFACE-DECL: Identifier: "id" [7:18 - 7:20] TemplateTypeParameter=T:7:14
+// CHECK-INTERFACE-DECL: Identifier: "id" [7:18 - 7:20] TypeRef=id:0:0
// CHECK-INTERFACE-DECL: Identifier: "U" [7:22 - 7:23] TemplateTypeParameter=U:7:22
-// FIXME: Should be a class reference
-// CHECK-INTERFACE-DECL: Identifier: "NSObject" [7:26 - 7:34] TemplateTypeParameter=U:7:22
+// CHECK-INTERFACE-DECL: Identifier: "NSObject" [7:26 - 7:34] ObjCClassRef=NSObject:4:12
// RUN: c-index-test -test-annotate-tokens=%s:10:1:12:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-CATEGORY-DECL %s
// CHECK-CATEGORY-DECL: Identifier: "T" [10:14 - 10:15] TemplateTypeParameter=T:10:14
-// FIXME: Should be a type reference
-// CHECK-CATEGORY-DECL: Identifier: "id" [10:18 - 10:20] TemplateTypeParameter=T:10:14
+// CHECK-CATEGORY-DECL: Identifier: "id" [10:18 - 10:20] TypeRef=id:0:0
// CHECK-CATEGORY-DECL: Identifier: "U" [10:22 - 10:23] TemplateTypeParameter=U:10:22
-// FIXME: Should be a class reference
-// CHECK-CATEGORY-DECL: Identifier: "NSObject" [10:26 - 10:34] TemplateTypeParameter=U:10:22
+// CHECK-CATEGORY-DECL: Identifier: "NSObject" [10:26 - 10:34] ObjCClassRef=NSObject:4:12
// RUN: c-index-test -test-annotate-tokens=%s:13:1:14:1 %s -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-SPECIALIZATION %s
// CHECK-SPECIALIZATION: Identifier: "id" [13:11 - 13:13] TypeRef=id:0:0
Modified: cfe/trunk/test/Index/annotate-tokens.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/annotate-tokens.m?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/test/Index/annotate-tokens.m (original)
+++ cfe/trunk/test/Index/annotate-tokens.m Mon Jul 6 22:58:14 2015
@@ -152,6 +152,7 @@ static Rdar8595462_A * Rdar8595462_stati
@property int extensionProperty;
@end
+typedef id<Proto> *proto_ptr;
// RUN: c-index-test -test-annotate-tokens=%s:1:1:118:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' | FileCheck %s
// CHECK: Punctuation: "@" [1:1 - 1:2] ObjCInterfaceDecl=Foo:1:12
@@ -596,3 +597,9 @@ static Rdar8595462_A * Rdar8595462_stati
// CHECK-PROP: Keyword: "property" [152:4 - 152:12] ObjCPropertyDecl=extensionProperty:152:17
// CHECK-PROP: Keyword: "int" [152:13 - 152:16] ObjCPropertyDecl=extensionProperty:152:17
// CHECK-PROP: Identifier: "extensionProperty" [152:17 - 152:34] ObjCPropertyDecl=extensionProperty:152:17
+
+// RUN: c-index-test -test-annotate-tokens=%s:155:1:156:1 %s -DIBOutlet='__attribute__((iboutlet))' -DIBAction='void)__attribute__((ibaction)' -target x86_64-apple-macosx10.7.0 | FileCheck -check-prefix=CHECK-ID-PROTO %s
+// CHECK-ID-PROTO: Identifier: "id" [155:9 - 155:11] TypeRef=id:0:0
+// CHECK-ID-PROTO: Punctuation: "<" [155:11 - 155:12] TypedefDecl=proto_ptr:155:20 (Definition)
+// CHECK-ID-PROTO: Identifier: "Proto" [155:12 - 155:17] ObjCProtocolRef=Proto
+// CHECK-ID-PROTO: Punctuation: ">" [155:17 - 155:18] TypedefDecl=proto_ptr:155:20 (Definition)
Modified: cfe/trunk/test/Parser/placeholder-recovery.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/placeholder-recovery.m?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/test/Parser/placeholder-recovery.m (original)
+++ cfe/trunk/test/Parser/placeholder-recovery.m Mon Jul 6 22:58:14 2015
@@ -3,10 +3,9 @@
// FIXME: We could do much better with this, if we recognized
// placeholders somehow. However, we're content with not generating
// bogus 'archaic' warnings with bad location info.
- at protocol <#protocol name#> <NSObject> // expected-error 2{{expected identifier}} \
-// expected-error{{cannot find protocol declaration for 'NSObject'}} \
+ at protocol <#protocol name#> <NSObject> // expected-error {{expected identifier or '('}} \
+// expected-error 2{{expected identifier}} \
// expected-warning{{protocol has no object type specified; defaults to qualified 'id'}}
+<#methods#>
-<#methods#> // expected-error{{expected identifier}}
-
- at end // expected-error{{prefix attribute}}
+ at end
Modified: cfe/trunk/test/SemaObjC/parameterized_classes.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/parameterized_classes.m?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/parameterized_classes.m (original)
+++ cfe/trunk/test/SemaObjC/parameterized_classes.m Mon Jul 6 22:58:14 2015
@@ -1,5 +1,9 @@
// RUN: %clang_cc1 -fblocks %s -verify
+#if !__has_feature(objc_generics)
+# error Compiler does not support Objective-C generics?
+#endif
+
@protocol NSObject // expected-note{{'NSObject' declared here}}
@end
@@ -255,14 +259,14 @@ typedef PC15<int (^)(int, int), // block
typedef PC15<NSObject *, NSObject *, id<NSCopying>> typeArgs8;
typedef PC15<NSObject *, NSObject *,
- NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisy the bound ('id<NSCopying>') of type parameter 'V'}}
+ NSObject *> typeArgs8b; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'V'}}
typedef PC15<id,
- id, // expected-error{{type argument 'id' does not satisy the bound ('NSObject *') of type parameter 'U'}}
+ id, // expected-error{{type argument 'id' does not satisfy the bound ('NSObject *') of type parameter 'U'}}
id> typeArgs9;
typedef PC15<id, NSObject *,
- id> typeArgs10; // expected-error{{type argument 'id' does not satisy the bound ('id<NSCopying>') of type parameter 'V'}}
+ id> typeArgs10; // expected-error{{type argument 'id' does not satisfy the bound ('id<NSCopying>') of type parameter 'V'}}
typedef PC15<id,
int (^)(int, int), // okay
@@ -306,7 +310,7 @@ void testSpecializedTypePrinting() {
@interface PC23<T : NSObject *> : PC1<T, U> // expected-error{{unknown type name 'U'}}
@end
- at interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka 'id') does not satisy the bound ('NSObject *') of type parameter 'U'}}
+ at interface PC24<T> : PC1<T, T> // expected-error{{type argument 'T' (aka 'id') does not satisfy the bound ('NSObject *') of type parameter 'U'}}
@end
@interface NSFoo : PC1<NSObject *, NSObject *> // okay
Modified: cfe/trunk/test/SemaObjC/protocol-archane.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/protocol-archane.m?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/protocol-archane.m (original)
+++ cfe/trunk/test/SemaObjC/protocol-archane.m Mon Jul 6 22:58:14 2015
@@ -40,3 +40,7 @@ Class <SomeProtocol> UnfortunateGCCExten
- (void)crashWith:(<Broken>)a { // expected-warning {{protocol has no object type specified; defaults to qualified 'id'}}
}
@end
+
+typedef <SomeProtocol> id TwoTypeSpecs; // expected-warning{{no object type specified}}
+// expected-error at -1{{typedef redefinition with different types ('id<SomeProtocol>' vs 'id')}}
+// expected-error at -2{{expected ';' after top level declarator}}
Added: cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm?rev=241545&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm (added)
+++ cfe/trunk/test/SemaObjCXX/parameterized_classes_subst.mm Mon Jul 6 22:58:14 2015
@@ -0,0 +1,407 @@
+// RUN: %clang_cc1 -fblocks -fsyntax-only -std=c++11 %s -verify
+//
+// Test the substitution of type arguments for type parameters when
+// using parameterized classes in Objective-C.
+
+__attribute__((objc_root_class))
+ at interface NSObject
++ (instancetype)alloc;
+- (instancetype)init;
+ at end
+
+ at protocol NSCopying
+ at end
+
+ at interface NSString : NSObject <NSCopying>
+ at end
+
+ at interface NSNumber : NSObject <NSCopying>
+ at end
+
+ at interface NSArray<T> : NSObject <NSCopying> {
+ at public
+ T *data; // don't try this at home
+}
+- (T)objectAtIndexedSubscript:(int)index;
++ (NSArray<T> *)array;
+ at property (copy,nonatomic) T lastObject;
+ at end
+
+ at interface NSMutableArray<T> : NSArray<T>
+-(instancetype)initWithArray:(NSArray<T> *)array; // expected-note{{passing argument}}
+- (void)setObject:(T)object atIndexedSubscript:(int)index; // expected-note 2{{passing argument to parameter 'object' here}}
+ at end
+
+ at interface NSStringArray : NSArray<NSString *>
+ at end
+
+ at interface NSSet<T> : NSObject <NSCopying>
+- (T)firstObject;
+ at property (nonatomic, copy) NSArray<T> *allObjects;
+ at end
+
+// Parameterized inheritance (simple case)
+ at interface NSMutableSet<U : id<NSCopying>> : NSSet<U>
+- (void)addObject:(U)object; // expected-note 7{{passing argument to parameter 'object' here}}
+ at end
+
+ at interface Widget : NSObject <NSCopying>
+ at end
+
+// Non-parameterized class inheriting from a specialization of a
+// parameterized class.
+ at interface WidgetSet : NSMutableSet<Widget *>
+ at end
+
+// Parameterized inheritance with a more interesting transformation in
+// the specialization.
+ at interface MutableSetOfArrays<T> : NSMutableSet<NSArray<T>*>
+ at end
+
+// Inheriting from an unspecialized form of a parameterized type.
+ at interface UntypedMutableSet : NSMutableSet
+ at end
+
+ at interface Window : NSObject
+ at end
+
+ at interface NSDictionary<K, V> : NSObject <NSCopying>
+- (V)objectForKeyedSubscript:(K)key; // expected-note 2{{parameter 'key'}}
+ at end
+
+ at interface NSMutableDictionary<K : id<NSCopying>, V> : NSDictionary<K, V> // expected-note 2{{type parameter 'K' declared here}} \
+// expected-note 2{{'NSMutableDictionary' declared here}}
+- (void)setObject:(V)object forKeyedSubscript:(K)key;
+// expected-note at -1 {{parameter 'object' here}}
+// expected-note at -2 {{parameter 'object' here}}
+// expected-note at -3 {{parameter 'key' here}}
+// expected-note at -4 {{parameter 'key' here}}
+
+ at property (strong) K someRandomKey;
+ at end
+
+ at interface WindowArray : NSArray<Window *>
+ at end
+
+ at interface NSSet<T> (Searching)
+- (T)findObject:(T)object;
+ at end
+
+
+// --------------------------------------------------------------------------
+// Message sends.
+// --------------------------------------------------------------------------
+void test_message_send_result(
+ NSSet<NSString *> *stringSet,
+ NSMutableSet<NSString *> *mutStringSet,
+ WidgetSet *widgetSet,
+ UntypedMutableSet *untypedMutSet,
+ MutableSetOfArrays<NSString *> *mutStringArraySet,
+ NSSet *set,
+ NSMutableSet *mutSet,
+ MutableSetOfArrays *mutArraySet,
+ NSArray<NSString *> *stringArray,
+ void (^block)(void)) {
+ int *ip;
+ ip = [stringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}}
+ ip = [mutStringSet firstObject]; // expected-error{{from incompatible type 'NSString *'}}
+ ip = [widgetSet firstObject]; // expected-error{{from incompatible type 'Widget *'}}
+ ip = [untypedMutSet firstObject]; // expected-error{{from incompatible type 'id'}}
+ ip = [mutStringArraySet firstObject]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+ ip = [set firstObject]; // expected-error{{from incompatible type 'id'}}
+ ip = [mutSet firstObject]; // expected-error{{from incompatible type 'id'}}
+ ip = [mutArraySet firstObject]; // expected-error{{from incompatible type 'id'}}
+ ip = [block firstObject]; // expected-error{{from incompatible type 'id'}}
+
+ ip = [stringSet findObject:@"blah"]; // expected-error{{from incompatible type 'NSString *'}}
+
+ // Class messages.
+ ip = [NSSet<NSString *> alloc]; // expected-error{{from incompatible type 'NSSet<NSString *> *'}}
+ ip = [NSSet alloc]; // expected-error{{from incompatible type 'NSSet *'}}
+ ip = [MutableSetOfArrays<NSString *> alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays<NSString *> *'}}
+ ip = [MutableSetOfArrays alloc]; // expected-error{{from incompatible type 'MutableSetOfArrays *'}}
+ ip = [NSArray<NSString *> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+ ip = [NSArray<NSString *><NSCopying> array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+
+ ip = [[NSMutableArray<NSString *> alloc] init]; // expected-error{{from incompatible type 'NSMutableArray<NSString *> *'}}
+
+ [[NSMutableArray alloc] initWithArray: stringArray]; // okay
+ [[NSMutableArray<NSString *> alloc] initWithArray: stringArray]; // okay
+ [[NSMutableArray<NSNumber *> alloc] initWithArray: stringArray]; // expected-error{{parameter of type 'NSArray<NSNumber *> *' with an lvalue of type 'NSArray<NSString *> *'}}
+}
+
+void test_message_send_param(
+ NSMutableSet<NSString *> *mutStringSet,
+ WidgetSet *widgetSet,
+ UntypedMutableSet *untypedMutSet,
+ MutableSetOfArrays<NSString *> *mutStringArraySet,
+ NSMutableSet *mutSet,
+ MutableSetOfArrays *mutArraySet,
+ void (^block)(void)) {
+ Window *window;
+
+ [mutStringSet addObject: window]; // expected-error{{parameter of type 'NSString *'}}
+ [widgetSet addObject: window]; // expected-error{{parameter of type 'Widget *'}}
+ [untypedMutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
+ [mutStringArraySet addObject: window]; // expected-error{{parameter of type 'NSArray<NSString *> *'}}
+ [mutSet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
+ [mutArraySet addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
+ [block addObject: window]; // expected-error{{parameter of type 'id<NSCopying>'}}
+}
+
+// --------------------------------------------------------------------------
+// Property accesses.
+// --------------------------------------------------------------------------
+void test_property_read(
+ NSSet<NSString *> *stringSet,
+ NSMutableSet<NSString *> *mutStringSet,
+ WidgetSet *widgetSet,
+ UntypedMutableSet *untypedMutSet,
+ MutableSetOfArrays<NSString *> *mutStringArraySet,
+ NSSet *set,
+ NSMutableSet *mutSet,
+ MutableSetOfArrays *mutArraySet,
+ NSMutableDictionary *mutDict) {
+ int *ip;
+ ip = stringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+ ip = mutStringSet.allObjects; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+ ip = widgetSet.allObjects; // expected-error{{from incompatible type 'NSArray<Widget *> *'}}
+ ip = untypedMutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
+ ip = mutStringArraySet.allObjects; // expected-error{{from incompatible type 'NSArray<NSArray<NSString *> *> *'}}
+ ip = set.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
+ ip = mutSet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
+ ip = mutArraySet.allObjects; // expected-error{{from incompatible type 'NSArray *'}}
+
+ ip = mutDict.someRandomKey; // expected-error{{from incompatible type 'id'}}
+}
+
+void test_property_write(
+ NSMutableSet<NSString *> *mutStringSet,
+ WidgetSet *widgetSet,
+ UntypedMutableSet *untypedMutSet,
+ MutableSetOfArrays<NSString *> *mutStringArraySet,
+ NSMutableSet *mutSet,
+ MutableSetOfArrays *mutArraySet,
+ NSMutableDictionary *mutDict) {
+ int *ip;
+
+ mutStringSet.allObjects = ip; // expected-error{{to 'NSArray<NSString *> *'}}
+ widgetSet.allObjects = ip; // expected-error{{to 'NSArray<Widget *> *'}}
+ untypedMutSet.allObjects = ip; // expected-error{{to 'NSArray *'}}
+ mutStringArraySet.allObjects = ip; // expected-error{{to 'NSArray<NSArray<NSString *> *> *'}}
+ mutSet.allObjects = ip; // expected-error{{to 'NSArray *'}}
+ mutArraySet.allObjects = ip; // expected-error{{to 'NSArray *'}}
+
+ mutDict.someRandomKey = ip; // expected-error{{to 'id<NSCopying>'}}
+}
+
+// --------------------------------------------------------------------------
+// Subscripting
+// --------------------------------------------------------------------------
+void test_subscripting(
+ NSArray<NSString *> *stringArray,
+ NSMutableArray<NSString *> *mutStringArray,
+ NSArray *array,
+ NSMutableArray *mutArray,
+ NSDictionary<NSString *, Widget *> *stringWidgetDict,
+ NSMutableDictionary<NSString *, Widget *> *mutStringWidgetDict,
+ NSDictionary *dict,
+ NSMutableDictionary *mutDict) {
+ int *ip;
+ NSString *string;
+ Widget *widget;
+ Window *window;
+
+ ip = stringArray[0]; // expected-error{{from incompatible type 'NSString *'}}
+
+ ip = mutStringArray[0]; // expected-error{{from incompatible type 'NSString *'}}
+ mutStringArray[0] = ip; // expected-error{{parameter of type 'NSString *'}}
+
+ ip = array[0]; // expected-error{{from incompatible type 'id'}}
+
+ ip = mutArray[0]; // expected-error{{from incompatible type 'id'}}
+ mutArray[0] = ip; // expected-error{{parameter of type 'id'}}
+
+ ip = stringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}}
+ widget = stringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}}
+
+ ip = mutStringWidgetDict[string]; // expected-error{{from incompatible type 'Widget *'}}
+ widget = mutStringWidgetDict[widget]; // expected-error{{parameter of type 'NSString *'}}
+ mutStringWidgetDict[string] = ip; // expected-error{{parameter of type 'Widget *'}}
+ mutStringWidgetDict[widget] = widget; // expected-error{{parameter of type 'NSString *'}}
+
+ ip = dict[string]; // expected-error{{from incompatible type 'id'}}
+
+ ip = mutDict[string]; // expected-error{{incompatible type 'id'}}
+ mutDict[string] = ip; // expected-error{{parameter of type 'id'}}
+
+ widget = mutDict[window];
+ mutDict[window] = widget; // expected-error{{parameter of type 'id<NSCopying>'}}
+}
+
+// --------------------------------------------------------------------------
+// Instance variable access.
+// --------------------------------------------------------------------------
+void test_instance_variable(NSArray<NSString *> *stringArray,
+ NSArray *array) {
+ int *ip;
+
+ ip = stringArray->data; // expected-error{{from incompatible type 'NSString **'}}
+ ip = array->data; // expected-error{{from incompatible type 'id *'}}
+}
+
+ at implementation WindowArray
+- (void)testInstanceVariable {
+ int *ip;
+
+ ip = data; // expected-error{{from incompatible type 'Window **'}}
+}
+ at end
+
+// --------------------------------------------------------------------------
+// Implicit conversions.
+// --------------------------------------------------------------------------
+void test_implicit_conversions(NSArray<NSString *> *stringArray,
+ NSArray<NSNumber *> *numberArray,
+ NSMutableArray<NSString *> *mutStringArray,
+ NSArray *array,
+ NSMutableArray *mutArray) {
+ // Specialized -> unspecialized (same level)
+ array = stringArray;
+
+ // Unspecialized -> specialized (same level)
+ stringArray = array;
+
+ // Specialized -> specialized failure (same level).
+ stringArray = numberArray; // expected-error{{assigning to 'NSArray<NSString *> *' from incompatible type 'NSArray<NSNumber *> *'}}
+
+ // Specialized -> specialized (different levels).
+ stringArray = mutStringArray;
+
+ // Specialized -> specialized failure (different levels).
+ numberArray = mutStringArray; // expected-error{{assigning to 'NSArray<NSNumber *> *' from incompatible type 'NSMutableArray<NSString *> *'}}
+
+ // Unspecialized -> specialized (different levels).
+ stringArray = mutArray;
+
+ // Specialized -> unspecialized (different levels).
+ array = mutStringArray;
+}
+
+// --------------------------------------------------------------------------
+// Ternary operator
+// --------------------------------------------------------------------------
+void test_ternary_operator(NSArray<NSString *> *stringArray,
+ NSArray<NSNumber *> *numberArray,
+ NSMutableArray<NSString *> *mutStringArray,
+ NSStringArray *stringArray2,
+ NSArray *array,
+ NSMutableArray *mutArray,
+ int cond) {
+ int *ip;
+ id object;
+
+ ip = cond ? stringArray : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+ ip = cond ? mutStringArray : stringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+
+ ip = cond ? stringArray2 : mutStringArray; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+ ip = cond ? mutStringArray : stringArray2; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+
+ ip = cond ? stringArray : mutArray; // expected-error{{from incompatible type 'NSArray *'}}
+
+ ip = cond ? stringArray2 : mutArray; // expected-error{{from incompatible type 'NSArray *'}}
+
+ ip = cond ? mutArray : stringArray; // expected-error{{from incompatible type 'NSArray *'}}
+
+ ip = cond ? mutArray : stringArray2; // expected-error{{from incompatible type 'NSArray *'}}
+
+ object = cond ? stringArray : numberArray; // expected-warning{{incompatible operand types ('NSArray<NSString *> *' and 'NSArray<NSNumber *> *')}}
+}
+
+// --------------------------------------------------------------------------
+// super
+// --------------------------------------------------------------------------
+ at implementation NSStringArray
+- (void)useSuperMethod {
+ int *ip;
+ ip = super.lastObject; // expected-error{{from incompatible type 'NSString *'}}
+ ip = [super objectAtIndexedSubscript:0]; // expected-error{{from incompatible type 'NSString *'}}
+}
+
++ (void)useSuperMethod {
+ int *ip;
+ ip = super.array; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+ ip = [super array]; // expected-error{{from incompatible type 'NSArray<NSString *> *'}}
+}
+ at end
+
+// --------------------------------------------------------------------------
+// Template instantiation
+// --------------------------------------------------------------------------
+template<typename K, typename V>
+struct NSMutableDictionaryOf {
+ typedef NSMutableDictionary<K, V> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}}
+};
+
+template<typename ...Args>
+struct VariadicNSMutableDictionaryOf {
+ typedef NSMutableDictionary<Args...> *type; // expected-error{{type argument 'NSObject *' does not satisfy the bound ('id<NSCopying>') of type parameter 'K'}}
+ // expected-error at -1{{too many type arguments for class 'NSMutableDictionary' (have 3, expected 2)}}
+ // expected-error at -2{{too few type arguments for class 'NSMutableDictionary' (have 1, expected 2)}}
+};
+
+void testInstantiation() {
+ int *ip;
+
+ typedef NSMutableDictionaryOf<NSString *, NSObject *>::type Dict1;
+ Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}}
+
+ typedef NSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}}
+}
+
+void testVariadicInstantiation() {
+ int *ip;
+
+ typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *>::type Dict1;
+ Dict1 d1 = ip; // expected-error{{cannot initialize a variable of type 'Dict1' (aka 'NSMutableDictionary<NSString *,NSObject *> *')}}
+
+ typedef VariadicNSMutableDictionaryOf<NSObject *, NSString *>::type Dict2; // expected-note{{in instantiation of template}}
+
+ typedef VariadicNSMutableDictionaryOf<NSString *, NSObject *, NSObject *>::type Dict3; // expected-note{{in instantiation of template}}
+
+ typedef VariadicNSMutableDictionaryOf<NSString *>::type Dict3; // expected-note{{in instantiation of template}}
+}
+
+// --------------------------------------------------------------------------
+// Parameterized classes are not templates
+// --------------------------------------------------------------------------
+template<template<typename T, typename U> class TT>
+struct AcceptsTemplateTemplate { };
+
+typedef AcceptsTemplateTemplate<NSMutableDictionary> TemplateTemplateFail1; // expected-error{{template argument for template template parameter must be a class template or type alias template}}
+
+template<typename T>
+struct DependentTemplate {
+ typedef typename T::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}}
+};
+
+struct NSMutableDictionaryBuilder {
+ typedef NSMutableDictionary apply;
+};
+
+typedef DependentTemplate<NSMutableDictionaryBuilder>::type DependentTemplateFail1; // expected-note{{in instantiation of template class}}
+
+template<typename K, typename V>
+struct NonDependentTemplate {
+ typedef NSMutableDictionaryBuilder::template apply<NSString *, NSObject *> type; // expected-error{{'apply' following the 'template' keyword does not refer to a template}}
+ // expected-error at -1{{expected member name or }}
+};
+
+// However, one can use an alias template to turn a parameterized
+// class into a template.
+template<typename K, typename V>
+using NSMutableDictionaryAlias = NSMutableDictionary<K, V>;
+
+typedef AcceptsTemplateTemplate<NSMutableDictionaryAlias> TemplateTemplateAlias1; // okay
+
+
Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Mon Jul 6 22:58:14 2015
@@ -916,6 +916,18 @@ bool CursorVisitor::VisitTemplateTemplat
return false;
}
+bool CursorVisitor::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) {
+ // Visit the bound, if it's explicit.
+ if (D->hasExplicitBound()) {
+ if (auto TInfo = D->getTypeSourceInfo()) {
+ if (Visit(TInfo->getTypeLoc()))
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) {
if (TypeSourceInfo *TSInfo = ND->getReturnTypeSourceInfo())
if (Visit(TSInfo->getTypeLoc()))
@@ -1091,14 +1103,6 @@ bool CursorVisitor::VisitObjCTypeParamLi
// Visit the type parameter.
if (Visit(MakeCXCursor(typeParam, TU, RegionOfInterest)))
return true;
-
- // Visit the bound, if it's explicit.
- if (typeParam->hasExplicitBound()) {
- if (auto TInfo = typeParam->getTypeSourceInfo()) {
- if (Visit(TInfo->getTypeLoc()))
- return true;
- }
- }
}
return false;
Modified: cfe/trunk/tools/libclang/CursorVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CursorVisitor.h?rev=241545&r1=241544&r2=241545&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CursorVisitor.h (original)
+++ cfe/trunk/tools/libclang/CursorVisitor.h Mon Jul 6 22:58:14 2015
@@ -217,6 +217,7 @@ public:
bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
bool VisitClassTemplateDecl(ClassTemplateDecl *D);
bool VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ bool VisitObjCTypeParamDecl(ObjCTypeParamDecl *D);
bool VisitObjCMethodDecl(ObjCMethodDecl *ND);
bool VisitObjCContainerDecl(ObjCContainerDecl *D);
bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND);
More information about the cfe-commits
mailing list