When building types from declarators, instead of building two types (one for
the DeclaratorInfo, one for semantic analysis), just build a single type whose
canonical type will reflect the semantic analysis (assuming the type is
well-formed, of course).
To make that work, make a few changes to the type system:
* allow the nominal pointee type of a reference type to be a (possibly sugared)
reference type. Also, preserve the original spelling of the reference type.
Both of these can be ignored on canonical reference types.
* Remove ObjCProtocolListType and preserve the associated source information on
the various ObjC TypeLocs. Preserve the spelling of protocol lists except in
the canonical form.
* Preserve some level of source type structure on parameter types, but
canonicalize on the canonical function type. This is still a WIP.
Drops code size, makes strides towards accurate source location representation,
slight (~1.7%) progression on Cocoa.h because of complexity drop.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84907 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 074a6fc..6dd081b 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -448,7 +448,7 @@
//
QualType adjustParameterType(QualType T);
QualType ConvertDeclSpecToType(const DeclSpec &DS, SourceLocation DeclLoc,
- bool &IsInvalid, QualType &SourceTy);
+ bool &IsInvalid);
void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
QualType BuildPointerType(QualType T, unsigned Quals,
SourceLocation Loc, DeclarationName Entity);
@@ -3755,22 +3755,6 @@
QualType FieldTy, const Expr *BitWidth,
bool *ZeroWidth = 0);
- /// adjustFunctionParamType - Converts the type of a function parameter to a
- // type that can be passed as an argument type to
- /// ASTContext::getFunctionType.
- ///
- /// C++ [dcl.fct]p3: "...Any cv-qualifier modifying a parameter type is
- /// deleted. Such cv-qualifiers affect only the definition of the parameter
- /// within the body of the function; they do not affect the function type.
- QualType adjustFunctionParamType(QualType T) const {
- if (!Context.getLangOptions().CPlusPlus)
- return T;
- return
- T->isDependentType() ? T.getUnqualifiedType()
- : T.getDesugaredType().getUnqualifiedType();
-
- }
-
/// \name Code completion
//@{
void setCodeCompleteConsumer(CodeCompleteConsumer *CCC);
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index e083c07..6d1f4ea 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -4281,8 +4281,7 @@
// friend templates because ActOnTag never produces a ClassTemplateDecl
// for a TUK_Friend.
bool invalid = false;
- QualType SourceTy;
- QualType T = ConvertDeclSpecToType(DS, Loc, invalid, SourceTy);
+ QualType T = ConvertDeclSpecToType(DS, Loc, invalid);
if (invalid) return DeclPtrTy();
// This is definitely an error in C++98. It's probably meant to
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 219ac3e..49f7119 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -52,16 +52,14 @@
/// object.
/// \param DS the declaration specifiers
/// \param DeclLoc The location of the declarator identifier or invalid if none.
-/// \param SourceTy QualType representing the type as written in source form.
/// \returns The type described by the declaration specifiers. This function
/// never returns null.
QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS,
SourceLocation DeclLoc,
- bool &isInvalid, QualType &SourceTy) {
+ bool &isInvalid) {
// FIXME: Should move the logic from DeclSpec::Finish to here for validity
// checking.
QualType Result;
- SourceTy = Result;
switch (DS.getTypeSpecType()) {
case DeclSpec::TST_void:
@@ -106,9 +104,6 @@
case DeclSpec::TST_unspecified:
// "<proto1,proto2>" is an objc qualified ID with a missing id.
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- SourceTy = Context.getObjCProtocolListType(QualType(),
- (ObjCProtocolDecl**)PQ,
- DS.getNumProtocolQualifiers());
Result = Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy,
(ObjCProtocolDecl**)PQ,
DS.getNumProtocolQualifiers());
@@ -226,9 +221,6 @@
Result = GetTypeFromParser(DS.getTypeRep());
if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) {
- SourceTy = Context.getObjCProtocolListType(Result,
- (ObjCProtocolDecl**)PQ,
- DS.getNumProtocolQualifiers());
if (const ObjCInterfaceType *
Interface = Result->getAs<ObjCInterfaceType>()) {
// It would be nice if protocol qualifiers were only stored with the
@@ -385,8 +377,6 @@
Result = Context.getQualifiedType(Result, Quals);
}
- if (SourceTy.isNull())
- SourceTy = Result;
return Result;
}
@@ -450,36 +440,32 @@
///
/// \returns A suitable reference type, if there are no
/// errors. Otherwise, returns a NULL type.
-QualType Sema::BuildReferenceType(QualType T, bool LValueRef, unsigned CVR,
- SourceLocation Loc, DeclarationName Entity) {
+QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue,
+ unsigned CVR, SourceLocation Loc,
+ DeclarationName Entity) {
Qualifiers Quals = Qualifiers::fromCVRMask(CVR);
- if (LValueRef) {
- if (const RValueReferenceType *R = T->getAs<RValueReferenceType>()) {
- // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a
- // reference to a type T, and attempt to create the type "lvalue
- // reference to cv TD" creates the type "lvalue reference to T".
- // We use the qualifiers (restrict or none) of the original reference,
- // not the new ones. This is consistent with GCC.
- QualType LVRT = Context.getLValueReferenceType(R->getPointeeType());
- return Context.getQualifiedType(LVRT, T.getQualifiers());
- }
- }
- if (T->isReferenceType()) {
- // C++ [dcl.ref]p4: There shall be no references to references.
- //
- // According to C++ DR 106, references to references are only
- // diagnosed when they are written directly (e.g., "int & &"),
- // but not when they happen via a typedef:
- //
- // typedef int& intref;
- // typedef intref& intref2;
- //
- // Parser::ParseDeclaratorInternal diagnoses the case where
- // references are written directly; here, we handle the
- // collapsing of references-to-references as described in C++
- // DR 106 and amended by C++ DR 540.
- return T;
- }
+
+ bool LValueRef = SpelledAsLValue || T->getAs<LValueReferenceType>();
+
+ // C++0x [dcl.typedef]p9: If a typedef TD names a type that is a
+ // reference to a type T, and attempt to create the type "lvalue
+ // reference to cv TD" creates the type "lvalue reference to T".
+ // We use the qualifiers (restrict or none) of the original reference,
+ // not the new ones. This is consistent with GCC.
+
+ // C++ [dcl.ref]p4: There shall be no references to references.
+ //
+ // According to C++ DR 106, references to references are only
+ // diagnosed when they are written directly (e.g., "int & &"),
+ // but not when they happen via a typedef:
+ //
+ // typedef int& intref;
+ // typedef intref& intref2;
+ //
+ // Parser::ParseDeclaratorInternal diagnoses the case where
+ // references are written directly; here, we handle the
+ // collapsing of references-to-references as described in C++
+ // DR 106 and amended by C++ DR 540.
// C++ [dcl.ref]p1:
// A declarator that specifies the type "reference to cv void"
@@ -511,7 +497,8 @@
// Handle restrict on references.
if (LValueRef)
- return Context.getQualifiedType(Context.getLValueReferenceType(T), Quals);
+ return Context.getQualifiedType(
+ Context.getLValueReferenceType(T, SpelledAsLValue), Quals);
return Context.getQualifiedType(Context.getRValueReferenceType(T), Quals);
}
@@ -717,7 +704,7 @@
Invalid = true;
}
- ParamTypes[Idx] = adjustFunctionParamType(ParamType);
+ ParamTypes[Idx] = ParamType;
}
if (Invalid)
@@ -856,9 +843,6 @@
// Determine the type of the declarator. Not all forms of declarator
// have a type.
QualType T;
- // The QualType referring to the type as written in source code. We can't use
- // T because it can change due to semantic analysis.
- QualType SourceTy;
switch (D.getKind()) {
case Declarator::DK_Abstract:
@@ -872,7 +856,7 @@
T = Context.DependentTy;
} else {
bool isInvalid = false;
- T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid, SourceTy);
+ T = ConvertDeclSpecToType(DS, D.getIdentifierLoc(), isInvalid);
if (isInvalid)
D.setInvalidType(true);
else if (OwnedDecl && DS.isTypeSpecOwned())
@@ -891,9 +875,6 @@
break;
}
- if (SourceTy.isNull())
- SourceTy = T;
-
if (T == Context.UndeducedAutoTy) {
int Error = -1;
@@ -942,8 +923,6 @@
if (D.getIdentifier())
Name = D.getIdentifier();
- bool ShouldBuildInfo = DInfo != 0;
-
// Walk the DeclTypeInfo, building the recursive type as we go.
// DeclTypeInfos are ordered from the identifier out, which is
// opposite of what we want :).
@@ -952,17 +931,6 @@
switch (DeclType.Kind) {
default: assert(0 && "Unknown decltype!");
case DeclaratorChunk::BlockPointer:
- if (ShouldBuildInfo) {
- if (SourceTy->isFunctionType())
- SourceTy
- = Context.getQualifiedType(Context.getBlockPointerType(SourceTy),
- Qualifiers::fromCVRMask(DeclType.Cls.TypeQuals));
- else
- // If not function type Context::getBlockPointerType asserts,
- // so just give up.
- ShouldBuildInfo = false;
- }
-
// If blocks are disabled, emit an error.
if (!LangOpts.Blocks)
Diag(DeclType.Loc, diag::err_blocks_disable);
@@ -971,10 +939,6 @@
Name);
break;
case DeclaratorChunk::Pointer:
- //FIXME: Use ObjCObjectPointer for info when appropriate.
- if (ShouldBuildInfo)
- SourceTy = Context.getQualifiedType(Context.getPointerType(SourceTy),
- Qualifiers::fromCVRMask(DeclType.Ptr.TypeQuals));
// Verify that we're not building a pointer to pointer to function with
// exception specification.
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -995,14 +959,6 @@
Qualifiers Quals;
if (DeclType.Ref.HasRestrict) Quals.addRestrict();
- if (ShouldBuildInfo) {
- if (DeclType.Ref.LValueRef)
- SourceTy = Context.getLValueReferenceType(SourceTy);
- else
- SourceTy = Context.getRValueReferenceType(SourceTy);
- SourceTy = Context.getQualifiedType(SourceTy, Quals);
- }
-
// Verify that we're not building a reference to pointer to function with
// exception specification.
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -1015,11 +971,6 @@
break;
}
case DeclaratorChunk::Array: {
- if (ShouldBuildInfo)
- // We just need to get an array type, the exact type doesn't matter.
- SourceTy = Context.getIncompleteArrayType(SourceTy, ArrayType::Normal,
- DeclType.Arr.TypeQuals);
-
// Verify that we're not building an array of pointers to function with
// exception specification.
if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) {
@@ -1051,24 +1002,6 @@
break;
}
case DeclaratorChunk::Function: {
- if (ShouldBuildInfo) {
- const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun;
- llvm::SmallVector<QualType, 16> ArgTys;
-
- for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) {
- ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
- if (Param) {
- QualType ArgTy = adjustFunctionParamType(Param->getType());
-
- ArgTys.push_back(ArgTy);
- }
- }
- SourceTy = Context.getFunctionType(SourceTy, ArgTys.data(),
- ArgTys.size(),
- FTI.isVariadic,
- FTI.TypeQuals);
- }
-
// If the function declarator has a prototype (i.e. it is not () and
// does not have a K&R-style identifier list), then the arguments are part
// of the type, otherwise the argument list is ().
@@ -1137,6 +1070,7 @@
} else if (FTI.ArgInfo[0].Param == 0) {
// C99 6.7.5.3p3: Reject int(x,y,z) when it's not a function definition.
Diag(FTI.ArgInfo[0].IdentLoc, diag::err_ident_list_in_fn_declaration);
+ D.setInvalidType(true);
} else {
// Otherwise, we have a function with an argument list that is
// potentially variadic.
@@ -1185,7 +1119,7 @@
}
}
- ArgTys.push_back(adjustFunctionParamType(ArgTy));
+ ArgTys.push_back(ArgTy);
}
llvm::SmallVector<QualType, 4> Exceptions;
@@ -1234,13 +1168,6 @@
D.setInvalidType(true);
}
- if (ShouldBuildInfo) {
- QualType cls = !ClsType.isNull() ? ClsType : Context.IntTy;
- SourceTy = Context.getQualifiedType(
- Context.getMemberPointerType(SourceTy, cls.getTypePtr()),
- Qualifiers::fromCVRMask(DeclType.Mem.TypeQuals));
- }
-
if (!ClsType.isNull())
T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals,
DeclType.Loc, D.getIdentifier());
@@ -1293,8 +1220,12 @@
if (const AttributeList *Attrs = D.getAttributes())
ProcessTypeAttributeList(T, Attrs);
- if (ShouldBuildInfo)
- *DInfo = GetDeclaratorInfoForDeclarator(D, SourceTy, Skip);
+ if (DInfo) {
+ if (D.isInvalidType())
+ *DInfo = 0;
+ else
+ *DInfo = GetDeclaratorInfoForDeclarator(D, T, Skip);
+ }
return T;
}
@@ -1314,17 +1245,49 @@
}
void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) {
TL.setNameLoc(DS.getTypeSpecTypeLoc());
- }
- void VisitObjCProtocolListTypeLoc(ObjCProtocolListTypeLoc TL) {
- assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
- TL.setLAngleLoc(DS.getProtocolLAngleLoc());
- TL.setRAngleLoc(DS.getSourceRange().getEnd());
- for (unsigned i = 0; i != DS.getNumProtocolQualifiers(); ++i)
- TL.setProtocolLoc(i, DS.getProtocolLocs()[i]);
- TypeLoc BaseLoc = TL.getBaseTypeLoc();
- if (BaseLoc)
+ if (DS.getProtocolQualifiers()) {
+ assert(TL.getNumProtocols() > 0);
+ assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
+ TL.setLAngleLoc(DS.getProtocolLAngleLoc());
+ TL.setRAngleLoc(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.setLAngleLoc(SourceLocation());
+ TL.setRAngleLoc(SourceLocation());
+ }
+ }
+ void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
+ assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
+
+ TL.setStarLoc(SourceLocation());
+
+ if (DS.getProtocolQualifiers()) {
+ assert(TL.getNumProtocols() > 0);
+ assert(TL.getNumProtocols() == DS.getNumProtocolQualifiers());
+ TL.setHasProtocolsAsWritten(true);
+ TL.setLAngleLoc(DS.getProtocolLAngleLoc());
+ TL.setRAngleLoc(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.setHasProtocolsAsWritten(false);
+ TL.setLAngleLoc(SourceLocation());
+ TL.setRAngleLoc(SourceLocation());
+ }
+
+ // This might not have been written with an inner type.
+ if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) {
+ TL.setHasBaseTypeAsWritten(false);
+ TL.getBaseTypeLoc().initialize(SourceLocation());
+ } else {
+ TL.setHasBaseTypeAsWritten(true);
Visit(TL.getBaseTypeLoc());
+ }
}
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
@@ -1353,6 +1316,10 @@
void VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::Pointer);
TL.setStarLoc(Chunk.Loc);
+ TL.setHasBaseTypeAsWritten(true);
+ TL.setHasProtocolsAsWritten(false);
+ TL.setLAngleLoc(SourceLocation());
+ TL.setRAngleLoc(SourceLocation());
}
void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::MemberPointer);
@@ -1361,7 +1328,8 @@
}
void VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) {
assert(Chunk.Kind == DeclaratorChunk::Reference);
- assert(Chunk.Ref.LValueRef);
+ // 'Amp' is misleading: this might have been originally
+ /// spelled with AmpAmp.
TL.setAmpLoc(Chunk.Loc);
}
void VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) {
@@ -1381,12 +1349,9 @@
TL.setRParenLoc(Chunk.EndLoc);
const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun;
- for (unsigned i = 0, e = FTI.NumArgs, tpi = 0; i != e; ++i) {
+ for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) {
ParmVarDecl *Param = FTI.ArgInfo[i].Param.getAs<ParmVarDecl>();
- if (Param) {
- assert(tpi < TL.getNumArgs());
- TL.setArg(tpi++, Param);
- }
+ TL.setArg(tpi++, Param);
}
// FIXME: exception specs
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 5f06ce5..38273dc 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -514,14 +514,6 @@
SourceRange(getDerived().getBaseLocation()));
}
- /// \brief Rebuild an objective C protocol list type.
- QualType RebuildObjCProtocolListType(QualType BaseType,
- ObjCProtocolDecl **Protocols,
- unsigned NumProtocols) {
- return SemaRef.Context.getObjCProtocolListType(BaseType, Protocols,
- NumProtocols);
- }
-
/// \brief Build a new nested-name-specifier given the prefix and an
/// identifier that names the next step in the nested-name-specifier.
///
@@ -2808,50 +2800,16 @@
QualType
TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB,
ObjCInterfaceTypeLoc TL) {
- return TransformTypeSpecType(TLB, TL);
+ assert(false && "TransformObjCInterfaceType unimplemented");
+ return QualType();
}
template<typename Derived>
QualType
TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
ObjCObjectPointerTypeLoc TL) {
- TransformPointerLikeType(ObjCObjectPointerType);
-}
-
-template<typename Derived>
-QualType TreeTransform<Derived>::TransformObjCProtocolListType(
- TypeLocBuilder &TLB,
- ObjCProtocolListTypeLoc TL) {
- ObjCProtocolListType *T = TL.getTypePtr();
- QualType BaseType = T->getBaseType();
- if (!BaseType.isNull()) {
- BaseType = getDerived().TransformType(TLB, TL.getBaseTypeLoc());
- if (BaseType.isNull())
- return QualType();
- }
-
- QualType Result = TL.getType();
- if (getDerived().AlwaysRebuild() ||
- BaseType != T->getBaseType()) {
- // TODO: transform these?
- llvm::SmallVector<ObjCProtocolDecl*,4> Protocols(T->getNumProtocols());
- std::copy(T->qual_begin(), T->qual_end(), Protocols.begin());
- Result = getDerived().RebuildObjCProtocolListType(BaseType,
- &Protocols[0],
- T->getNumProtocols());
- if (Result.isNull())
- return QualType();
- }
-
- ObjCProtocolListTypeLoc NewTL = TLB.push<ObjCProtocolListTypeLoc>(Result);
- NewTL.setLAngleLoc(TL.getLAngleLoc());
- NewTL.setRAngleLoc(TL.getRAngleLoc());
-
- assert(NewTL.getNumProtocols() == TL.getNumProtocols());
- for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i)
- NewTL.setProtocolLoc(i, TL.getProtocolLoc(i));
-
- return Result;
+ assert(false && "TransformObjCObjectPointerType unimplemented");
+ return QualType();
}
//===----------------------------------------------------------------------===//